MTP: Popup a dialog asking the user if they want to manage the device with calibre the first time it is detected

This commit is contained in:
Kovid Goyal 2012-09-20 12:41:29 +05:30
parent e4739c1334
commit fa026406bb
4 changed files with 67 additions and 5 deletions

View File

@ -99,6 +99,12 @@ class DevicePlugin(Plugin):
#: after the books lists have been loaded to get the driveinfo.
SLOW_DRIVEINFO = False
#: If set to True, calibre will ask the user if they want to manage the
#: device with calibre, the first time it is detected. If you set this to
#: True you must implement :meth:`get_device_uid()` and
#: :meth:`ignore_connected_device()`.
ASK_TO_ALLOW_CONNECT = False
@classmethod
def get_gui_name(cls):
if hasattr(cls, 'gui_name'):
@ -587,6 +593,24 @@ class DevicePlugin(Plugin):
'''
pass
def get_device_uid(self):
'''
Must return a unique id for the currently connected device (this is
called immediately after a successful call to open()). You must
implement this method if you set ASK_TO_ALLOW_CONNECT = True
'''
raise NotImplementedError()
def ignore_connected_device(self, uid):
'''
Should ignore the device identified by uid (the result of a call to
get_device_uid()) in the future. You must implement this method if you
set ASK_TO_ALLOW_CONNECT = True. Note that this function is called
immediately after open(), so if open() caches some state, the driver
should reset that state.
'''
raise NotImplementedError()
# Dynamic control interface.
# The following methods are probably called on the GUI thread. Any driver
# that implements these methods must take pains to be thread safe, because

View File

@ -38,6 +38,7 @@ class MTP_DEVICE(BASE):
FORMATS = ['epub', 'azw3', 'mobi', 'pdf']
DEVICE_PLUGBOARD_NAME = 'MTP_DEVICE'
SLOW_DRIVEINFO = True
ASK_TO_ALLOW_CONNECT = True
def __init__(self, *args, **kwargs):
BASE.__init__(self, *args, **kwargs)
@ -90,6 +91,17 @@ class MTP_DEVICE(BASE):
self.current_device_defaults = self.device_defaults(device, self)
def get_device_uid(self):
return self.current_serial_num
def ignore_connected_device(self, uid):
bl = self.prefs['blacklist']
if uid not in bl:
bl.append(uid)
self.prefs['blacklist'] = bl
if self.is_mtp_device_connected:
self.eject()
# Device information {{{
def _update_drive_info(self, storage, location_code, name=None):
import uuid

View File

@ -294,7 +294,9 @@ def question_dialog(parent, title, msg, det_msg='', show_copy_button=False,
# Set skip_dialog_name to a unique name for this dialog
# Set skip_dialog_msg to a message displayed to the user
skip_dialog_name=None, skip_dialog_msg=_('Show this confirmation again'),
skip_dialog_skipped_value=True, skip_dialog_skip_precheck=True):
skip_dialog_skipped_value=True, skip_dialog_skip_precheck=True,
# Override icon (QIcon to be used as the icon for this dialog)
override_icon=None):
from calibre.gui2.dialogs.message_box import MessageBox
auto_skip = set(gprefs.get('questions_to_auto_skip', []))
@ -302,7 +304,8 @@ def question_dialog(parent, title, msg, det_msg='', show_copy_button=False,
return bool(skip_dialog_skipped_value)
d = MessageBox(MessageBox.QUESTION, title, msg, det_msg, parent=parent,
show_copy_button=show_copy_button, default_yes=default_yes)
show_copy_button=show_copy_button, default_yes=default_yes,
q_icon=override_icon)
if skip_dialog_name is not None and skip_dialog_msg:
tc = d.toggle_checkbox

View File

@ -20,7 +20,7 @@ from calibre.utils.ipc.job import BaseJob
from calibre.devices.scanner import DeviceScanner
from calibre.gui2 import (config, error_dialog, Dispatcher, dynamic,
warning_dialog, info_dialog, choose_dir, FunctionDispatcher,
show_restart_warning)
show_restart_warning, gprefs, question_dialog)
from calibre.ebooks.metadata import authors_to_string
from calibre import preferred_encoding, prints, force_unicode, as_unicode
from calibre.utils.filenames import ascii_filename
@ -122,7 +122,7 @@ def device_name_for_plugboards(device_class):
class DeviceManager(Thread): # {{{
def __init__(self, connected_slot, job_manager, open_feedback_slot,
open_feedback_msg, sleep_time=2):
open_feedback_msg, allow_connect_slot, sleep_time=2):
'''
:sleep_time: Time to sleep between device probes in secs
'''
@ -136,6 +136,7 @@ class DeviceManager(Thread): # {{{
x.MANAGES_DEVICE_PRESENCE]
self.sleep_time = sleep_time
self.connected_slot = connected_slot
self.allow_connect_slot = allow_connect_slot
self.jobs = Queue.Queue(0)
self.job_steps = Queue.Queue(0)
self.keep_going = True
@ -193,6 +194,21 @@ class DeviceManager(Thread): # {{{
return False
def after_device_connect(self, dev, device_kind):
allow_connect = True
try:
uid = dev.get_device_uid()
except NotImplementedError:
uid = None
asked = gprefs.get('ask_to_manage_device', [])
if (dev.ASK_TO_ALLOW_CONNECT and uid and uid not in asked):
if not self.allow_connect_slot(dev.get_gui_name()):
allow_connect = False
asked.append(uid)
gprefs.set('ask_to_manage_device', asked)
if not allow_connect:
dev.ignore_connected_device(uid)
return
self.connected_device = dev
self.connected_device_kind = device_kind
self.connected_slot(True, device_kind)
@ -829,12 +845,19 @@ class DeviceMixin(object): # {{{
self.device_error_dialog.setModal(Qt.NonModal)
self.device_manager = DeviceManager(FunctionDispatcher(self.device_detected),
self.job_manager, Dispatcher(self.status_bar.show_message),
Dispatcher(self.show_open_feedback))
Dispatcher(self.show_open_feedback),
FunctionDispatcher(self.allow_connect))
self.device_manager.start()
self.device_manager.devices_initialized.wait()
if tweaks['auto_connect_to_folder']:
self.connect_to_folder_named(tweaks['auto_connect_to_folder'])
def allow_connect(self, name):
return question_dialog(self, _('Mange the %s?')%name,
_('Detected the <b>%s</b>. Do you want calibre to manage it?')%
name, show_copy_button=False,
override_icon=QIcon(I('reader.png')))
def debug_detection(self, done):
self.debug_detection_callback = weakref.ref(done)
self.device_manager.debug_detection(FunctionDispatcher(self.debug_detection_done))