plugin_handler_xembed_client.py
Go to the documentation of this file.
00001 # Copyright (c) 2011, Dirk Thomas, Dorian Scholz, TU Darmstadt
00002 # All rights reserved.
00003 #
00004 # Redistribution and use in source and binary forms, with or without
00005 # modification, are permitted provided that the following conditions
00006 # are met:
00007 #
00008 #   * Redistributions of source code must retain the above copyright
00009 #     notice, this list of conditions and the following disclaimer.
00010 #   * Redistributions in binary form must reproduce the above
00011 #     copyright notice, this list of conditions and the following
00012 #     disclaimer in the documentation and/or other materials provided
00013 #     with the distribution.
00014 #   * Neither the name of the TU Darmstadt nor the names of its
00015 #     contributors may be used to endorse or promote products derived
00016 #     from this software without specific prior written permission.
00017 #
00018 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00019 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00021 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00022 # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00023 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00024 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00026 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00027 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00028 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00029 # POSSIBILITY OF SUCH DAMAGE.
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         # mapping of added widgets to their embed widget and WindowChangedSignaler
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         # signal failed loading before emitting signal, as it might not be possible afterwards
00080         if exception is not None:
00081             self._remote_container.load_completed(False, False)
00082         super(PluginHandlerXEmbedClient, self)._emit_load_completed(exception)
00083         # signal successful loading after emitting signal, for better message order
00084         if exception is None:
00085             self._remote_container.load_completed(True, self._plugin_has_configuration)
00086 
00087     def shutdown_plugin(self, callback):
00088         # this method should never be called for embedded clients
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         # this method should never be called for embedded clients
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         # this method should never be called for embedded clients
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     # pointer to QWidget must be used for PySide to work (at least with 1.0.1)
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         # close embed widget when container is closed
00141         # TODO necessary?
00142         #embed_widget.containerClosed.connect(embed_widget.close)
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         # trigger to update initial window icon and title
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         # serialize icon base64-encoded string
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     # pointer to QWidget must be used for PySide to work (at least with 1.0.1)
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         # do not delete the widget, only the embed widget
00177         widget.setParent(None)
00178         embed_widget.deleteLater()
00179         # triggering close after last widget and toolbar is closed is handled by the container
00180 
00181     # pointer to QToolBar must be used for PySide to work (at least with 1.0.1)
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         # close embed widget when container is closed
00194         # TODO necessary?
00195         #embed_widget.containerClosed.connect(embed_widget.close)
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     # pointer to QToolBar must be used for PySide to work (at least with 1.0.1)
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         # do not delete the toolbar, only the embed widget
00220         toolbar.setParent(None)
00221         embed_widget.deleteLater()
00222         # triggering close after last widget and toolbar is closed is handled by the container
00223 
00224     def _emit_close_plugin(self):
00225         self._remote_container.close_plugin()


qt_gui
Author(s): Dirk Thomas
autogenerated on Fri Aug 28 2015 12:15:40