dynreconf_client_widget.py
Go to the documentation of this file.
1 # Software License Agreement (BSD License)
2 #
3 # Copyright (c) 2012, Willow Garage, Inc.
4 # All rights reserved.
5 #
6 # Redistribution and use in source and binary forms, with or without
7 # modification, are permitted provided that the following conditions
8 # are met:
9 #
10 # * Redistributions of source code must retain the above copyright
11 # notice, this list of conditions and the following disclaimer.
12 # * Redistributions in binary form must reproduce the above
13 # copyright notice, this list of conditions and the following
14 # disclaimer in the documentation and/or other materials provided
15 # with the distribution.
16 # * Neither the name of Willow Garage, Inc. nor the names of its
17 # contributors may be used to endorse or promote products derived
18 # from this software without specific prior written permission.
19 #
20 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 # POSSIBILITY OF SUCH DAMAGE.
32 #
33 # Author: Isaac Saito, Ze'ev Klapow
34 
35 from dynamic_reconfigure import (DynamicReconfigureCallbackException,
36  DynamicReconfigureParameterException)
37 
38 from python_qt_binding.QtCore import QMargins
39 from python_qt_binding.QtGui import QIcon
40 from python_qt_binding.QtWidgets import (QFileDialog, QHBoxLayout,
41  QPushButton, QWidget)
42 
43 from rospy.service import ServiceException
44 
45 import yaml
46 
47 from . import logging
48 from .param_editors import EditorWidget
49 from .param_groups import find_cfg, GroupWidget
50 from .param_updater import ParamUpdater
51 
52 
53 class DynreconfClientWidget(GroupWidget):
54  """
55  A wrapper of dynamic_reconfigure.client instance.
56 
57  Represents a widget where users can view and modify ROS params.
58  """
59 
60  def __init__(self, reconf, node_name):
61  """
62  :type reconf: dynamic_reconfigure.client
63  :type node_name: str
64  """
65  group_desc = reconf.get_group_descriptions()
66  logging.debug('DynreconfClientWidget.group_desc=%s', group_desc)
67  super(DynreconfClientWidget, self).__init__(ParamUpdater(reconf),
68  group_desc, node_name)
69 
70  # Save and load buttons
71  self.button_widget = QWidget(self)
72  self.button_header = QHBoxLayout(self.button_widget)
73  self.button_header.setContentsMargins(QMargins(0, 0, 0, 0))
74 
75  self.load_button = QPushButton()
76  self.save_button = QPushButton()
77 
78  self.load_button.setIcon(QIcon.fromTheme('document-open'))
79  self.save_button.setIcon(QIcon.fromTheme('document-save'))
80 
81  self.load_button.clicked[bool].connect(self._handle_load_clicked)
82  self.save_button.clicked[bool].connect(self._handle_save_clicked)
83 
84  self.button_header.addWidget(self.save_button)
85  self.button_header.addWidget(self.load_button)
86 
87  self.setMinimumWidth(150)
88 
89  self.reconf = reconf
90  self.updater.start()
91  self.reconf.config_callback = self.config_callback
92  self._node_grn = node_name
93 
94  def get_node_grn(self):
95  return self._node_grn
96 
97  def config_callback(self, config):
98 
99  # TODO: Think about replacing callback architecture with signals.
100 
101  if config:
102  # TODO: should use config.keys but this method doesnt exist
103 
104  names = [name for name, v in config.items()]
105  # v isn't used but necessary to get key and put it into dict.
106  # logging.debug('config_callback name={} v={}'.format(name, v))
107 
108  for widget in self.editor_widgets:
109  if isinstance(widget, EditorWidget):
110  if widget.param_name in names:
111  logging.debug('EDITOR widget.param_name=%s',
112  widget.param_name)
113  widget.update_value(config[widget.param_name])
114  elif isinstance(widget, GroupWidget):
115  cfg = find_cfg(config, widget.param_name)
116  logging.debug('GROUP widget.param_name=%s',
117  widget.param_name)
118  widget.update_group(cfg)
119 
121  filename = QFileDialog.getOpenFileName(
122  self, self.tr('Load from File'), '.',
123  self.tr('YAML file {.yaml} (*.yaml)'))
124  if filename[0] != '':
125  self.load_param(filename[0])
126 
128  filename = QFileDialog.getSaveFileName(
129  self, self.tr('Save parameters to file...'), '.',
130  self.tr('YAML files {.yaml} (*.yaml)'))
131  if filename[0] != '':
132  self.save_param(filename[0])
133 
134  def save_param(self, filename):
135  configuration = self.reconf.get_configuration()
136  if configuration is not None:
137  with open(filename, 'w') as f:
138  yaml.dump(configuration, f)
139 
140  def load_param(self, filename):
141  with open(filename, 'r') as f:
142  configuration = {}
143  for doc in yaml.load_all(f.read()):
144  configuration.update(doc)
145 
146  try:
147  self.reconf.update_configuration(configuration)
148  except ServiceException as e:
149  logging.warn(
150  "Call for reconfiguration wasn't successful because: %s",
151  e.message
152  )
153  except DynamicReconfigureParameterException as e:
154  logging.warn(
155  "Reconfiguration wasn't successful because: %s",
156  e.message
157  )
158  except DynamicReconfigureCallbackException as e:
159  logging.warn(
160  "Reconfiguration wasn't successful because: %s",
161  e.message
162  )
163 
164  def close(self):
165  self.reconf.close()
166  self.updater.stop()
167 
168  for w in self.editor_widgets:
169  w.close()
170 
171  self.deleteLater()
172 
173  def filter_param(self, filter_key):
174  # TODO impl
175  pass
def find_cfg(config, name)
Definition: param_groups.py:60


rqt_reconfigure
Author(s): Isaac Saito, Ze'ev Klapow
autogenerated on Wed Jul 10 2019 04:02:40