00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 import os
00032 import traceback
00033
00034 from dbus import Interface
00035 from dbus.connection import Connection
00036 from python_qt_binding.QtCore import QByteArray, qCritical, QDataStream, qDebug, QIODevice, Qt, qWarning, Slot
00037 from python_qt_binding.QtGui import QVBoxLayout, QX11EmbedWidget
00038
00039 from .plugin_handler_direct import PluginHandlerDirect
00040 from .settings import Settings
00041 from .window_changed_signaler import WindowChangedSignaler
00042
00043
00044 class PluginHandlerXEmbedClient(PluginHandlerDirect):
00045
00046 """
00047 Client part of the `PluginHandlerXEmbed`.
00048 It utilizes the `PluginHandlerDBusService` of the `PluginHandlerXEmbedContainer` through a peer-to-peer DBus connection.
00049 """
00050
00051 def __init__(self, parent, main_window, instance_id, application_context, container_manager, argv, dbus_object_path):
00052 super(PluginHandlerXEmbedClient, self).__init__(parent, main_window, instance_id, application_context, container_manager, argv)
00053 self.setObjectName('PluginHandlerXEmbedClient')
00054 self._dbus_object_path = dbus_object_path
00055 self._remote_container = None
00056 self._remote_plugin_settings = None
00057 self._remote_instance_settings = None
00058
00059 self._embed_widgets = {}
00060
00061 def _load(self):
00062 conn = Connection(self._application_context.options.embed_plugin_address)
00063 proxy = conn.get_object(None, self._dbus_object_path)
00064 self._remote_container = Interface(proxy, 'org.ros.qt_gui.PluginHandlerContainer')
00065 self._remote_container.connect_to_signal('shutdown_plugin', self._shutdown_plugin)
00066 self._remote_container.connect_to_signal('save_settings', self._save_settings_from_remote)
00067 self._remote_container.connect_to_signal('restore_settings', self._restore_settings_from_remote)
00068 self._remote_container.connect_to_signal('trigger_configuration', self._trigger_configuration)
00069 self._remote_container.connect_to_signal('toolbar_orientation_changed', self._toolbar_orientation_changed)
00070
00071 proxy = conn.get_object(None, self._dbus_object_path + '/plugin')
00072 self._remote_plugin_settings = Interface(proxy, 'org.ros.qt_gui.Settings')
00073 proxy = conn.get_object(None, self._dbus_object_path + '/instance')
00074 self._remote_instance_settings = Interface(proxy, 'org.ros.qt_gui.Settings')
00075
00076 super(PluginHandlerXEmbedClient, self)._load()
00077
00078 def _emit_load_completed(self, exception=None):
00079
00080 if exception is not None:
00081 self._remote_container.load_completed(False, False)
00082 super(PluginHandlerXEmbedClient, self)._emit_load_completed(exception)
00083
00084 if exception is None:
00085 self._remote_container.load_completed(True, self._plugin_has_configuration)
00086
00087 def shutdown_plugin(self, callback):
00088
00089 assert(False)
00090
00091 def emit_shutdown_plugin_completed(self):
00092 self._remote_container.shutdown_plugin_completed()
00093
00094 def save_settings(self, plugin_settings, instance_settings, callback=None):
00095
00096 assert(False)
00097
00098 def _save_settings_from_remote(self):
00099 qDebug('PluginHandlerXEmbedClient._save_settings_from_remote()')
00100 try:
00101 plugin_settings = Settings(self._remote_plugin_settings, '')
00102 instance_settings = Settings(self._remote_instance_settings, '')
00103 self._save_settings(plugin_settings, instance_settings)
00104 except Exception:
00105 qCritical('PluginHandlerXEmbedClient._save_settings_from_remote() plugin "%s" raised an exception:\n%s' % (str(self._instance_id), traceback.format_exc()))
00106 self.emit_save_settings_completed()
00107
00108 def emit_save_settings_completed(self):
00109 self._remote_container.save_settings_completed()
00110
00111 def restore_settings(self, plugin_settings, instance_settings, callback=None):
00112
00113 assert(False)
00114
00115 def _restore_settings_from_remote(self):
00116 qDebug('PluginHandlerXEmbedClient._restore_settings_from_remote()')
00117 try:
00118 plugin_settings = Settings(self._remote_plugin_settings, '')
00119 instance_settings = Settings(self._remote_instance_settings, '')
00120 self._restore_settings(plugin_settings, instance_settings)
00121 except Exception:
00122 qCritical('PluginHandlerXEmbedClient._restore_settings_from_remote() plugin "%s" raised an exception:\n%s' % (str(self._instance_id), traceback.format_exc()))
00123 self.emit_restore_settings_completed()
00124
00125 def emit_restore_settings_completed(self):
00126 self._remote_container.restore_settings_completed()
00127
00128
00129 @Slot('QWidget*')
00130 def add_widget(self, widget):
00131 if widget in self._embed_widgets:
00132 qWarning('PluginHandlerXEmbedClient.add_widget() widget "%s" already added' % widget.objectName())
00133 return
00134 embed_widget = QX11EmbedWidget()
00135 layout = QVBoxLayout()
00136 layout.setContentsMargins(0, 0, 0, 0)
00137 layout.addWidget(widget)
00138 embed_widget.setLayout(layout)
00139
00140
00141
00142
00143
00144 embed_container_window_id = self._remote_container.embed_widget(os.getpid(), widget.objectName())
00145 embed_widget.embedInto(embed_container_window_id)
00146
00147 signaler = WindowChangedSignaler(widget, widget)
00148 signaler.window_icon_changed_signal.connect(self._on_embed_widget_icon_changed)
00149 signaler.window_title_changed_signal.connect(self._on_embed_widget_title_changed)
00150 self._embed_widgets[widget] = embed_widget, signaler
00151
00152 signaler.window_icon_changed_signal.emit(widget)
00153 signaler.window_title_changed_signal.emit(widget)
00154
00155 embed_widget.show()
00156
00157 def _on_embed_widget_icon_changed(self, widget):
00158
00159 ba = QByteArray()
00160 s = QDataStream(ba, QIODevice.WriteOnly)
00161 s << widget.windowIcon()
00162 icon_str = str(ba.toBase64())
00163 self._remote_container.update_embedded_widget_icon(widget.objectName(), icon_str)
00164
00165 def _on_embed_widget_title_changed(self, widget):
00166 self._remote_container.update_embedded_widget_title(widget.objectName(), widget.windowTitle())
00167
00168
00169 @Slot('QWidget*')
00170 def remove_widget(self, widget):
00171 embed_widget, signaler = self._embed_widgets[widget]
00172 del self._embed_widgets[widget]
00173 signaler.window_icon_changed_signal.disconnect(self._on_embed_widget_icon_changed)
00174 signaler.window_title_changed_signal.disconnect(self._on_embed_widget_title_changed)
00175 self._remote_container.unembed_widget(widget.objectName())
00176
00177 widget.setParent(None)
00178 embed_widget.deleteLater()
00179
00180
00181
00182 @Slot('QToolBar*')
00183 def add_toolbar(self, toolbar):
00184 if toolbar in self._embed_widgets:
00185 qWarning('PluginHandlerXEmbedClient.add_toolbar() toolbar "%s" already added' % toolbar.objectName())
00186 return
00187 embed_widget = QX11EmbedWidget()
00188 layout = QVBoxLayout()
00189 layout.setContentsMargins(0, 0, 0, 0)
00190 layout.addWidget(toolbar)
00191 embed_widget.setLayout(layout)
00192
00193
00194
00195
00196 def foo():
00197 print('embed_widget.containerClosed')
00198 embed_widget.containerClosed.connect(foo)
00199
00200 embed_container_window_id = self._remote_container.embed_toolbar(os.getpid(), toolbar.objectName())
00201 embed_widget.embedInto(embed_container_window_id)
00202
00203 self._embed_widgets[toolbar] = embed_widget, None
00204
00205 embed_widget.show()
00206
00207 def _toolbar_orientation_changed(self, win_id, is_horizontal):
00208 for toolbar, (embed_widget, _) in self._embed_widgets.items():
00209 if embed_widget.containerWinId() == win_id:
00210 toolbar.setOrientation(Qt.Horizontal if is_horizontal else Qt.Vertical)
00211 break
00212
00213
00214 @Slot('QToolBar*')
00215 def remove_toolbar(self, toolbar):
00216 embed_widget, _ = self._embed_widgets[toolbar]
00217 del self._embed_widgets[toolbar]
00218 self._remote_container.unembed_widget(toolbar.objectName())
00219
00220 toolbar.setParent(None)
00221 embed_widget.deleteLater()
00222
00223
00224 def _emit_close_plugin(self):
00225 self._remote_container.close_plugin()