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