Go to the documentation of this file.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
00032
00033
00034
00035 import rospy
00036
00037 from python_qt_binding.QtCore import QMargins
00038 from python_qt_binding.QtGui import QIcon
00039 from python_qt_binding.QtWidgets import (QFileDialog, QHBoxLayout,
00040 QPushButton, QWidget)
00041 from .param_editors import EditorWidget
00042 from .param_groups import GroupWidget, find_cfg
00043 from .param_updater import ParamUpdater
00044
00045 from dynamic_reconfigure import (DynamicReconfigureParameterException,
00046 DynamicReconfigureCallbackException)
00047 from rospy.service import ServiceException
00048
00049 import yaml
00050
00051
00052 class DynreconfClientWidget(GroupWidget):
00053 """
00054 A wrapper of dynamic_reconfigure.client instance.
00055 Represents a widget where users can view and modify ROS params.
00056 """
00057
00058 def __init__(self, reconf, node_name):
00059 """
00060 :type reconf: dynamic_reconfigure.client
00061 :type node_name: str
00062 """
00063
00064 group_desc = reconf.get_group_descriptions()
00065 rospy.logdebug('DynreconfClientWidget.group_desc=%s', group_desc)
00066 super(DynreconfClientWidget, self).__init__(ParamUpdater(reconf),
00067 group_desc, node_name)
00068
00069
00070 self.button_widget = QWidget(self)
00071 self.button_header = QHBoxLayout(self.button_widget)
00072 self.button_header.setContentsMargins(QMargins(0, 0, 0, 0))
00073
00074 self.load_button = QPushButton()
00075 self.save_button = QPushButton()
00076
00077 self.load_button.setIcon(QIcon.fromTheme('document-open'))
00078 self.save_button.setIcon(QIcon.fromTheme('document-save'))
00079
00080 self.load_button.clicked[bool].connect(self._handle_load_clicked)
00081 self.save_button.clicked[bool].connect(self._handle_save_clicked)
00082
00083 self.button_header.addWidget(self.save_button)
00084 self.button_header.addWidget(self.load_button)
00085
00086 self.setMinimumWidth(150)
00087
00088 self.reconf = reconf
00089 self.updater.start()
00090 self.reconf.config_callback = self.config_callback
00091 self._node_grn = node_name
00092
00093 def get_node_grn(self):
00094
00095 return self._node_grn
00096
00097 def config_callback(self, config):
00098
00099
00100
00101 if config:
00102
00103
00104 names = [name for name, v in config.items()]
00105
00106 rospy.logdebug('config_callback name={} v={}'.format(name, v))
00107
00108 for widget in self.editor_widgets:
00109 if isinstance(widget, EditorWidget):
00110 if widget.param_name in names:
00111 rospy.logdebug('EDITOR widget.param_name=%s',
00112 widget.param_name)
00113 widget.update_value(config[widget.param_name])
00114 elif isinstance(widget, GroupWidget):
00115 cfg = find_cfg(config, widget.param_name)
00116 rospy.logdebug('GROUP widget.param_name=%s',
00117 widget.param_name)
00118 widget.update_group(cfg)
00119
00120 def _handle_load_clicked(self):
00121 filename = QFileDialog.getOpenFileName(
00122 self, self.tr('Load from File'), '.',
00123 self.tr('YAML file {.yaml} (*.yaml)'))
00124 if filename[0] != '':
00125 self.load_param(filename[0])
00126
00127 def _handle_save_clicked(self):
00128 filename = QFileDialog.getSaveFileName(
00129 self, self.tr('Save parameters to file...'), '.',
00130 self.tr('YAML files {.yaml} (*.yaml)'))
00131 if filename[0] != '':
00132 self.save_param(filename[0])
00133
00134 def save_param(self, filename):
00135 configuration = self.reconf.get_configuration()
00136 if configuration is not None:
00137 with file(filename, 'w') as f:
00138 yaml.dump(configuration, f)
00139
00140 def load_param(self, filename):
00141 with file(filename, 'r') as f:
00142 configuration = {}
00143 for doc in yaml.load_all(f.read()):
00144 configuration.update(doc)
00145
00146 try:
00147 self.reconf.update_configuration(configuration)
00148 except ServiceException as e:
00149 rospy.logwarn('Call for reconfiguration wasn\'t successful because: %s', e.message)
00150 except DynamicReconfigureParameterException as e:
00151 rospy.logwarn('Reconfiguration wasn\'t successful because: %s', e.message)
00152 except DynamicReconfigureCallbackException as e:
00153 rospy.logwarn('Reconfiguration wasn\'t successful because: %s', e.message)
00154
00155 def close(self):
00156 self.reconf.close()
00157 self.updater.stop()
00158
00159 for w in self.editor_widgets:
00160 w.close()
00161
00162 self.deleteLater()
00163
00164 def filter_param(self, filter_key):
00165
00166 pass