plugin_manager.py
Go to the documentation of this file.
1 # Copyright (c) 2011, Dirk Thomas, Dorian Scholz, TU Darmstadt
2 # All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions
6 # are met:
7 #
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following
12 # disclaimer in the documentation and/or other materials provided
13 # with the distribution.
14 # * Neither the name of the TU Darmstadt nor the names of its
15 # contributors may be used to endorse or promote products derived
16 # from this software without specific prior written permission.
17 #
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 # POSSIBILITY OF SUCH DAMAGE.
30 
31 import time
32 import traceback
33 
34 from python_qt_binding.QtCore import \
35  qCritical, qDebug, QObject, Qt, qWarning, Signal, Slot
36 
37 from qt_gui.errors import PluginLoadError
38 from qt_gui.plugin_handler_container import PluginHandlerContainer
39 from qt_gui.plugin_handler_direct import PluginHandlerDirect
40 from qt_gui.plugin_instance_id import PluginInstanceId
41 from qt_gui.plugin_menu import PluginMenu
42 from qt_gui.settings import Settings
43 from qt_gui.settings_proxy import SettingsProxy
44 
45 
46 class PluginManager(QObject):
47  """
48  Manager of plugin life cycle.
49 
50  It creates a specific `PluginHandler` for each plugin instance and maintains the perspective
51  specific set of running plugins.
52  """
53 
54  plugins_about_to_change_signal = Signal()
55  plugins_changed_signal = Signal()
56  plugin_help_signal = Signal(object)
57  save_settings_completed_signal = Signal()
58  close_application_signal = Signal()
59  _deferred_reload_plugin_signal = Signal(str)
60 
61  discovery_cache_max_age = 60 * 60 * 24 # one day
62 
63  def __init__(self, plugin_provider, settings, application_context, settings_prefix=''):
64  super(PluginManager, self).__init__()
65  self.setObjectName('PluginManager')
66 
67  self._plugin_provider = plugin_provider
68  self._settings = Settings(SettingsProxy(settings), '/'.join(
69  [x for x in ['plugin_manager', settings_prefix] if x != '']))
70  self._application_context = application_context
71 
72  self._main_window = None
73  self._container_manager = None
74  self._plugin_menu = None
76 
77  self._global_settings = None
79  self._plugin_descriptors = None
80  self._running_plugins = {}
81 
83 
84  if self._application_context.options.multi_process or \
85  self._application_context.options.embed_plugin:
86  try:
87  from qt_gui.plugin_handler_xembed import PluginHandlerXEmbed # noqa: F401
88  except ImportError:
89  qCritical('PluginManager.__init__() multiprocess-mode only available under linux')
90  exit(-1)
91 
92  # force connection type to queued, to delay the 'reloading' giving the
93  # 'unloading' time to finish
94  self._deferred_reload_plugin_signal.connect(
95  self._reload_plugin_load, type=Qt.QueuedConnection)
96 
97  if self._application_context.provide_app_dbus_interfaces:
98  from qt_gui.plugin_manager_dbus_interface import PluginManagerDBusInterface
99  self._dbus_service = PluginManagerDBusInterface(self, self._application_context)
100 
101  def set_main_window(self, main_window, menu_bar, container_manager):
102  self._main_window = main_window
103  self._container_manager = container_manager
104  self.plugins_changed_signal.connect(self._container_manager.restore_state_of_containers)
105  if menu_bar is not None:
106  self._plugin_menu = PluginMenu(menu_bar, self)
107  self._plugin_menu.load_plugin_signal.connect(self.load_plugin)
108  self._plugin_menu.unload_plugin_signal.connect(self.unload_plugin)
109 
111  self._minimized_dock_widgets_toolbar = toolbar
112 
113  def discover(self):
114  # skip discover if called multiple times
115  if self._plugin_descriptors is not None:
116  return
117  self._plugin_descriptors = {}
118 
119  # register discovered plugins
120  plugin_descriptors = self._discover()
121  for plugin_descriptor in plugin_descriptors:
122  self._plugin_descriptors[plugin_descriptor.plugin_id()] = plugin_descriptor
123 
124  if self._plugin_menu is not None:
125  self._plugin_menu.add_plugin(plugin_descriptor)
126 
127  if self._container_manager is not None:
128  descriptor = self._container_manager.get_container_descriptor()
129  self._plugin_descriptors[descriptor.plugin_id()] = descriptor
130  if self._plugin_menu is not None:
131  self._container_manager.add_to_plugin_menu(self._plugin_menu)
132 
133  def _discover(self):
134  discovery_data = self._settings.get_settings('discovery_data')
135  # check timestamp of the cached discovery data
136  cache_stamp = self._settings.value('discovery_timestamp', default_value=None)
137  if cache_stamp:
138  cache_stamp = float(cache_stamp)
139 
140  # wipe cached data when forcing discovery or when cache is to old (or from the future)
141  now = time.time()
142  if self._application_context.options.force_discover or \
143  not cache_stamp or \
144  cache_stamp > now or \
145  cache_stamp + PluginManager.discovery_cache_max_age < now:
146  qDebug('PluginManager._discover() force discovery of plugins')
147  cache_stamp = None
148  for k in discovery_data.all_keys():
149  discovery_data.remove(k)
150  else:
151  qDebug('PluginManager._discover() using cached plugin discovery information')
152 
153  plugin_descriptors = self._plugin_provider.discover(discovery_data)
154 
155  # store timestamp and newly discovered data
156  if not cache_stamp:
157  self._settings.set_value('discovery_timestamp', now)
158 
159  return plugin_descriptors
160 
161  def find_plugins_by_name(self, lookup_name):
162  plugins = {}
163  for plugin_id, plugin_full_name in self.get_plugins().items():
164  if plugin_full_name.lower().find(lookup_name.lower()) >= 0 or \
165  plugin_id.lower().find(lookup_name.lower()) >= 0:
166  plugins[plugin_id] = plugin_full_name
167  return plugins
168 
169  def get_plugins(self):
170  self.discover()
171  plugins = {}
172  for plugin_id, plugin_descriptor in self._plugin_descriptors.items():
173  plugins[plugin_id] = '/'.join(
174  plugin_descriptor.attributes().get('class_type', 'unknown').split('::'))
175  return plugins
176 
177  def get_plugin_descriptor(self, plugin_id):
178  return self._plugin_descriptors.get(plugin_id, None)
179 
180  def is_plugin_running(self, plugin_id, serial_number):
181  instance_id = PluginInstanceId(plugin_id, serial_number)
182  return str(instance_id) in self._running_plugins
183 
184  @Slot(str)
185  @Slot(str, int)
186  def load_plugin(self, plugin_id, serial_number=None, argv=None):
187  qDebug('PluginManager.load_plugin(%s, %s)' %
188  (str(plugin_id), str(serial_number) if serial_number is not None else ''))
189  # save state of top-level widgets
191  if serial_number is None:
192  serial_number = self._next_serial_number(plugin_id)
193  instance_id = PluginInstanceId(plugin_id, serial_number)
194  self._load_plugin_load(instance_id, self._load_plugin_restore, argv)
195 
196  def _next_serial_number(self, plugin_id):
197  # convert from unicode
198  plugin_id = str(plugin_id)
199  # collect serial numbers of all running instances of the specific plugin
200  used_serial_numbers = {}
201  for info in self._running_plugins.values():
202  if info['instance_id'].plugin_id == plugin_id:
203  used_serial_numbers[info['instance_id'].serial_number] = None
204 
205  # find first not used serial number
206  serial_number = 1
207  while serial_number in used_serial_numbers:
208  serial_number = serial_number + 1
209  return serial_number
210 
211  def _load_plugin_load(self, instance_id, callback, argv=None):
212  # if the requested instance is already running, do nothing
213  if str(instance_id) in self._running_plugins:
214  raise Exception(
215  'PluginManager._load_plugin(%s) instance already loaded' % str(instance_id))
216 
217  # containers are pseudo-plugins and handled by a special handler
218  if self._container_manager is not None and \
219  instance_id.plugin_id == \
220  self._container_manager.get_container_descriptor().plugin_id():
221  handler = PluginHandlerContainer(self, self._main_window, instance_id,
223 
224  # use platform specific handler for multiprocess-mode if available
225  elif self._application_context.options.multi_process or \
226  self._application_context.options.embed_plugin:
227  try:
228  from qt_gui.plugin_handler_xembed import PluginHandlerXEmbed
229  handler = \
230  PluginHandlerXEmbed(self, self._main_window, instance_id,
231  self._application_context, self._container_manager, argv)
232  except ImportError:
233  qCritical(
234  'PluginManager._load_plugin() could not load plugin in a separate process')
235  return
236 
237  # use direct handler for in-process plugins
238  else:
239  handler = PluginHandlerDirect(self, self._main_window, instance_id,
240  self._application_context, self._container_manager, argv)
241 
242  handler.set_minimized_dock_widgets_toolbar(self._minimized_dock_widgets_toolbar)
243 
244  if instance_id.plugin_id not in self._plugin_descriptors.keys():
245  qWarning(
246  'PluginManager._load_plugin() could not load plugin "%s": plugin not available' %
247  (instance_id.plugin_id))
248  return
249  plugin_descriptor = self._plugin_descriptors[instance_id.plugin_id]
250  handler.set_plugin_descriptor(plugin_descriptor)
251 
252  self._add_running_plugin(instance_id, handler)
253  handler.load(self._plugin_provider, callback)
254 
255  def _add_running_plugin(self, instance_id, handler):
256  if self._plugin_menu is not None:
257  plugin_descriptor = self._plugin_descriptors[instance_id.plugin_id]
258  self._plugin_menu.add_instance(plugin_descriptor, instance_id)
259  handler.label_updated.connect(self._plugin_menu.update_plugin_instance_label)
260 
261  info = {
262  'handler': handler,
263  'instance_id': instance_id
264  }
265  self._running_plugins[str(instance_id)] = info
266 
267  def _load_plugin_restore(self, handler, exception):
268  qDebug('PluginManager._load_plugin_restore()')
269  self._load_plugin_completed(handler, exception)
270  if exception is None:
271  # restore settings after load
272  self._restore_plugin_settings(handler.instance_id(), self._emit_load_plugin_completed)
273 
274  def _load_plugin_completed(self, handler, exception):
275  instance_id = handler.instance_id()
276  if exception is not None:
277  if isinstance(exception, PluginLoadError):
278  qWarning('PluginManager._load_plugin() could not load plugin "%s": %s' %
279  (instance_id.plugin_id, exception))
280  else:
281  qCritical('PluginManager._load_plugin() could not load plugin "%s"%s' %
282  (instance_id.plugin_id, (':\n%s' % traceback.format_exc() if
283  isinstance(exception, Exception) else '')))
284  self._remove_running_plugin(instance_id)
285  # quit embed application
286  if self._application_context.options.embed_plugin:
287  exit(-1)
288  return
289 
290  qDebug('PluginManager._load_plugin(%s) successful' % str(instance_id))
291 
292  handler.close_signal.connect(self.unload_plugin)
293  handler.reload_signal.connect(self.reload_plugin)
294  handler.help_signal.connect(self._emit_plugin_help_signal)
295 
296  def _emit_plugin_help_signal(self, instance_id_str):
297  instance_id = PluginInstanceId(instance_id=instance_id_str)
298  plugin_descriptor = self._plugin_descriptors[instance_id.plugin_id]
299  self.plugin_help_signal.emit(plugin_descriptor)
300 
301  def _restore_plugin_settings(self, instance_id, callback):
302  if self._global_settings is not None and self._perspective_settings is not None:
303  info = self._running_plugins[str(instance_id)]
304  plugin_settings = self._global_settings.get_settings(
305  'plugin__' + instance_id.tidy_plugin_str())
306  instance_settings = self._perspective_settings.get_settings(
307  'plugin__' + instance_id.tidy_str())
308  handler = info['handler']
309  handler.restore_settings(plugin_settings, instance_settings, callback)
310  else:
311  callback(instance_id)
312 
313  def _emit_load_plugin_completed(self, instance_id):
314  qDebug('PluginManager._emit_load_plugin_completed()')
315  # restore state of top-level widgets
316  self.plugins_changed_signal.emit()
317 
318  @Slot(str)
319  def unload_plugin(self, instance_id_str):
320  # unloading a plugin with locked perspective or running standalone
321  # triggers close of application
322  if self._application_context.options.lock_perspective or \
323  self._application_context.options.standalone_plugin:
325  return
326  instance_id = PluginInstanceId(instance_id=instance_id_str)
327  qDebug('PluginManager.unload_plugin(%s)' % str(instance_id))
328  # save state of top-level widgets
330  # save settings before shutdown and unloading
331  self._save_plugin_settings(instance_id, self._unload_plugin_shutdown)
332 
333  def _save_plugin_settings(self, instance_id, callback):
334  if self._global_settings is not None and self._perspective_settings is not None:
335  info = self._running_plugins[str(instance_id)]
336  plugin_settings = self._global_settings.get_settings(
337  'plugin__' + instance_id.tidy_plugin_str())
338  instance_settings = self._perspective_settings.get_settings(
339  'plugin__' + instance_id.tidy_str())
340  handler = info['handler']
341  handler.save_settings(plugin_settings, instance_settings, callback)
342  else:
343  callback(instance_id)
344 
345  def _unload_plugin_shutdown(self, instance_id):
346  qDebug('PluginManager._unload_plugin_shutdown(%s)' % str(instance_id))
347  self._shutdown_plugin(instance_id, self._unload_plugin_unload)
348 
349  def _shutdown_plugin(self, instance_id, callback):
350  # shutdown plugin before unloading
351  info = self._running_plugins[str(instance_id)]
352  handler = info['handler']
353  handler.close_signal.disconnect(self.unload_plugin)
354  handler.shutdown_plugin(callback)
355 
356  def _unload_plugin_unload(self, instance_id):
357  qDebug('PluginManager._unload_plugin_unload(%s)' % str(instance_id))
358  self._unload_plugin(instance_id, self._unload_plugin_completed)
359 
360  def _unload_plugin(self, instance_id, callback=None):
361  # unload plugin
362  info = self._running_plugins[str(instance_id)]
363  handler = info['handler']
364  handler.unload(callback)
365 
366  def _unload_plugin_completed(self, instance_id):
367  qDebug('PluginManager._unload_plugin_completed(%s)' % str(instance_id))
368  self._remove_running_plugin(instance_id)
369 
370  def _remove_running_plugin(self, instance_id):
371  info = self._running_plugins[str(instance_id)]
372  if self._plugin_menu is not None:
373  self._plugin_menu.remove_instance(instance_id)
374  info['handler'].label_updated.disconnect(
375  self._plugin_menu.update_plugin_instance_label)
376  self._running_plugins.pop(str(instance_id))
377 
378  @Slot(str)
379  def reload_plugin(self, instance_id_str):
380  instance_id = PluginInstanceId(instance_id=instance_id_str)
381  qDebug('PluginManager.reload_plugin(%s)' % str(instance_id))
382  # save state of top-level widgets
384  self._reload_plugin_save(instance_id)
385 
386  def _reload_plugin_save(self, instance_id):
387  # save settings before unloading
388  self._save_plugin_settings(instance_id, self._reload_plugin_shutdown)
389 
390  def _reload_plugin_shutdown(self, instance_id):
391  qDebug('PluginManager._reload_plugin_shutdown(%s)' % str(instance_id))
392  self._shutdown_plugin(instance_id, self._reload_plugin_unload)
393 
394  def _reload_plugin_unload(self, instance_id):
395  qDebug('PluginManager._reload_plugin_unload(%s)' % str(instance_id))
396  self._unload_plugin(instance_id, self._reload_plugin_schedule_load)
397 
398  def _reload_plugin_schedule_load(self, instance_id):
399  qDebug('PluginManager._reload_plugin_schedule_load(%s)' % str(instance_id))
400  self._remove_running_plugin(instance_id)
401  self._deferred_reload_plugin_signal.emit(str(instance_id))
402 
403  def _reload_plugin_load(self, instance_id_str):
404  instance_id = PluginInstanceId(instance_id=instance_id_str)
405  qDebug('PluginManager._reload_plugin_load(%s)' % str(instance_id))
406  self._load_plugin_load(instance_id, self._reload_plugin_restore)
407 
408  def _reload_plugin_restore(self, handler, exception):
409  qDebug('PluginManager._reload_plugin_restore()')
410  self._load_plugin_completed(handler, exception)
411  if exception is None:
412  # restore settings after load
413  self._restore_plugin_settings(handler.instance_id(), self._emit_load_plugin_completed)
414 
415  def save_settings(self, global_settings, perspective_settings):
416  self._save_settings(global_settings, perspective_settings, self._save_settings_callback)
417 
418  def _save_settings(self, global_settings, perspective_settings, callback):
419  qDebug('PluginManager.save_settings()')
420  self._global_settings = global_settings.get_settings('pluginmanager')
421  self._perspective_settings = perspective_settings.get_settings('pluginmanager')
423  # trigger async call on all running plugins
425  if self._number_of_ongoing_calls > 0:
426  # If changing perspectives, plugins may be removed from this dictionary during
427  # _save_plugin_settings, so a shallow copy of the values is needed
428  for info in list(self._running_plugins.values()):
429  self._save_plugin_settings(info['instance_id'], callback)
430  else:
431  callback()
432 
434  if self._perspective_settings is not None:
435  plugins = {}
436  for info in self._running_plugins.values():
437  instance_id = info['instance_id']
438  plugin_id = instance_id.plugin_id
439  if plugin_id not in plugins:
440  plugins[plugin_id] = []
441  plugins[plugin_id].append(instance_id.serial_number)
442  self._perspective_settings.set_value('running-plugins', plugins)
443 
444  def _save_settings_callback(self, instance_id=None):
445  if instance_id is not None:
447  if self._number_of_ongoing_calls == 0:
448  qDebug('PluginManager.save_settings() completed')
449  self._number_of_ongoing_calls = None
451 
452  def close_application(self, global_settings, perspective_settings):
453  self._save_settings(
454  global_settings, perspective_settings, self._close_application_save_callback)
455 
456  def _close_application_save_callback(self, instance_id=None):
457  self._save_settings_callback(instance_id)
458  if self._number_of_ongoing_calls is None:
460 
462  # trigger async call on all running plugins
464  if self._number_of_ongoing_calls > 0:
465  for info in self._running_plugins.values():
466  self._shutdown_plugin(
467  info['instance_id'], self._close_application_shutdown_callback)
468  else:
470 
471  def _close_application_shutdown_callback(self, instance_id=None):
472  if instance_id is not None:
474  if self._number_of_ongoing_calls == 0:
475  qDebug('PluginManager.close_application() completed')
476  self._number_of_ongoing_calls = None
478 
480  self._plugin_provider.shutdown()
481  self.close_application_signal.emit()
482 
483  def restore_settings(self, global_settings, perspective_settings):
484  qDebug('PluginManager.restore_settings()')
485  self._global_settings = global_settings.get_settings('pluginmanager')
486  self._perspective_settings = perspective_settings.get_settings('pluginmanager')
488 
490  # trigger shutdown of obsolete plugins
491  plugins = self._restore_running_plugins_get_plugins()
492  obsolete = []
493  for instance_id in self._running_plugins.keys():
494  if instance_id not in plugins.keys():
495  obsolete.append(PluginInstanceId(instance_id=instance_id))
496  self._number_of_ongoing_calls = len(obsolete)
497  if self._number_of_ongoing_calls > 0:
498  qDebug('PluginManager.restore_settings() unloading %d obsolete plugins' %
500  for instance_id in obsolete:
502  else:
504 
506  plugins = {}
507  if self._perspective_settings is not None:
508  data = self._perspective_settings.value('running-plugins', {})
509  for plugin_id, serial_numbers in data.items():
510  for serial_number in serial_numbers:
511  instance_id = PluginInstanceId(plugin_id, serial_number)
512  plugins[str(instance_id)] = instance_id
513  return plugins
514 
515  def _restore_settings_unload_obsolete(self, instance_id):
516  # trigger unload of obsolete plugins
518 
519  def _restore_settings_unload_obsolete_callback(self, instance_id=None):
520  if instance_id is not None:
522  self._remove_running_plugin(instance_id)
523  if self._number_of_ongoing_calls == 0:
524  if instance_id is not None:
525  qDebug('PluginManager.restore_settings() all obsolete plugins unloaded')
526  self._number_of_ongoing_calls = None
528 
530  # trigger_load of not yet loaded plugins
531  plugins = self._restore_running_plugins_get_plugins()
532  loading = []
533  for instance_id_str, instance_id in plugins.items():
534  if instance_id_str not in self._running_plugins.keys():
535  loading.append(instance_id)
536  self._number_of_ongoing_calls = len(loading)
537  if self._number_of_ongoing_calls > 0:
538  qDebug('PluginManager.restore_settings() loading %d plugins' %
540  for instance_id in loading:
542  else:
544 
545  def _restore_settings_load_missing_callback(self, handler=None, exception=None):
546  if handler is not None:
548  self._load_plugin_completed(handler, exception)
549  if self._number_of_ongoing_calls == 0:
550  if handler is not None:
551  qDebug('PluginManager.restore_settings() all missing plugins loaded')
552  self._number_of_ongoing_calls = None
554 
555  def restore_settings_without_plugins(self, global_settings, perspective_settings):
556  qDebug('PluginManager.restore_settings_without_plugins()')
557  self._global_settings = global_settings.get_settings('pluginmanager')
558  self._perspective_settings = perspective_settings.get_settings('pluginmanager')
560 
562  # trigger restore settings for all running plugins
564  if self._number_of_ongoing_calls > 0:
565  for info in self._running_plugins.values():
567  info['instance_id'], self._restore_settings_restore_callback)
568  else:
570 
571  def _restore_settings_restore_callback(self, instance_id=None):
572  if instance_id is not None:
574  if self._number_of_ongoing_calls == 0:
575  if instance_id is not None:
576  qDebug('PluginManager.restore_settings() all plugin settings restored')
577  self._number_of_ongoing_calls = None
578  # restore state of top-level widgets
579  self.plugins_changed_signal.emit()
def _restore_settings_unload_obsolete_callback(self, instance_id=None)
def load_plugin(self, plugin_id, serial_number=None, argv=None)
def find_plugins_by_name(self, lookup_name)
def restore_settings(self, global_settings, perspective_settings)
def is_plugin_running(self, plugin_id, serial_number)
def reload_plugin(self, instance_id_str)
def _load_plugin_restore(self, handler, exception)
def _save_settings(self, global_settings, perspective_settings, callback)
def _unload_plugin_shutdown(self, instance_id)
def _emit_load_plugin_completed(self, instance_id)
def set_main_window(self, main_window, menu_bar, container_manager)
def _load_plugin_load(self, instance_id, callback, argv=None)
def save_settings(self, global_settings, perspective_settings)
def get_plugin_descriptor(self, plugin_id)
def _unload_plugin(self, instance_id, callback=None)
def _reload_plugin_save(self, instance_id)
def _restore_settings_load_missing_callback(self, handler=None, exception=None)
def _next_serial_number(self, plugin_id)
def _add_running_plugin(self, instance_id, handler)
def _unload_plugin_unload(self, instance_id)
def set_minimized_dock_widgets_toolbar(self, toolbar)
def _restore_settings_restore_callback(self, instance_id=None)
def _remove_running_plugin(self, instance_id)
def close_application(self, global_settings, perspective_settings)
def _restore_settings_unload_obsolete(self, instance_id)
def _close_application_shutdown_callback(self, instance_id=None)
def _load_plugin_completed(self, handler, exception)
def _reload_plugin_restore(self, handler, exception)
def _emit_plugin_help_signal(self, instance_id_str)
def _reload_plugin_load(self, instance_id_str)
def _restore_plugin_settings(self, instance_id, callback)
def __init__(self, plugin_provider, settings, application_context, settings_prefix='')
def _save_plugin_settings(self, instance_id, callback)
def restore_settings_without_plugins(self, global_settings, perspective_settings)
def _save_settings_callback(self, instance_id=None)
def _unload_plugin_completed(self, instance_id)
def _reload_plugin_shutdown(self, instance_id)
def _close_application_save_callback(self, instance_id=None)
def unload_plugin(self, instance_id_str)
def _shutdown_plugin(self, instance_id, callback)
def _reload_plugin_schedule_load(self, instance_id)
def _reload_plugin_unload(self, instance_id)


qt_gui
Author(s): Dirk Thomas
autogenerated on Fri Jun 24 2022 02:42:37