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
|
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):
|
class BookList(list):
|
||||||
'''
|
'''
|
||||||
A list of books. Each Book object must have the fields
|
A list of books. Each Book object must have the fields
|
||||||
|
@ -24,6 +24,7 @@ class ShareConnMenu(QMenu): # {{{
|
|||||||
|
|
||||||
config_email = pyqtSignal()
|
config_email = pyqtSignal()
|
||||||
toggle_server = pyqtSignal()
|
toggle_server = pyqtSignal()
|
||||||
|
toggle_smartdevice = pyqtSignal()
|
||||||
dont_add_to = frozenset(['context-menu-device'])
|
dont_add_to = frozenset(['context-menu-device'])
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
@ -56,6 +57,11 @@ class ShareConnMenu(QMenu): # {{{
|
|||||||
_('Start Content Server'))
|
_('Start Content Server'))
|
||||||
self.toggle_server_action.triggered.connect(lambda x:
|
self.toggle_server_action.triggered.connect(lambda x:
|
||||||
self.toggle_server.emit())
|
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.addSeparator()
|
||||||
|
|
||||||
self.email_actions = []
|
self.email_actions = []
|
||||||
@ -80,6 +86,15 @@ class ShareConnMenu(QMenu): # {{{
|
|||||||
text = _('Stop Content Server') + ' [%s]'%get_external_ip()
|
text = _('Stop Content Server') + ' [%s]'%get_external_ip()
|
||||||
self.toggle_server_action.setText(text)
|
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):
|
def build_email_entries(self, sync_menu):
|
||||||
from calibre.gui2.device import DeviceAction
|
from calibre.gui2.device import DeviceAction
|
||||||
for ac in self.email_actions:
|
for ac in self.email_actions:
|
||||||
@ -158,6 +173,7 @@ class ConnectShareAction(InterfaceAction):
|
|||||||
def genesis(self):
|
def genesis(self):
|
||||||
self.share_conn_menu = ShareConnMenu(self.gui)
|
self.share_conn_menu = ShareConnMenu(self.gui)
|
||||||
self.share_conn_menu.toggle_server.connect(self.toggle_content_server)
|
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.share_conn_menu.config_email.connect(partial(
|
||||||
self.gui.iactions['Preferences'].do_config,
|
self.gui.iactions['Preferences'].do_config,
|
||||||
initial_plugin=('Sharing', 'Email')))
|
initial_plugin=('Sharing', 'Email')))
|
||||||
@ -200,8 +216,23 @@ class ConnectShareAction(InterfaceAction):
|
|||||||
if not self.stopping_msg.isVisible():
|
if not self.stopping_msg.isVisible():
|
||||||
self.stopping_msg.exec_()
|
self.stopping_msg.exec_()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
self.gui.content_server = None
|
self.gui.content_server = None
|
||||||
self.stopping_msg.accept()
|
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._device_information = None
|
||||||
self.current_library_uuid = None
|
self.current_library_uuid = None
|
||||||
self.call_shutdown_on_disconnect = False
|
self.call_shutdown_on_disconnect = False
|
||||||
|
self.devices_initialized = Queue.Queue(0)
|
||||||
|
self.dynamic_plugins = {}
|
||||||
|
|
||||||
def report_progress(self, *args):
|
def report_progress(self, *args):
|
||||||
pass
|
pass
|
||||||
@ -286,6 +288,10 @@ class DeviceManager(Thread): # {{{
|
|||||||
# Do any device-specific startup processing.
|
# Do any device-specific startup processing.
|
||||||
for d in self.devices:
|
for d in self.devices:
|
||||||
self.run_startup(d)
|
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:
|
while self.keep_going:
|
||||||
kls = None
|
kls = None
|
||||||
@ -508,6 +514,59 @@ class DeviceManager(Thread): # {{{
|
|||||||
if self.connected_device:
|
if self.connected_device:
|
||||||
self.connected_device.set_driveinfo_name(location_code, name)
|
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): # {{{
|
class DeviceAction(QAction): # {{{
|
||||||
@ -708,6 +767,7 @@ class DeviceMixin(object): # {{{
|
|||||||
self.job_manager, Dispatcher(self.status_bar.show_message),
|
self.job_manager, Dispatcher(self.status_bar.show_message),
|
||||||
Dispatcher(self.show_open_feedback))
|
Dispatcher(self.show_open_feedback))
|
||||||
self.device_manager.start()
|
self.device_manager.start()
|
||||||
|
self.device_manager.devices_initialized.get()
|
||||||
if tweaks['auto_connect_to_folder']:
|
if tweaks['auto_connect_to_folder']:
|
||||||
self.connect_to_folder_named(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']:
|
if config['autolaunch_server']:
|
||||||
self.start_content_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.keyboard_interrupt.connect(self.quit, type=Qt.QueuedConnection)
|
||||||
|
|
||||||
self.read_settings()
|
self.read_settings()
|
||||||
|
@ -955,11 +955,16 @@ class Reaper(threading.Thread):
|
|||||||
return
|
return
|
||||||
if globals()['_GLOBAL_DONE']:
|
if globals()['_GLOBAL_DONE']:
|
||||||
return
|
return
|
||||||
now = currentTimeMillis()
|
try:
|
||||||
for record in self.zeroconf.cache.entries():
|
# can get here in a race condition with shutdown. Swallow the
|
||||||
if record.isExpired(now):
|
# exception and run around the loop again.
|
||||||
self.zeroconf.updateRecord(now, record)
|
now = currentTimeMillis()
|
||||||
self.zeroconf.cache.remove(record)
|
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):
|
class ServiceBrowser(threading.Thread):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user