From cb07d093e25fddef5f569577c920a1cd33788740 Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 12 Aug 2010 17:59:51 -0600 Subject: [PATCH] Migrate catalog and convert actions. And remove layout spec from plugins --- src/calibre/customize/builtins.py | 15 +++- src/calibre/gui2/actions/__init__.py | 5 +- src/calibre/gui2/actions/add.py | 3 - src/calibre/gui2/actions/annotate.py | 2 +- src/calibre/gui2/actions/catalog.py | 38 +++++----- src/calibre/gui2/actions/convert.py | 99 ++++++++++++++++---------- src/calibre/gui2/actions/fetch_news.py | 3 + src/calibre/gui2/device.py | 8 +-- src/calibre/gui2/layout.py | 12 ---- src/calibre/gui2/ui.py | 1 - 10 files changed, 103 insertions(+), 83 deletions(-) diff --git a/src/calibre/customize/builtins.py b/src/calibre/customize/builtins.py index d71d934e2c..8462ae5d38 100644 --- a/src/calibre/customize/builtins.py +++ b/src/calibre/customize/builtins.py @@ -578,11 +578,20 @@ plugins += input_profiles + output_profiles from calibre.customize import InterfaceActionBase class ActionAdd(InterfaceActionBase): - name = 'action_add' + name = 'Add Books' actual_plugin = 'calibre.gui2.actions.add:AddAction' class ActionFetchAnnotations(InterfaceActionBase): - name = 'action_fetch_annotations' + name = 'Fetch Annotations' actual_plugin = 'calibre.gui2.actions.annotate:FetchAnnotationsAction' -plugins += [ActionAdd, ActionFetchAnnotations] +class ActionGenerateCatalog(InterfaceActionBase): + name = 'Generate Catalog' + actual_plugin = 'calibre.gui2.actions.catalog:GenerateCatalogAction' + +class ActionConvert(InterfaceActionBase): + name = 'Convert Books' + actual_plugin = 'calibre.gui2.actions.convert:ConvertAction' + +plugins += [ActionAdd, ActionFetchAnnotations, ActionGenerateCatalog, + ActionConvert] diff --git a/src/calibre/gui2/actions/__init__.py b/src/calibre/gui2/actions/__init__.py index 74a8cbe5f5..65d0078c50 100644 --- a/src/calibre/gui2/actions/__init__.py +++ b/src/calibre/gui2/actions/__init__.py @@ -16,17 +16,16 @@ class InterfaceAction(QObject): name = 'Implement me' priority = 1 positions = frozenset([]) - separators = frozenset([]) - popup_type = QToolButton.MenuPopup #: Of the form: (text, icon_path, tooltip, keyboard shortcut) - #: tooltip and keybard shortcut can be None + #: icon, tooltip and keybard shortcut can be None #: shortcut must be a translated string if not None action_spec = ('text', 'icon', None, None) def __init__(self, parent, site_customization): QObject.__init__(self, parent) + self.setObjectName(self.name) self.gui = parent self.site_customization = site_customization diff --git a/src/calibre/gui2/actions/add.py b/src/calibre/gui2/actions/add.py index 8c6b627d5c..668af0957e 100644 --- a/src/calibre/gui2/actions/add.py +++ b/src/calibre/gui2/actions/add.py @@ -23,9 +23,6 @@ class AddAction(InterfaceAction): name = 'Add Books' action_spec = (_('Add books'), 'add_book.svg', None, _('A')) - positions = frozenset([ - ('toolbar', 'all', 0), - ]) def genesis(self): self._add_filesystem_book = self.Dispatcher(self.__add_filesystem_book) diff --git a/src/calibre/gui2/actions/annotate.py b/src/calibre/gui2/actions/annotate.py index e4c45742c2..d8b7b829b2 100644 --- a/src/calibre/gui2/actions/annotate.py +++ b/src/calibre/gui2/actions/annotate.py @@ -17,7 +17,7 @@ from calibre.gui2.actions import InterfaceAction class FetchAnnotationsAction(InterfaceAction): name = 'Fetch Annotations' - action_spec = (_('Fetch Annotations'), None, None, None) + action_spec = (_('Fetch annotations (experimental)'), None, None, None) def genesis(self): pass diff --git a/src/calibre/gui2/actions/catalog.py b/src/calibre/gui2/actions/catalog.py index f8c9b24b30..6807d7717e 100644 --- a/src/calibre/gui2/actions/catalog.py +++ b/src/calibre/gui2/actions/catalog.py @@ -9,58 +9,62 @@ import os, shutil from PyQt4.Qt import QModelIndex -from calibre.gui2 import error_dialog, Dispatcher, choose_dir +from calibre.gui2 import error_dialog, choose_dir from calibre.gui2.tools import generate_catalog from calibre.utils.config import dynamic +from calibre.gui2.actions import InterfaceAction -class GenerateCatalogAction(object): +class GenerateCatalogAction(InterfaceAction): + + name = 'Generate Catalog' + action_spec = (_('Create catalog of books in your calibre library'), None, None, None) def generate_catalog(self): - rows = self.library_view.selectionModel().selectedRows() + rows = self.gui.library_view.selectionModel().selectedRows() if not rows or len(rows) < 2: - rows = xrange(self.library_view.model().rowCount(QModelIndex())) - ids = map(self.library_view.model().id, rows) + rows = xrange(self.gui.library_view.model().rowCount(QModelIndex())) + ids = map(self.gui.library_view.model().id, rows) dbspec = None if not ids: - return error_dialog(self, _('No books selected'), + return error_dialog(self.gui, _('No books selected'), _('No books selected to generate catalog for'), show=True) # Calling gui2.tools:generate_catalog() - ret = generate_catalog(self, dbspec, ids, self.device_manager.device) + ret = generate_catalog(self.gui, dbspec, ids, self.gui.device_manager.device) if ret is None: return func, args, desc, out, sync, title = ret fmt = os.path.splitext(out)[1][1:].upper() - job = self.job_manager.run_job( - Dispatcher(self.catalog_generated), func, args=args, + job = self.gui.job_manager.run_job( + self.Dispatcher(self.catalog_generated), func, args=args, description=desc) job.catalog_file_path = out job.fmt = fmt job.catalog_sync, job.catalog_title = sync, title - self.status_bar.show_message(_('Generating %s catalog...')%fmt) + self.gui.status_bar.show_message(_('Generating %s catalog...')%fmt) def catalog_generated(self, job): if job.result: # Search terms nulled catalog results - return error_dialog(self, _('No books found'), + return error_dialog(self.gui, _('No books found'), _("No books to catalog\nCheck exclude tags"), show=True) if job.failed: - return self.job_exception(job) - id = self.library_view.model().add_catalog(job.catalog_file_path, job.catalog_title) - self.library_view.model().reset() + return self.gui.job_exception(job) + id = self.gui.library_view.model().add_catalog(job.catalog_file_path, job.catalog_title) + self.gui.library_view.model().reset() if job.catalog_sync: sync = dynamic.get('catalogs_to_be_synced', set([])) sync.add(id) dynamic.set('catalogs_to_be_synced', sync) - self.status_bar.show_message(_('Catalog generated.'), 3000) - self.sync_catalogs() + self.gui.status_bar.show_message(_('Catalog generated.'), 3000) + self.gui.sync_catalogs() if job.fmt not in ['EPUB','MOBI']: - export_dir = choose_dir(self, _('Export Catalog Directory'), + export_dir = choose_dir(self.gui, _('Export Catalog Directory'), _('Select destination for %s.%s') % (job.catalog_title, job.fmt.lower())) if export_dir: destination = os.path.join(export_dir, '%s.%s' % (job.catalog_title, job.fmt.lower())) diff --git a/src/calibre/gui2/actions/convert.py b/src/calibre/gui2/actions/convert.py index 9d5f1da048..ace877b315 100644 --- a/src/calibre/gui2/actions/convert.py +++ b/src/calibre/gui2/actions/convert.py @@ -6,133 +6,154 @@ __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' import os +from functools import partial -from PyQt4.Qt import QModelIndex +from PyQt4.Qt import QModelIndex, QMenu from calibre.gui2 import error_dialog, Dispatcher from calibre.gui2.tools import convert_single_ebook, convert_bulk_ebook from calibre.utils.config import prefs +from calibre.gui2.actions import InterfaceAction + +class ConvertAction(InterfaceAction): + + name = 'Convert Books' + action_spec = (_('Convert books'), 'convert.svg', None, _('C')) + + def genesis(self): + cm = QMenu() + cm.addAction(_('Convert individually'), partial(self.convert_ebook, + False, bulk=False)) + cm.addAction(_('Bulk convert'), + partial(self.convert_ebook, False, bulk=True)) + cm.addSeparator() + ac = cm.addAction( + _('Create catalog of books in your calibre library')) + ac.triggered.connect(self.gui.iactions['Generate Catalog'].generate_catalog) + self.qaction.setMenu(cm) + self.qaction.triggered.connect(self.convert_ebook) + self.convert_menu = cm + self.conversion_jobs = {} -class ConvertAction(object): def auto_convert(self, book_ids, on_card, format): - previous = self.library_view.currentIndex() + previous = self.gui.library_view.currentIndex() rows = [x.row() for x in \ - self.library_view.selectionModel().selectedRows()] - jobs, changed, bad = convert_single_ebook(self, self.library_view.model().db, book_ids, True, format) + self.gui.library_view.selectionModel().selectedRows()] + jobs, changed, bad = convert_single_ebook(self.gui, self.gui.library_view.model().db, book_ids, True, format) if jobs == []: return self.queue_convert_jobs(jobs, changed, bad, rows, previous, self.book_auto_converted, extra_job_args=[on_card]) def auto_convert_mail(self, to, fmts, delete_from_library, book_ids, format): - previous = self.library_view.currentIndex() + previous = self.gui.library_view.currentIndex() rows = [x.row() for x in \ - self.library_view.selectionModel().selectedRows()] - jobs, changed, bad = convert_single_ebook(self, self.library_view.model().db, book_ids, True, format) + self.gui.library_view.selectionModel().selectedRows()] + jobs, changed, bad = convert_single_ebook(self.gui, self.gui.library_view.model().db, book_ids, True, format) if jobs == []: return self.queue_convert_jobs(jobs, changed, bad, rows, previous, self.book_auto_converted_mail, extra_job_args=[delete_from_library, to, fmts]) def auto_convert_news(self, book_ids, format): - previous = self.library_view.currentIndex() + previous = self.gui.library_view.currentIndex() rows = [x.row() for x in \ - self.library_view.selectionModel().selectedRows()] - jobs, changed, bad = convert_single_ebook(self, self.library_view.model().db, book_ids, True, format) + self.gui.library_view.selectionModel().selectedRows()] + jobs, changed, bad = convert_single_ebook(self.gui, self.gui.library_view.model().db, book_ids, True, format) if jobs == []: return self.queue_convert_jobs(jobs, changed, bad, rows, previous, self.book_auto_converted_news) def auto_convert_catalogs(self, book_ids, format): - previous = self.library_view.currentIndex() + previous = self.gui.library_view.currentIndex() rows = [x.row() for x in \ - self.library_view.selectionModel().selectedRows()] - jobs, changed, bad = convert_single_ebook(self, self.library_view.model().db, book_ids, True, format) + self.gui.library_view.selectionModel().selectedRows()] + jobs, changed, bad = convert_single_ebook(self.gui, self.gui.library_view.model().db, book_ids, True, format) if jobs == []: return self.queue_convert_jobs(jobs, changed, bad, rows, previous, self.book_auto_converted_catalogs) def get_books_for_conversion(self): rows = [r.row() for r in \ - self.library_view.selectionModel().selectedRows()] + self.gui.library_view.selectionModel().selectedRows()] if not rows or len(rows) == 0: - d = error_dialog(self, _('Cannot convert'), + d = error_dialog(self.gui, _('Cannot convert'), _('No books selected')) d.exec_() return None - return [self.library_view.model().db.id(r) for r in rows] + return [self.gui.library_view.model().db.id(r) for r in rows] def convert_ebook(self, checked, bulk=None): book_ids = self.get_books_for_conversion() if book_ids is None: return - previous = self.library_view.currentIndex() + previous = self.gui.library_view.currentIndex() rows = [x.row() for x in \ - self.library_view.selectionModel().selectedRows()] + self.gui.library_view.selectionModel().selectedRows()] num = 0 if bulk or (bulk is None and len(book_ids) > 1): - self.__bulk_queue = convert_bulk_ebook(self, self.queue_convert_jobs, - self.library_view.model().db, book_ids, + self.__bulk_queue = convert_bulk_ebook(self.gui, self.queue_convert_jobs, + self.gui.library_view.model().db, book_ids, out_format=prefs['output_format'], args=(rows, previous, self.book_converted)) if self.__bulk_queue is None: return num = len(self.__bulk_queue.book_ids) else: - jobs, changed, bad = convert_single_ebook(self, - self.library_view.model().db, book_ids, out_format=prefs['output_format']) + jobs, changed, bad = convert_single_ebook(self.gui, + self.gui.library_view.model().db, book_ids, out_format=prefs['output_format']) self.queue_convert_jobs(jobs, changed, bad, rows, previous, self.book_converted) num = len(jobs) if num > 0: - self.status_bar.show_message(_('Starting conversion of %d book(s)') % + self.gui.status_bar.show_message(_('Starting conversion of %d book(s)') % num, 2000) def queue_convert_jobs(self, jobs, changed, bad, rows, previous, converted_func, extra_job_args=[]): for func, args, desc, fmt, id, temp_files in jobs: if id not in bad: - job = self.job_manager.run_job(Dispatcher(converted_func), + job = self.gui.job_manager.run_job(Dispatcher(converted_func), func, args=args, description=desc) args = [temp_files, fmt, id]+extra_job_args self.conversion_jobs[job] = tuple(args) if changed: - self.library_view.model().refresh_rows(rows) - current = self.library_view.currentIndex() - self.library_view.model().current_changed(current, previous) + self.gui.library_view.model().refresh_rows(rows) + current = self.gui.library_view.currentIndex() + self.gui.library_view.model().current_changed(current, previous) def book_auto_converted(self, job): temp_files, fmt, book_id, on_card = self.conversion_jobs[job] self.book_converted(job) - self.sync_to_device(on_card, False, specific_format=fmt, send_ids=[book_id], do_auto_convert=False) + self.gui.sync_to_device(on_card, False, specific_format=fmt, send_ids=[book_id], do_auto_convert=False) def book_auto_converted_mail(self, job): temp_files, fmt, book_id, delete_from_library, to, fmts = self.conversion_jobs[job] self.book_converted(job) - self.send_by_mail(to, fmts, delete_from_library, specific_format=fmt, send_ids=[book_id], do_auto_convert=False) + self.gui.send_by_mail(to, fmts, delete_from_library, specific_format=fmt, send_ids=[book_id], do_auto_convert=False) def book_auto_converted_news(self, job): temp_files, fmt, book_id = self.conversion_jobs[job] self.book_converted(job) - self.sync_news(send_ids=[book_id], do_auto_convert=False) + self.gui.sync_news(send_ids=[book_id], do_auto_convert=False) def book_auto_converted_catalogs(self, job): temp_files, fmt, book_id = self.conversion_jobs[job] self.book_converted(job) - self.sync_catalogs(send_ids=[book_id], do_auto_convert=False) + self.gui.sync_catalogs(send_ids=[book_id], do_auto_convert=False) def book_converted(self, job): temp_files, fmt, book_id = self.conversion_jobs.pop(job)[:3] try: if job.failed: - self.job_exception(job) + self.gui.job_exception(job) return data = open(temp_files[-1].name, 'rb') - self.library_view.model().db.add_format(book_id, \ + self.gui.library_view.model().db.add_format(book_id, \ fmt, data, index_is_id=True) data.close() - self.status_bar.show_message(job.description + \ + self.gui.status_bar.show_message(job.description + \ (' completed'), 2000) finally: for f in temp_files: @@ -141,8 +162,8 @@ class ConvertAction(object): os.remove(f.name) except: pass - self.tags_view.recount() - if self.current_view() is self.library_view: - current = self.library_view.currentIndex() - self.library_view.model().current_changed(current, QModelIndex()) + self.gui.tags_view.recount() + if self.gui.current_view() is self.gui.library_view: + current = self.gui.library_view.currentIndex() + self.gui.library_view.model().current_changed(current, QModelIndex()) diff --git a/src/calibre/gui2/actions/fetch_news.py b/src/calibre/gui2/actions/fetch_news.py index c051f362f1..72c93937dc 100644 --- a/src/calibre/gui2/actions/fetch_news.py +++ b/src/calibre/gui2/actions/fetch_news.py @@ -11,6 +11,9 @@ from calibre.utils.config import dynamic class FetchNewsAction(object): + def genesis(self): + self.conversion_jobs = {} + def download_scheduled_recipe(self, arg): func, args, desc, fmt, temp_files = \ fetch_scheduled_recipe(arg) diff --git a/src/calibre/gui2/device.py b/src/calibre/gui2/device.py index 0f83afa6dd..6cc8e47aa5 100644 --- a/src/calibre/gui2/device.py +++ b/src/calibre/gui2/device.py @@ -925,7 +925,7 @@ class DeviceMixin(object): # {{{ _('Auto convert the following books before sending via ' 'email?'), det_msg=autos, buttons=QMessageBox.Yes|QMessageBox.Cancel): - self.auto_convert_mail(to, fmts, delete_from_library, auto, format) + self.iactions['Convert Books'].auto_convert_mail(to, fmts, delete_from_library, auto, format) if bad: bad = '\n'.join('%s'%(i,) for i in bad) @@ -1027,7 +1027,7 @@ class DeviceMixin(object): # {{{ _('Auto convert the following books before uploading to ' 'the device?'), det_msg=autos, buttons=QMessageBox.Yes|QMessageBox.Cancel): - self.auto_convert_catalogs(auto, format) + self.iactions['Convert Books'].auto_convert_catalogs(auto, format) files = [f for f in files if f is not None] if not files: dynamic.set('catalogs_to_be_synced', set([])) @@ -1089,7 +1089,7 @@ class DeviceMixin(object): # {{{ _('Auto convert the following books before uploading to ' 'the device?'), det_msg=autos, buttons=QMessageBox.Yes|QMessageBox.Cancel): - self.auto_convert_news(auto, format) + self.iactions['Convert Books'].auto_convert_news(auto, format) files = [f for f in files if f is not None] for f in files: f.deleted_after_upload = del_on_upload @@ -1208,7 +1208,7 @@ class DeviceMixin(object): # {{{ _('Auto convert the following books before uploading to ' 'the device?'), det_msg=autos, buttons=QMessageBox.Yes|QMessageBox.Cancel): - self.auto_convert(auto, on_card, format) + self.iactions['Convert Books'].auto_convert(auto, on_card, format) if bad: bad = '\n'.join('%s'%(i,) for i in bad) diff --git a/src/calibre/gui2/layout.py b/src/calibre/gui2/layout.py index 05763db658..b0851c0b25 100644 --- a/src/calibre/gui2/layout.py +++ b/src/calibre/gui2/layout.py @@ -585,18 +585,6 @@ class MainWindowMixin(object): self.action_edit.setMenu(md) self.action_save.setMenu(self.save_menu) - cm = QMenu() - cm.addAction(_('Convert individually'), partial(self.convert_ebook, - False, bulk=False)) - cm.addAction(_('Bulk convert'), - partial(self.convert_ebook, False, bulk=True)) - cm.addSeparator() - ac = cm.addAction( - _('Create catalog of books in your calibre library')) - ac.triggered.connect(self.generate_catalog) - self.action_convert.setMenu(cm) - self.action_convert.triggered.connect(self.convert_ebook) - self.convert_menu = cm pm = QMenu() pm.addAction(QIcon(I('config.svg')), _('Preferences'), self.do_config) diff --git a/src/calibre/gui2/ui.py b/src/calibre/gui2/ui.py index 63b1e72de4..79d16eeb5a 100644 --- a/src/calibre/gui2/ui.py +++ b/src/calibre/gui2/ui.py @@ -150,7 +150,6 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, # {{{ self.get_metadata = GetMetadata() self.upload_memory = {} self.delete_memory = {} - self.conversion_jobs = {} self.persistent_files = [] self.metadata_dialogs = [] self.default_thumbnail = None