Merge from trunk

This commit is contained in:
Charles Haley 2012-09-20 17:41:39 +02:00
commit 9dbe62c036
8 changed files with 72 additions and 9 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

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

@ -27,7 +27,7 @@ def synchronous(func):
class MTPDeviceBase(DevicePlugin):
name = 'MTP Device Interface'
gui_name = _('MTP Device')
icon = I('devices/galaxy_s3.png')
icon = I('devices/tablet.png')
description = _('Communicate with MTP devices')
author = 'Kovid Goyal'
version = (1, 0, 0)

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

@ -34,7 +34,7 @@ from calibre.library import current_library_name
from calibre.library.server import server_config as content_server_config
from calibre.ptempfile import PersistentTemporaryFile
from calibre.utils.ipc import eintr_retry_call
from calibre.utils.config import from_json, tweaks, ConfigProxy
from calibre.utils.config import from_json, tweaks
from calibre.utils.date import isoformat, now
from calibre.utils.filenames import ascii_filename as sanitize, shorten_components_to
from calibre.utils.mdns import (publish as publish_zeroconf, unpublish as
@ -171,7 +171,7 @@ class SDBook(Book):
class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
name = 'SmartDevice App Interface'
gui_name = _('Wireless Device')
gui_name = gui_name_base = _('Wireless Device')
gui_name_template = '%s: %s'
icon = I('devices/galaxy_s3.png')
@ -1056,6 +1056,7 @@ class SMART_DEVICE_APP(DeviceConfig, DevicePlugin):
def eject(self):
self._debug()
self._close_device_socket()
self.gui_name = self.gui_name_base
@synchronous('sync_lock')
def post_yank_cleanup(self):

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(), dev.icon):
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, icon):
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(icon))
def debug_detection(self, done):
self.debug_detection_callback = weakref.ref(done)
self.device_manager.debug_detection(FunctionDispatcher(self.debug_detection_done))

View File

@ -415,6 +415,7 @@ class MTPConfig(QTabWidget):
return True
def commit(self):
self.device.prefs['blacklist'] = self.igntab.blacklist
p = self.device.prefs.get(self.current_device_key, {})
if hasattr(self, 'formats'):
@ -440,7 +441,6 @@ class MTPConfig(QTabWidget):
self.device.prefs[self.current_device_key] = p
self.device.prefs['blacklist'] = self.igntab.blacklist
if __name__ == '__main__':
from calibre.gui2 import Application