diff --git a/src/calibre/customize/__init__.py b/src/calibre/customize/__init__.py index 5198969430..9f44f6972f 100644 --- a/src/calibre/customize/__init__.py +++ b/src/calibre/customize/__init__.py @@ -581,60 +581,41 @@ class PreferencesPlugin(Plugin): # {{{ # }}} - -class StorePlugin(Plugin): # {{{ - +class StoreBase(Plugin): # {{{ + supported_platforms = ['windows', 'osx', 'linux'] author = 'John Schember' type = _('Store') # This needs to be changed to (0, 8, 0) minimum_calibre_version = (0, 4, 118) - - def open(self, gui, parent=None, detail_item=None, external=False): + + actual_plugin = None + actual_plugin_object = None + + def load_actual_plugin(self, gui): ''' - Open the store. - - :param gui: The main GUI. This will be used to have the job - system start downloading an item from the store. - - :param parent: The parent of the store dialog. This is used - to create modal dialogs. - - :param detail_item: A plugin specific reference to an item - in the store that the user should be shown. - - :param external: When False open an internal dialog with the - store. When True open the users default browser to the store's - web site. :param:`detail_item` should still be respected when external - is True. + This method must return the actual interface action plugin object. ''' - raise NotImplementedError() - - def search(self, query, max_results=10, timeout=60): - ''' - Searches the store for items matching query. This should - return items as a generator. + mod, cls = self.actual_plugin.split(':') + self.actual_plugin_object = getattr(__import__(mod, fromlist=['1'], level=0), cls)(gui, self.name) + return self.actual_plugin_object + + def customization_help(self, gui=False): + if self.actual_plugin_object: + return self.actual_plugin_object.customization_help(gui) + else: + raise NotImplementedError() - :param query: The string query search with. - :param max_results: The maximum number of results to return. - :param timeout: The maximum amount of time in seconds to spend download the search results. - - :return: :class:`calibre.gui2.store.search_result.SearchResult` objects - item_data is plugin specific and is used in :meth:`open` to open to a specifc place in the store. - ''' - raise NotImplementedError() - - def get_settings(self): - ''' - This is only useful for plugins that implement - :attr:`config_widget` that is the only way to save - settings. This is used by plugins to get the saved - settings and apply when necessary. - - :return: A dictionary filled with the settings used - by this plugin. - ''' - raise NotImplementedError() + def config_widget(self): + if self.actual_plugin_object: + return self.actual_plugin_object.config_widget() + else: + raise NotImplementedError() + + def save_settings(self, config_widget): + if self.actual_plugin_object: + return self.actual_plugin_object.save_settings(config_widget) + else: + raise NotImplementedError() # }}} - diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index 913b5d3c7b..53d3f0dd08 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -5,7 +5,7 @@ __copyright__ = '2008, Kovid Goyal ' import textwrap, os, glob, functools, re from calibre import guess_type from calibre.customize import FileTypePlugin, MetadataReaderPlugin, \ - MetadataWriterPlugin, PreferencesPlugin, InterfaceActionBase + MetadataWriterPlugin, PreferencesPlugin, InterfaceActionBase, StoreBase from calibre.constants import numeric_version from calibre.ebooks.metadata.archive import ArchiveExtract, get_cbz_metadata from calibre.ebooks.metadata.opf2 import metadata_to_opf @@ -1042,12 +1042,32 @@ plugins += [GoogleBooks] # }}} # Store plugins {{{ -from calibre.gui2.store.amazon_plugin import AmazonKindleStore -from calibre.gui2.store.gutenberg_plugin import GutenbergStore -from calibre.gui2.store.feedbooks_plugin import FeedbooksStore -from calibre.gui2.store.manybooks_plugin import ManyBooksStore -from calibre.gui2.store.smashwords_plugin import SmashwordsStore +class StoreAmazonKindleStore(StoreBase): + name = 'Amazon Kindle' + description = _('Kindle books from Amazon') + actual_plugin = 'calibre.gui2.store.amazon_plugin:AmazonKindleStore' -plugins += [AmazonKindleStore, GutenbergStore, FeedbooksStore, ManyBooksStore, SmashwordsStore] + +class StoreGutenbergStore(StoreBase): + name = 'Project Gutenberg' + description = _('The first producer of free ebooks.') + actual_plugin = 'calibre.gui2.store.gutenberg_plugin:GutenbergStore' + +class StoreFeedbooksStore(StoreBase): + name = 'Feedbooks' + description = _('Read anywhere.') + actual_plugin = 'calibre.gui2.store.feedbooks_plugin:FeedbooksStore' + +class StoreManyBooksStore(StoreBase): + name = 'ManyBooks' + description = _('The best ebooks at the best price: free!') + actual_plugin = 'calibre.gui2.store.manybooks_plugin:ManyBooksStore' + +class StoreSmashwordsStore(StoreBase): + name = 'Smashwords' + description = _('Your ebook. Your way.') + actual_plugin = 'calibre.gui2.store.smashwords_plugin:SmashwordsStore' + +plugins += [StoreAmazonKindleStore, StoreGutenbergStore, StoreFeedbooksStore, StoreManyBooksStore, StoreSmashwordsStore] # }}} diff --git a/src/calibre/customize/ui.py b/src/calibre/customize/ui.py index bbe24125b8..8e7aa50951 100644 --- a/src/calibre/customize/ui.py +++ b/src/calibre/customize/ui.py @@ -8,7 +8,7 @@ from contextlib import closing from calibre.customize import Plugin, CatalogPlugin, FileTypePlugin, \ MetadataReaderPlugin, MetadataWriterPlugin, \ InterfaceActionBase as InterfaceAction, \ - PreferencesPlugin, StorePlugin + PreferencesPlugin, StoreBase from calibre.customize.conversion import InputFormatPlugin, OutputFormatPlugin from calibre.customize.profiles import InputProfile, OutputProfile from calibre.customize.builtins import plugins as builtin_plugins @@ -283,7 +283,7 @@ def preferences_plugins(): def store_plugins(): customization = config['plugin_customization'] for plugin in _initialized_plugins: - if isinstance(plugin, StorePlugin): + if isinstance(plugin, StoreBase): if not is_disabled(plugin): plugin.site_customization = customization.get(plugin.name, '') yield plugin diff --git a/src/calibre/gui2/actions/store.py b/src/calibre/gui2/actions/store.py index 9066150684..0a14bce30b 100644 --- a/src/calibre/gui2/actions/store.py +++ b/src/calibre/gui2/actions/store.py @@ -8,7 +8,6 @@ from functools import partial from PyQt4.Qt import Qt, QMenu, QToolButton, QDialog, QVBoxLayout -from calibre.customize.ui import store_plugins from calibre.gui2.actions import InterfaceAction class StoreAction(InterfaceAction): @@ -21,14 +20,14 @@ class StoreAction(InterfaceAction): self.store_menu = QMenu() self.store_menu.addAction(_('Search'), self.search) self.store_menu.addSeparator() - for x in store_plugins(): - self.store_menu.addAction(x.name, partial(self.open_store, x)) + for n, p in self.gui.istores.items(): + self.store_menu.addAction(n, partial(self.open_store, p)) self.qaction.setMenu(self.store_menu) def search(self): from calibre.gui2.store.search import SearchDialog - sd = SearchDialog(self.gui, self.gui) + sd = SearchDialog(self.gui.istores, self.gui) sd.exec_() def open_store(self, store_plugin): - store_plugin.open(self.gui, self.gui) + store_plugin.open(self.gui) diff --git a/src/calibre/gui2/store/__init__.py b/src/calibre/gui2/store/__init__.py index e69de29bb2..882c81597b 100644 --- a/src/calibre/gui2/store/__init__.py +++ b/src/calibre/gui2/store/__init__.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- + +__license__ = 'GPL 3' +__copyright__ = '2011, John Schember ' +__docformat__ = 'restructuredtext en' + +class StorePlugin(object): # {{{ + + def __init__(self, gui, name): + self.gui = gui + self.name = name + self.base_plugin = None + + def open(self, gui, parent=None, detail_item=None, external=False): + ''' + Open the store. + + :param gui: The main GUI. This will be used to have the job + system start downloading an item from the store. + + :param parent: The parent of the store dialog. This is used + to create modal dialogs. + + :param detail_item: A plugin specific reference to an item + in the store that the user should be shown. + + :param external: When False open an internal dialog with the + store. When True open the users default browser to the store's + web site. :param:`detail_item` should still be respected when external + is True. + ''' + raise NotImplementedError() + + def search(self, query, max_results=10, timeout=60): + ''' + Searches the store for items matching query. This should + return items as a generator. + + :param query: The string query search with. + :param max_results: The maximum number of results to return. + :param timeout: The maximum amount of time in seconds to spend download the search results. + + :return: :class:`calibre.gui2.store.search_result.SearchResult` objects + item_data is plugin specific and is used in :meth:`open` to open to a specifc place in the store. + ''' + raise NotImplementedError() + + def get_settings(self): + ''' + This is only useful for plugins that implement + :attr:`config_widget` that is the only way to save + settings. This is used by plugins to get the saved + settings and apply when necessary. + + :return: A dictionary filled with the settings used + by this plugin. + ''' + raise NotImplementedError() + + def do_genesis(self): + self.genesis() + + def genesis(self): + pass + + def config_widget(self): + raise NotImplementedError() + + def save_settings(self, config_widget): + raise NotImplementedError() + + def customization_help(self, gui=False): + raise NotImplementedError() + +# }}} \ No newline at end of file diff --git a/src/calibre/gui2/store/amazon_plugin.py b/src/calibre/gui2/store/amazon_plugin.py index 7086cfba8f..68f2daf2ea 100644 --- a/src/calibre/gui2/store/amazon_plugin.py +++ b/src/calibre/gui2/store/amazon_plugin.py @@ -14,15 +14,13 @@ from lxml import html from PyQt4.Qt import QUrl from calibre import browser -from calibre.customize import StorePlugin +from calibre.gui2 import open_url +from calibre.gui2.store import StorePlugin from calibre.gui2.store.search_result import SearchResult class AmazonKindleStore(StorePlugin): - name = 'Amazon Kindle' - description = _('Kindle books from Amazon') - - def open(self, gui, parent=None, detail_item=None): + def open(self, parent=None, detail_item=None, external=False): ''' Amazon comes with a number of difficulties. @@ -106,7 +104,6 @@ class AmazonKindleStore(StorePlugin): The best (I use the term lightly here) solution is to open Amazon.com in the users default browser and set the affiliate id as part of the url. ''' - from calibre.gui2 import open_url aff_id = {'tag': 'josbl0e-cpb-20'} # Use Kovid's affiliate id 30% of the time. if random.randint(1, 10) in (1, 2, 3): diff --git a/src/calibre/gui2/store/feedbooks_plugin.py b/src/calibre/gui2/store/feedbooks_plugin.py index 57f9e2d472..121b193806 100644 --- a/src/calibre/gui2/store/feedbooks_plugin.py +++ b/src/calibre/gui2/store/feedbooks_plugin.py @@ -10,18 +10,14 @@ from contextlib import closing from lxml import html from calibre import browser -from calibre.customize import StorePlugin -from calibre.gui2.store.search_result import SearchResult +from calibre.gui2.store import StorePlugin +from calibre.gui2.store.basic_config import BasicStoreConfig +from calibre.gui2.store.web_store_dialog import WebStoreDialog -class FeedbooksStore(StorePlugin): +class FeedbooksStore(BasicStoreConfig, StorePlugin): - name = 'Feedbooks' - description = _('Read anywhere.') - - - def open(self, gui, parent=None, detail_item=None): - from calibre.gui2.store.web_store_dialog import WebStoreDialog - d = WebStoreDialog(gui, 'http://m.feedbooks.com/', parent, detail_item) + def open(self, parent=None, detail_item=None, external=False): + d = WebStoreDialog(self.gui, 'http://m.feedbooks.com/', parent, detail_item) d.setWindowTitle(self.name) d.set_tags(self.name + ',' + _('store')) d = d.exec_() @@ -76,22 +72,3 @@ class FeedbooksStore(StorePlugin): s.detail_item = id.strip() yield s - - def customization_help(self, gui=False): - return 'Customize the behavior of this store.' - - def config_widget(self): - from calibre.gui2.store.basic_config_widget import BasicStoreConfigWidget - return BasicStoreConfigWidget(self) - - def save_settings(self, config_widget): - from calibre.gui2.store.basic_config_widget import save_settings - save_settings(config_widget) - - def get_settings(self): - from calibre.gui2 import gprefs - settings = {} - - settings[self.name + '_tags'] = gprefs.get(self.name + '_tags', self.name + ', store, download') - - return settings diff --git a/src/calibre/gui2/store/gutenberg_plugin.py b/src/calibre/gui2/store/gutenberg_plugin.py index 952f7f512f..c263d544ea 100644 --- a/src/calibre/gui2/store/gutenberg_plugin.py +++ b/src/calibre/gui2/store/gutenberg_plugin.py @@ -10,18 +10,16 @@ from contextlib import closing from lxml import html from calibre import browser -from calibre.customize import StorePlugin +from calibre.gui2.store import StorePlugin +from calibre.gui2.store.basic_config import BasicStoreConfig from calibre.gui2.store.search_result import SearchResult +from calibre.gui2.store.web_store_dialog import WebStoreDialog -class GutenbergStore(StorePlugin): - - name = 'Project Gutenberg' - description = _('The first producer of free ebooks.') +class GutenbergStore(BasicStoreConfig, StorePlugin): - def open(self, gui, parent=None, detail_item=None): + def open(self, parent=None, detail_item=None, external=False): settings = self.get_settings() - from calibre.gui2.store.web_store_dialog import WebStoreDialog - d = WebStoreDialog(gui, 'http://m.gutenberg.org/', parent, detail_item) + d = WebStoreDialog(self.gui, 'http://m.gutenberg.org/', parent, detail_item) d.setWindowTitle(self.name) d.set_tags(settings.get(self.name + '_tags', '')) d = d.exec_() @@ -51,8 +49,9 @@ class GutenbergStore(StorePlugin): continue id = url.split('/')[-1] - heading = ''.join(url_a.xpath('text()')) - title, _, author = heading.partition('by ') + url_a = html.fromstring(html.tostring(url_a)) + heading = ''.join(url_a.xpath('//text()')) + title, _, author = heading.rpartition('by ') author = author.split('-')[0] price = '$0.00' @@ -66,22 +65,3 @@ class GutenbergStore(StorePlugin): s.detail_item = '/ebooks/' + id.strip() yield s - - def customization_help(self, gui=False): - return 'Customize the behavior of this store.' - - def config_widget(self): - from calibre.gui2.store.basic_config_widget import BasicStoreConfigWidget - return BasicStoreConfigWidget(self) - - def save_settings(self, config_widget): - from calibre.gui2.store.basic_config_widget import save_settings - save_settings(config_widget) - - def get_settings(self): - from calibre.gui2 import gprefs - settings = {} - - settings[self.name + '_tags'] = gprefs.get(self.name + '_tags', self.name + ', store, download') - - return settings diff --git a/src/calibre/gui2/store/manybooks_plugin.py b/src/calibre/gui2/store/manybooks_plugin.py index d2531cc7b1..e1eb5eaa13 100644 --- a/src/calibre/gui2/store/manybooks_plugin.py +++ b/src/calibre/gui2/store/manybooks_plugin.py @@ -11,18 +11,15 @@ from contextlib import closing from lxml import html from calibre import browser -from calibre.customize import StorePlugin +from calibre.gui2.store import StorePlugin +from calibre.gui2.store.basic_config import BasicStoreConfig from calibre.gui2.store.search_result import SearchResult - -class ManyBooksStore(StorePlugin): - - name = 'ManyBooks' - description = _('The best ebooks at the best price: free!') - +from calibre.gui2.store.web_store_dialog import WebStoreDialog - def open(self, gui, parent=None, detail_item=None): - from calibre.gui2.store.web_store_dialog import WebStoreDialog - d = WebStoreDialog(gui, 'http://manybooks.net/', parent, detail_item) +class ManyBooksStore(BasicStoreConfig, StorePlugin): + + def open(self, parent=None, detail_item=None, external=False): + d = WebStoreDialog(self.gui, 'http://manybooks.net/', parent, detail_item) d.setWindowTitle(self.name) d.set_tags(self.name + ',' + _('store')) d = d.exec_() @@ -55,8 +52,9 @@ class ManyBooksStore(StorePlugin): id = url.split('/')[-1] id = id.strip() - heading = ''.join(url_a.xpath('text()')) - title, _, author = heading.partition('by ') + url_a = html.fromstring(html.tostring(url_a)) + heading = ''.join(url_a.xpath('//text()')) + title, _, author = heading.rpartition('by ') author = author.split('-')[0] price = '$0.00' @@ -78,22 +76,3 @@ class ManyBooksStore(StorePlugin): s.detail_item = '/titles/' + id yield s - - def customization_help(self, gui=False): - return 'Customize the behavior of this store.' - - def config_widget(self): - from calibre.gui2.store.basic_config_widget import BasicStoreConfigWidget - return BasicStoreConfigWidget(self) - - def save_settings(self, config_widget): - from calibre.gui2.store.basic_config_widget import save_settings - save_settings(config_widget) - - def get_settings(self): - from calibre.gui2 import gprefs - settings = {} - - settings[self.name + '_tags'] = gprefs.get(self.name + '_tags', self.name + ', store, download') - - return settings diff --git a/src/calibre/gui2/store/search.py b/src/calibre/gui2/store/search.py index 89e2cf2696..0f4a82ee5b 100644 --- a/src/calibre/gui2/store/search.py +++ b/src/calibre/gui2/store/search.py @@ -16,7 +16,6 @@ from PyQt4.Qt import Qt, QAbstractItemModel, QDialog, QTimer, QVariant, \ QPushButton from calibre import browser -from calibre.customize.ui import store_plugins from calibre.gui2 import NONE from calibre.gui2.store.search_ui import Ui_Dialog from calibre.utils.icu import sort_key @@ -29,17 +28,12 @@ COVER_DOWNLOAD_THREAD_TOTAL = 2 class SearchDialog(QDialog, Ui_Dialog): - def __init__(self, gui, *args): + def __init__(self, istores, *args): QDialog.__init__(self, *args) self.setupUi(self) - - # We pass this on to the store plugins so they can - # tell the gui's job system to start downloading an - # item. - self.gui = gui # We keep a cache of store plugins and reference them by name. - self.store_plugins = {} + self.store_plugins = istores self.search_pool = SearchThreadPool(SearchThread, SEARCH_THREAD_TOTAL) # Check for results and hung threads. self.checker = QTimer() @@ -53,12 +47,11 @@ class SearchDialog(QDialog, Ui_Dialog): # per search basis. stores_group_layout = QVBoxLayout() self.stores_group.setLayout(stores_group_layout) - for x in store_plugins(): - self.store_plugins[x.name] = x - cbox = QCheckBox(x.name) + for x in self.store_plugins: + cbox = QCheckBox(x) cbox.setChecked(True) stores_group_layout.addWidget(cbox) - setattr(self, 'store_check_' + x.name, cbox) + setattr(self, 'store_check_' + x, cbox) stores_group_layout.addStretch() self.search.clicked.connect(self.do_search) @@ -122,7 +115,7 @@ class SearchDialog(QDialog, Ui_Dialog): self.checker.stop() else: # Stop the checker if not threads are running. - if not self.search_pool.threads_running(): + if not self.search_pool.threads_running() and not self.search_pool.has_tasks(): self.checker.stop() while self.search_pool.has_results(): @@ -132,7 +125,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.gui, self, result.detail_item) + self.store_plugins[result.store_name].open(self, result.detail_item) def get_store_checks(self): ''' @@ -156,6 +149,10 @@ class SearchDialog(QDialog, Ui_Dialog): def stores_select_none(self): for check in self.get_store_checks(): check.setChecked(False) + + def closeEvent(self, e): + self.model.closing() + QDialog.closeEvent(self, e) class GenericDownloadThreadPool(object): @@ -305,6 +302,9 @@ class Matches(QAbstractItemModel): self.matches = [] self.cover_pool = CoverThreadPool(CoverThread, 2) self.cover_pool.start_threads() + + def closing(self): + self.cover_pool.abort() def clear_results(self): self.matches = [] @@ -315,7 +315,6 @@ class Matches(QAbstractItemModel): def add_result(self, result): self.layoutAboutToBeChanged.emit() self.matches.append(result) - self.cover_pool.add_task(result, self.update_result) self.layoutChanged.emit() diff --git a/src/calibre/gui2/store/smashwords_plugin.py b/src/calibre/gui2/store/smashwords_plugin.py index 5724b65669..dc9c308ad5 100644 --- a/src/calibre/gui2/store/smashwords_plugin.py +++ b/src/calibre/gui2/store/smashwords_plugin.py @@ -12,22 +12,19 @@ from contextlib import closing from lxml import html from calibre import browser -from calibre.customize import StorePlugin +from calibre.gui2.store import StorePlugin +from calibre.gui2.store.basic_config import BasicStoreConfig from calibre.gui2.store.search_result import SearchResult +from calibre.gui2.store.web_store_dialog import WebStoreDialog -class SmashwordsStore(StorePlugin): - - name = 'Smashwords' - description = _('Your ebook. Your way.') - - - def open(self, gui, parent=None, detail_item=None): - from calibre.gui2.store.web_store_dialog import WebStoreDialog +class SmashwordsStore(BasicStoreConfig, StorePlugin): + + def open(self, parent=None, detail_item=None, external=False): aff_id = 'usernone' # Use Kovid's affiliate id 30% of the time. if random.randint(1, 10) in (1, 2, 3): aff_id = 'kovidgoyal' - d = WebStoreDialog(gui, 'http://www.smashwords.com/?ref=%s' % aff_id, parent, detail_item) + d = WebStoreDialog(self.gui, 'http://www.smashwords.com/?ref=%s' % aff_id, parent, detail_item) d.setWindowTitle(self.name) d.set_tags(self.name + ',' + _('store')) d = d.exec_() @@ -78,22 +75,3 @@ class SmashwordsStore(StorePlugin): s.detail_item = '/books/view/' + id.strip() yield s - - def customization_help(self, gui=False): - return 'Customize the behavior of this store.' - - def config_widget(self): - from calibre.gui2.store.basic_config_widget import BasicStoreConfigWidget - return BasicStoreConfigWidget(self) - - def save_settings(self, config_widget): - from calibre.gui2.store.basic_config_widget import save_settings - save_settings(config_widget) - - def get_settings(self): - from calibre.gui2 import gprefs - settings = {} - - settings[self.name + '_tags'] = gprefs.get(self.name + '_tags', self.name + ', store, download') - - return settings diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index aa36279c85..629bea61af 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -22,7 +22,7 @@ from calibre.ptempfile import PersistentTemporaryFile from calibre.utils.config import prefs, dynamic from calibre.utils.ipc.server import Server from calibre.library.database2 import LibraryDatabase2 -from calibre.customize.ui import interface_actions +from calibre.customize.ui import interface_actions, store_plugins from calibre.gui2 import error_dialog, GetMetadata, open_local_file, \ gprefs, max_available_height, config, info_dialog, Dispatcher, \ question_dialog @@ -102,6 +102,7 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ self.device_connected = None self.gui_debug = gui_debug self.iactions = OrderedDict() + # Actions for action in interface_actions(): if opts.ignore_plugins and action.plugin_path is not None: continue @@ -114,11 +115,24 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ if action.plugin_path is None: raise continue - ac.plugin_path = action.plugin_path ac.interface_action_base_plugin = action - self.add_iaction(ac) + # Stores + self.istores = OrderedDict() + for store in store_plugins(): + if opts.ignore_plugins and store.plugin_path is not None: + continue + try: + st = self.init_istore(store) + self.add_istore(st) + except: + # Ignore errors in loading user supplied plugins + import traceback + traceback.print_exc() + if store.plugin_path is None: + raise + continue def init_iaction(self, action): ac = action.load_actual_plugin(self) @@ -126,6 +140,13 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ ac.interface_action_base_plugin = action action.actual_iaction_plugin_loaded = True return ac + + def init_istore(self, store): + st = store.load_actual_plugin(self) + st.plugin_path = store.plugin_path + st.base_plugin = store + store.actual_istore_plugin_loaded = True + return st def add_iaction(self, ac): acmap = self.iactions @@ -134,6 +155,14 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ acmap[ac.name] = ac else: acmap[ac.name] = ac + + def add_istore(self, st): + stmap = self.istores + if st.name in stmap: + if st.priority >= stmap[st.name].priority: + stmap[st.name] = st + else: + stmap[st.name] = st def initialize(self, library_path, db, listener, actions, show_gui=True): @@ -155,6 +184,8 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{ for ac in self.iactions.values(): ac.do_genesis() + for st in self.istores.values(): + st.do_genesis() MainWindowMixin.__init__(self, db) # Jobs Button {{{