Migrate catalog and convert actions. And remove layout spec from plugins

This commit is contained in:
Kovid Goyal 2010-08-12 17:59:51 -06:00
parent 206547021d
commit cb07d093e2
10 changed files with 103 additions and 83 deletions

View File

@ -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]

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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()))

View File

@ -6,133 +6,154 @@ __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__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())

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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