MTP: Implement prepare_addable_books and refactor the GUI to run prepare_addable_books in the device thread

This commit is contained in:
Kovid Goyal 2012-09-01 23:00:40 +05:30
parent b9737b9659
commit 2e66bd1aa5
3 changed files with 75 additions and 12 deletions

View File

@ -7,13 +7,13 @@ __license__ = 'GPL v3'
__copyright__ = '2012, Kovid Goyal <kovid at kovidgoyal.net>'
__docformat__ = 'restructuredtext en'
import json, traceback, posixpath, importlib
import json, traceback, posixpath, importlib, os
from io import BytesIO
from calibre import prints
from calibre.constants import iswindows, numeric_version
from calibre.devices.mtp.base import debug
from calibre.ptempfile import SpooledTemporaryFile
from calibre.ptempfile import SpooledTemporaryFile, PersistentTemporaryDirectory
from calibre.utils.config import from_json, to_json
from calibre.utils.date import now, isoformat
@ -199,10 +199,32 @@ class MTP_DEVICE(BASE):
# }}}
# Get files from the device {{{
def get_file(self, path, outfile, end_session=True):
f = self.filesystem_cache.resolve_mtp_id_path(path)
self.get_mtp_file(f, outfile)
def prepare_addable_books(self, paths):
tdir = PersistentTemporaryDirectory('_prepare_mtp')
ans = []
for path in paths:
try:
f = self.filesystem_cache.resolve_mtp_id_path(path)
except Exception as e:
ans.append((path, e, traceback.format_exc()))
continue
base = os.path.join(tdir, '%s'%f.object_id)
os.mkdir(base)
with open(os.path.join(base, f.name), 'wb') as out:
try:
self.get_mtp_file(f, out)
except Exception as e:
ans.append((path, e, traceback.format_exc()))
else:
ans.append(out.name)
return ans
# }}}
def create_upload_path(self, path, mdata, fname):
from calibre.devices import create_upload_path
from calibre.utils.filenames import ascii_filename as sanitize

View File

@ -10,9 +10,9 @@ from functools import partial
from PyQt4.Qt import QPixmap, QTimer
from calibre.gui2 import error_dialog, choose_files, \
choose_dir, warning_dialog, info_dialog
from calibre import as_unicode
from calibre.gui2 import (error_dialog, choose_files, choose_dir,
warning_dialog, info_dialog)
from calibre.gui2.dialogs.add_empty_book import AddEmptyBookDialog
from calibre.gui2.dialogs.progress import ProgressDialog
from calibre.gui2.widgets import IMAGE_EXTENSIONS
@ -400,12 +400,45 @@ class AddAction(InterfaceAction):
d = error_dialog(self.gui, _('Add to library'), _('No book files found'))
d.exec_()
return
paths = self.gui.device_manager.device.prepare_addable_books(paths)
from calibre.gui2.add import Adder
self.__adder_func = partial(self._add_from_device_adder, on_card=None,
model=view.model())
self._adder = Adder(self.gui, self.gui.library_view.model().db,
self.Dispatcher(self.__adder_func), spare_server=self.gui.spare_server)
self._adder.add(paths)
self.gui.device_manager.prepare_addable_books(self.Dispatcher(partial(
self.books_prepared, view)), paths)
self.bpd = ProgressDialog(_('Downloading books'),
msg=_('Downloading books from device'), parent=self.gui,
cancelable=False)
QTimer.singleShot(1000, self.show_bpd)
def show_bpd(self):
if self.bpd is not None:
self.bpd.show()
def books_prepared(self, view, job):
self.bpd.hide()
self.bpd = None
if job.exception is not None:
self.gui.device_job_exception(job)
return
paths = job.result
ok_paths = [x for x in paths if isinstance(x, basestring)]
failed_paths = [x for x in paths if isinstance(x, tuple)]
if failed_paths:
if not ok_paths:
msg = _('Could not download files from the device')
typ = error_dialog
else:
msg = _('Could not download some files from the device')
typ = warning_dialog
det_msg = [x[0]+ '\n ' + as_unicode(x[1]) for x in failed_paths]
det_msg = '\n\n'.join(det_msg)
typ(self.gui, _('Could not download files'), msg, det_msg=det_msg,
show=True)
if ok_paths:
from calibre.gui2.add import Adder
self.__adder_func = partial(self._add_from_device_adder, on_card=None,
model=view.model())
self._adder = Adder(self.gui, self.gui.library_view.model().db,
self.Dispatcher(self.__adder_func), spare_server=self.gui.spare_server)
self._adder.add(ok_paths)

View File

@ -443,6 +443,14 @@ class DeviceManager(Thread): # {{{
return self.create_job_step(self._books, done,
description=_('Get list of books on device'), to_job=add_as_step_to_job)
def _prepare_addable_books(self, paths):
return self.device.prepare_addable_books(paths)
def prepare_addable_books(self, done, paths, add_as_step_to_job=None):
return self.create_job_step(self._prepare_addable_books, done, args=[paths],
description=_('Prepare files for transfer from device'),
to_job=add_as_step_to_job)
def _annotations(self, path_map):
return self.device.get_annotations(path_map)