mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Add an interface to permit starting and stopping of devices without disabling them. Will be used by the smartdevice driver
This commit is contained in:
parent
61ddf184f0
commit
76c0892b51
@ -514,6 +514,54 @@ class DevicePlugin(Plugin):
|
||||
'''
|
||||
pass
|
||||
|
||||
# Dynamic control interface
|
||||
|
||||
def is_dynamically_controllable(self):
|
||||
'''
|
||||
Called by the device manager when starting plugins. If this method returns
|
||||
a string, then a) it supports the device manager's dynamic control
|
||||
interface, and b) that name is to be used when talking to the plugin
|
||||
'''
|
||||
return None
|
||||
|
||||
def start_plugin(self):
|
||||
'''
|
||||
This method is called to start the plugin. The plugin should begin
|
||||
to accept device connections however it does that. If the plugin is
|
||||
already accepting connections, then do nothing.
|
||||
'''
|
||||
pass
|
||||
|
||||
def stop_plugin(self):
|
||||
'''
|
||||
This method is called to stop the plugin. The plugin should no longer
|
||||
accept connections, and should cleanup behind itself. It is likely that
|
||||
this method should call shutdown. If the plugin is already not accepting
|
||||
connections, then do nothing.
|
||||
'''
|
||||
pass
|
||||
|
||||
def get_option(self, opt_string):
|
||||
'''
|
||||
Return the value of the option indicated by opt_string. This method can
|
||||
be called when the plugin is not started. Return None if the option does
|
||||
not exist.
|
||||
'''
|
||||
return None
|
||||
|
||||
def set_option(self, opt_string, opt_value):
|
||||
'''
|
||||
Set the value of the option indicated by opt_string. This method can
|
||||
be called when the plugin is not started.
|
||||
'''
|
||||
pass
|
||||
|
||||
def is_running(self):
|
||||
'''
|
||||
Return True if the plugin is started, otherwise false
|
||||
'''
|
||||
return False
|
||||
|
||||
class BookList(list):
|
||||
'''
|
||||
A list of books. Each Book object must have the fields
|
||||
|
@ -24,6 +24,7 @@ class ShareConnMenu(QMenu): # {{{
|
||||
|
||||
config_email = pyqtSignal()
|
||||
toggle_server = pyqtSignal()
|
||||
toggle_smartdevice = pyqtSignal()
|
||||
dont_add_to = frozenset(['context-menu-device'])
|
||||
|
||||
def __init__(self, parent=None):
|
||||
@ -56,6 +57,11 @@ class ShareConnMenu(QMenu): # {{{
|
||||
_('Start Content Server'))
|
||||
self.toggle_server_action.triggered.connect(lambda x:
|
||||
self.toggle_server.emit())
|
||||
self.toggle_smartdevice_action = \
|
||||
self.addAction(QIcon(I('devices/galaxy_s3.png')),
|
||||
_('Start Smart Device Connections'))
|
||||
self.toggle_smartdevice_action.triggered.connect(lambda x:
|
||||
self.toggle_smartdevice.emit())
|
||||
self.addSeparator()
|
||||
|
||||
self.email_actions = []
|
||||
@ -80,6 +86,15 @@ class ShareConnMenu(QMenu): # {{{
|
||||
text = _('Stop Content Server') + ' [%s]'%get_external_ip()
|
||||
self.toggle_server_action.setText(text)
|
||||
|
||||
def smartdevice_state_changed(self, accepting):
|
||||
if accepting:
|
||||
self.toggle_smartdevice_action.setText(_('Stop Smart Device Connections'))
|
||||
else:
|
||||
self.toggle_smartdevice_action.setText(_('Start Smart Device Connections'))
|
||||
|
||||
def hide_smartdevice_menus(self):
|
||||
self.toggle_smartdevice_action.setVisible(False)
|
||||
|
||||
def build_email_entries(self, sync_menu):
|
||||
from calibre.gui2.device import DeviceAction
|
||||
for ac in self.email_actions:
|
||||
@ -158,6 +173,7 @@ class ConnectShareAction(InterfaceAction):
|
||||
def genesis(self):
|
||||
self.share_conn_menu = ShareConnMenu(self.gui)
|
||||
self.share_conn_menu.toggle_server.connect(self.toggle_content_server)
|
||||
self.share_conn_menu.toggle_smartdevice.connect(self.toggle_smartdevice)
|
||||
self.share_conn_menu.config_email.connect(partial(
|
||||
self.gui.iactions['Preferences'].do_config,
|
||||
initial_plugin=('Sharing', 'Email')))
|
||||
@ -200,8 +216,23 @@ class ConnectShareAction(InterfaceAction):
|
||||
if not self.stopping_msg.isVisible():
|
||||
self.stopping_msg.exec_()
|
||||
return
|
||||
|
||||
|
||||
self.gui.content_server = None
|
||||
self.stopping_msg.accept()
|
||||
|
||||
def toggle_smartdevice(self):
|
||||
info_dialog(self.gui, _('Foobar'),
|
||||
_('Start server bla bla blah...'),
|
||||
show_copy_button=False, show=True)
|
||||
if self.gui.device_manager.is_running('smartdevice'):
|
||||
self.gui.device_manager.stop_plugin('smartdevice')
|
||||
else:
|
||||
self.gui.device_manager.start_plugin('smartdevice')
|
||||
self.share_conn_menu.smartdevice_state_changed(
|
||||
self.gui.device_manager.is_running('smartdevice'))
|
||||
|
||||
def smartdevice_state_changed(self, running):
|
||||
self.share_conn_menu.smartdevice_state_changed(running)
|
||||
|
||||
def check_smartdevice_menus(self):
|
||||
if not self.gui.device_manager.is_enabled('smartdevice'):
|
||||
self.share_conn_menu.hide_smartdevice_menus()
|
||||
|
@ -145,6 +145,8 @@ class DeviceManager(Thread): # {{{
|
||||
self._device_information = None
|
||||
self.current_library_uuid = None
|
||||
self.call_shutdown_on_disconnect = False
|
||||
self.devices_initialized = Queue.Queue(0)
|
||||
self.dynamic_plugins = {}
|
||||
|
||||
def report_progress(self, *args):
|
||||
pass
|
||||
@ -286,6 +288,10 @@ class DeviceManager(Thread): # {{{
|
||||
# Do any device-specific startup processing.
|
||||
for d in self.devices:
|
||||
self.run_startup(d)
|
||||
n = d.is_dynamically_controllable()
|
||||
if n:
|
||||
self.dynamic_plugins[n] = d
|
||||
self.devices_initialized.put(None)
|
||||
|
||||
while self.keep_going:
|
||||
kls = None
|
||||
@ -508,6 +514,59 @@ class DeviceManager(Thread): # {{{
|
||||
if self.connected_device:
|
||||
self.connected_device.set_driveinfo_name(location_code, name)
|
||||
|
||||
# dynamic plugin interface
|
||||
|
||||
def start_plugin(self, name):
|
||||
try:
|
||||
d = self.dynamic_plugins.get(name, None)
|
||||
if d:
|
||||
d.start_plugin()
|
||||
except:
|
||||
pass
|
||||
|
||||
def stop_plugin(self, name):
|
||||
try:
|
||||
d = self.dynamic_plugins.get(name, None)
|
||||
if d:
|
||||
d.stop_plugin()
|
||||
except:
|
||||
pass
|
||||
|
||||
def get_option(self, name, opt_string):
|
||||
try:
|
||||
d = self.dynamic_plugins.get(name, None)
|
||||
if d:
|
||||
return d.get_option(opt_string)
|
||||
except:
|
||||
pass
|
||||
return None
|
||||
|
||||
def set_option(self, name, opt_string, opt_value):
|
||||
try:
|
||||
d = self.dynamic_plugins.get(name, None)
|
||||
if d:
|
||||
d.set_option(opt_string, opt_value)
|
||||
except:
|
||||
pass
|
||||
|
||||
def is_running(self, name):
|
||||
try:
|
||||
d = self.dynamic_plugins.get(name, None)
|
||||
if d:
|
||||
return d.is_running()
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
def is_enabled(self, name):
|
||||
try:
|
||||
d = self.dynamic_plugins.get(name, None)
|
||||
if d:
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
# }}}
|
||||
|
||||
class DeviceAction(QAction): # {{{
|
||||
@ -708,6 +767,7 @@ class DeviceMixin(object): # {{{
|
||||
self.job_manager, Dispatcher(self.status_bar.show_message),
|
||||
Dispatcher(self.show_open_feedback))
|
||||
self.device_manager.start()
|
||||
self.device_manager.devices_initialized.get()
|
||||
if tweaks['auto_connect_to_folder']:
|
||||
self.connect_to_folder_named(tweaks['auto_connect_to_folder'])
|
||||
|
||||
|
@ -337,6 +337,15 @@ class Main(MainWindow, MainWindowMixin, DeviceMixin, EmailMixin, # {{{
|
||||
if config['autolaunch_server']:
|
||||
self.start_content_server()
|
||||
|
||||
smartdevice_actions = self.iactions['Connect Share']
|
||||
smartdevice_actions.check_smartdevice_menus()
|
||||
if self.device_manager.get_option('smartdevice', 'autostart'):
|
||||
try:
|
||||
self.device_manager.start_plugin('smartdevice')
|
||||
smartdevice_actions.smartdevice_state_changed(True)
|
||||
except:
|
||||
pass
|
||||
|
||||
self.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection)
|
||||
|
||||
self.read_settings()
|
||||
|
@ -955,11 +955,16 @@ class Reaper(threading.Thread):
|
||||
return
|
||||
if globals()['_GLOBAL_DONE']:
|
||||
return
|
||||
now = currentTimeMillis()
|
||||
for record in self.zeroconf.cache.entries():
|
||||
if record.isExpired(now):
|
||||
self.zeroconf.updateRecord(now, record)
|
||||
self.zeroconf.cache.remove(record)
|
||||
try:
|
||||
# can get here in a race condition with shutdown. Swallow the
|
||||
# exception and run around the loop again.
|
||||
now = currentTimeMillis()
|
||||
for record in self.zeroconf.cache.entries():
|
||||
if record.isExpired(now):
|
||||
self.zeroconf.updateRecord(now, record)
|
||||
self.zeroconf.cache.remove(record)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
class ServiceBrowser(threading.Thread):
|
||||
|
Loading…
x
Reference in New Issue
Block a user