def dasherr(msg, obj, title='Error'): """ Logs a message with ``rospy.logerr`` and displays a ``QMessageBox`` to the user :param msg: Message to display. :type msg: str :param obj: Parent object for the ``QMessageBox`` :type obj: QObject :param title: An optional title for the `QMessageBox`` :type title: str """ rospy.logerr(msg) box = QMessageBox() box.setText(msg) box.setWindowTitle(title) box.show() obj._message_box = box
class Switcher(QObject): # PySide signals are always defined as class attributes (GPL Pyqt4 Signals use pyqtSignal) signal_master_changed_state = Signal(bool) def __init__(self, rqt_plugin_name): super(Switcher, self).__init__() self._rqt_plugin_name = rqt_plugin_name self._rqt_subprocess = None self._no_ros_master_dialog = QMessageBox( QMessageBox.Warning, self.tr(self._rqt_plugin_name), self.tr("Waiting for the ROS Master to become available.")) self._no_ros_master_abort_button = self._no_ros_master_dialog.addButton( QMessageBox.Abort) self._no_ros_master_abort_button.clicked.connect(self.shutdown) self.signal_master_changed_state.connect(self.switch_state, type=Qt.QueuedConnection) self._ros_master_monitor = RosMasterMonitor( period=1, callback_function=self._master_changed_state) self._rqt_subprocess_shutdown_by_us = False @Slot(bool) def switch_state(self, new_master_found): ''' :param bool new_master_found: true when a new master is detected, false when a master has disappeared. ''' if new_master_found: self._no_ros_master_dialog.hide() self._launch_rocon_remocon() else: self._no_ros_master_dialog.show() self._no_ros_master_dialog.raise_() if self._rqt_subprocess is not None: self._rqt_subprocess_shutdown_by_us = True self._rqt_subprocess.send_signal(signal.SIGINT) # self._rqt_subprocess.terminate() # this is SIGTERM self._rqt_subprocess = None def shutdown(self): ''' Shutdowns from external signals or the abort button while waiting for a master. ''' print("Shutting down the ros master monitor") self._ros_master_monitor.shutdown() if self._rqt_subprocess is not None: print("Terminating subprocess") self._rqt_subprocess.send_signal(signal.SIGINT) # self._rqt_subprocess.terminate() # this is SIGTERM self._rqt_subprocess = None QCoreApplication.instance().quit() def _rqt_shutdown(self): ''' Shutdown handler coming from the rqt subprocess shutting down. This needs to be handled differently depending on whether it's us shutting it down because a ros master shut down (in which case we need to stay alive) or otherwise. ''' if not self._rqt_subprocess_shutdown_by_us: self._ros_master_monitor.shutdown() QCoreApplication.instance().quit() else: self._rqt_subprocess_shutdown_by_us = False def _master_changed_state(self, available): ''' :param bool available: whether the ros master is available or not. ''' self.signal_master_changed_state.emit(available) def _launch_rocon_remocon(self): script = ''' #!/usr/bin/env python import sys from rqt_gui.main import Main main = Main() sys.exit(main.main(sys.argv, standalone='%s')) ''' % self._rqt_plugin_name executable_file = tempfile.NamedTemporaryFile(mode='w+t', delete=False) executable_file.write(script) executable_file.flush() self._rqt_subprocess = rocon_python_utils.system.Popen( ['python', executable_file.name], postexec_fn=self._rqt_shutdown)