mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add action to context menu to copy selected books to another library
This commit is contained in:
parent
88618d085c
commit
f61c197194
@ -5,9 +5,57 @@ __license__ = 'GPL v3'
|
||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
from functools import partial
|
||||
from threading import Thread
|
||||
|
||||
from PyQt4.Qt import QMenu, QToolButton
|
||||
|
||||
from calibre.gui2.actions import InterfaceAction
|
||||
from calibre.gui2 import error_dialog, Dispatcher
|
||||
from calibre.gui2.dialogs.progress import ProgressDialog
|
||||
|
||||
class Worker(Thread):
|
||||
|
||||
def __init__(self, ids, db, loc, progress, done):
|
||||
Thread.__init__(self)
|
||||
self.ids = ids
|
||||
self.db = db
|
||||
self.loc = loc
|
||||
self.error = None
|
||||
self.progress = progress
|
||||
self.done = done
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
self.doit()
|
||||
except Exception, err:
|
||||
import traceback
|
||||
try:
|
||||
err = unicode(err)
|
||||
except:
|
||||
err = repr(err)
|
||||
self.error = (err, traceback.format_exc())
|
||||
|
||||
self.done()
|
||||
|
||||
def doit(self):
|
||||
from calibre.library.database2 import LibraryDatabase2
|
||||
newdb = LibraryDatabase2(self.loc)
|
||||
for i, x in enumerate(self.ids):
|
||||
mi = self.db.get_metadata(x, index_is_id=True, get_cover=True)
|
||||
self.progress(i, mi.title)
|
||||
fmts = self.db.formats(x, index_is_id=True)
|
||||
if not fmts: fmts = []
|
||||
else: fmts = fmts.split(',')
|
||||
paths = [self.db.format_abspath(x, fmt, index_is_id=True) for fmt in
|
||||
fmts]
|
||||
newdb.import_book(mi, paths, notify=False, import_hooks=False)
|
||||
co = self.db.conversion_options(x, 'PIPE')
|
||||
if co is not None:
|
||||
newdb.set_conversion_options(x, 'PIPE', co)
|
||||
|
||||
|
||||
|
||||
|
||||
class CopyToLibraryAction(InterfaceAction):
|
||||
|
||||
@ -18,5 +66,63 @@ class CopyToLibraryAction(InterfaceAction):
|
||||
|
||||
def genesis(self):
|
||||
self.menu = QMenu(self.gui)
|
||||
self.qaction.setMenu(self.menu)
|
||||
|
||||
@property
|
||||
def stats(self):
|
||||
return self.gui.iactions['Choose Library'].stats
|
||||
|
||||
def library_changed(self, db):
|
||||
self.build_menus()
|
||||
|
||||
def initialization_complete(self):
|
||||
self.library_changed(self.gui.library_view.model().db)
|
||||
|
||||
def location_selected(self, loc):
|
||||
enabled = loc == 'library'
|
||||
self.qaction.setEnabled(enabled)
|
||||
|
||||
def build_menus(self):
|
||||
self.menu.clear()
|
||||
db = self.gui.library_view.model().db
|
||||
locations = list(self.stats.locations(db))
|
||||
for name, loc in locations:
|
||||
self.menu.addAction(name, partial(self.copy_to_library,
|
||||
loc))
|
||||
self.qaction.setVisible(bool(locations))
|
||||
|
||||
def copy_to_library(self, loc):
|
||||
rows = self.gui.library_view.selectionModel().selectedRows()
|
||||
if not rows or len(rows) == 0:
|
||||
return error_dialog(self.gui, _('Cannot copy'),
|
||||
_('No books selected'), show=True)
|
||||
ids = list(map(self.gui.library_view.model().id, rows))
|
||||
db = self.gui.library_view.model().db
|
||||
if not db.exists_at(loc):
|
||||
return error_dialog(self.gui, _('No library'),
|
||||
_('No library found at %s')%loc, show=True)
|
||||
|
||||
|
||||
self.pd = ProgressDialog(_('Copying'), min=0, max=len(ids)-1,
|
||||
parent=self.gui, cancelable=False)
|
||||
|
||||
def progress(idx, title):
|
||||
self.pd.set_msg(_('Copying') + ' ' + title)
|
||||
self.pd.set_value(idx)
|
||||
|
||||
self.worker = Worker(ids, db, loc, Dispatcher(progress), Dispatcher(self.pd.accept))
|
||||
self.worker.start()
|
||||
|
||||
self.pd.exec_()
|
||||
|
||||
if self.worker.error is not None:
|
||||
e, tb = self.worker.error
|
||||
error_dialog(self.gui, _('Failed'), _('Could not copy books: ') + e,
|
||||
det_msg=tb, show=True)
|
||||
else:
|
||||
self.gui.status_bar.show_message(_('Copied %d books to %s') %
|
||||
(len(ids), loc), 2000)
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -28,9 +28,10 @@ def partial(*args, **kwargs):
|
||||
return ans
|
||||
|
||||
LIBRARY_CONTEXT_MENU = (
|
||||
'Edit Metadata', 'Send To Device', 'Save To Disk', 'Connect Share', None,
|
||||
'Convert Books', 'View', 'Open Folder', 'Show Book Details', None,
|
||||
'Remove Books',
|
||||
'Edit Metadata', 'Send To Device', 'Save To Disk',
|
||||
'Connect Share', 'Copy To Library', None,
|
||||
'Convert Books', 'View', 'Open Folder', 'Show Book Details',
|
||||
'Similar Books', None, 'Remove Books',
|
||||
)
|
||||
|
||||
DEVICE_CONTEXT_MENU = ('View', 'Save To Disk', None, 'Remove Books', None,
|
||||
|
@ -1754,7 +1754,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
return (paths, formats, metadata), len(ids)
|
||||
return None, len(ids)
|
||||
|
||||
def import_book(self, mi, formats, notify=True):
|
||||
def import_book(self, mi, formats, notify=True, import_hooks=True):
|
||||
series_index = 1.0 if mi.series_index is None else mi.series_index
|
||||
if not mi.title:
|
||||
mi.title = _('Unknown')
|
||||
@ -1779,7 +1779,11 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
||||
ext = os.path.splitext(path)[1][1:].lower()
|
||||
if ext == 'opf':
|
||||
continue
|
||||
self.add_format_with_hooks(id, ext, path, index_is_id=True)
|
||||
if import_hooks:
|
||||
self.add_format_with_hooks(id, ext, path, index_is_id=True)
|
||||
else:
|
||||
with open(path, 'rb') as f:
|
||||
self.add_format(id, ext, f, index_is_id=True)
|
||||
self.conn.commit()
|
||||
self.data.refresh_ids(self, [id]) # Needed to update format list and size
|
||||
if notify:
|
||||
|
Loading…
x
Reference in New Issue
Block a user