mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Migrate catalog and convert actions. And remove layout spec from plugins
This commit is contained in:
parent
206547021d
commit
cb07d093e2
@ -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]
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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()))
|
||||
|
@ -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())
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user