33 from __future__
import division
39 from python_qt_binding
import loadUi
40 from python_qt_binding.QtCore
import Qt, Slot, qWarning
41 from python_qt_binding.QtGui
import QIcon
42 from python_qt_binding.QtWidgets
import QMenu, QTreeWidgetItem, QWidget
53 column_names = [
'service',
'type',
'expression']
56 super(ServiceCallerWidget, self).
__init__()
57 self.setObjectName(
'ServiceCallerWidget')
61 for module
in (math, random, time):
62 self._eval_locals.update(module.__dict__)
68 ui_file = os.path.join(rp.get_path(
'rqt_service_caller'),
'resource',
'ServiceCaller.ui')
69 loadUi(ui_file, self, {
'ExtendedComboBox': ExtendedComboBox})
70 self.refresh_services_button.setIcon(QIcon.fromTheme(
'view-refresh'))
71 self.call_service_button.setIcon(QIcon.fromTheme(
'call-start'))
83 instance_settings.set_value(
'current_service_name', self.
_service_info[
'service_name'])
84 instance_settings.set_value(
'splitter_orientation', self.splitter.orientation())
87 current_service_name = instance_settings.value(
'current_service_name',
None)
88 if current_service_name:
89 current_service_index = self.service_combo_box.findData(
90 current_service_name, Qt.DisplayRole)
91 if current_service_index != -1:
92 self.service_combo_box.setCurrentIndex(current_service_index)
94 if int(instance_settings.value(
'splitter_orientation', Qt.Vertical)) == int(Qt.Vertical):
95 self.splitter.setOrientation(Qt.Vertical)
97 self.splitter.setOrientation(Qt.Horizontal)
101 Qt.Vertical
if self.splitter.orientation() == Qt.Horizontal
else Qt.Horizontal
102 self.splitter.setOrientation(new_orientation)
106 service_names = rosservice.get_service_list()
108 for service_name
in service_names:
110 self.
_services[service_name] = rosservice.get_service_class_by_name(service_name)
114 except (rosservice.ROSServiceException, rosservice.ROSServiceIOException)
as e:
116 'ServiceCaller.on_refresh_services_button_clicked(): could not get class of service %s:\n%s' %
118 except Exception
as e:
120 'ServiceCaller.on_refresh_services_button_clicked(): failed to load class of service %s:\n%s' %
123 self.service_combo_box.clear()
124 self.service_combo_box.addItems(sorted(self._services.keys()))
128 self.request_tree_widget.clear()
129 self.response_tree_widget.clear()
130 service_name = str(service_name)
143 request_class = self.
_service_info[
'service_class']._request_class
145 None, service_name, request_class._type, request_class())
148 self.request_tree_widget.addTopLevelItem(top_level_item)
151 self.request_tree_widget.expandAll()
152 for i
in range(self.request_tree_widget.columnCount()):
153 self.request_tree_widget.resizeColumnToContents(i)
156 item = QTreeWidgetItem(parent)
158 item.setFlags(item.flags() | Qt.ItemIsEditable)
160 item.setFlags(item.flags() & (~Qt.ItemIsEditable))
164 topic_text = topic_name
166 topic_text = topic_name.split(
'/')[-1]
171 item.setData(0, Qt.UserRole, topic_name)
173 if hasattr(message,
'__slots__')
and hasattr(message,
'_slot_types'):
174 for slot_name, type_name
in zip(message.__slots__, message._slot_types):
176 type_name, getattr(message, slot_name), is_editable)
178 elif type(message)
in (list, tuple)
and (len(message) > 0)
and hasattr(message[0],
'__slots__'):
179 type_name = type_name.split(
'[', 1)[0]
180 for index, slot
in enumerate(message):
182 item, topic_name +
'[%d]' % index, type_name, slot, is_editable)
185 item.setText(self.
_column_index[
'expression'], repr(message))
189 @Slot(
'QTreeWidgetItem*', int)
192 new_value = str(item.text(column))
197 if column_name ==
'expression':
198 topic_name = str(item.data(0, Qt.UserRole))
205 if not hasattr(message,
'__slots__'):
207 for slot_name
in message.__slots__:
208 slot_key = topic_name +
'/' + slot_name
211 if slot_key
not in expressions:
215 expression = expressions[slot_key]
216 if len(expression) == 0:
220 slot = getattr(message, slot_name)
221 if hasattr(slot,
'_type'):
222 slot_type = slot._type
224 slot_type = type(slot)
228 if value
is not None:
229 setattr(message, slot_name, value)
232 successful_eval =
True 233 successful_conversion =
True 241 successful_eval =
False 245 value = slot_type(value)
247 successful_conversion =
False 249 if successful_conversion:
251 elif successful_eval:
253 'ServiceCaller.fill_message_slots(): can not convert expression to slot type: %s -> %s' %
254 (type(value), slot_type))
256 qWarning(
'ServiceCaller.fill_message_slots(): failed to evaluate expression: %s' %
263 self.response_tree_widget.clear()
265 request = self.
_service_info[
'service_class']._request_class()
270 except rospy.ServiceException
as e:
271 qWarning(
'ServiceCaller.on_call_service_button_clicked(): request:\n%r' % (request))
272 qWarning(
'ServiceCaller.on_call_service_button_clicked(): error calling service "%s":\n%s' %
274 top_level_item = QTreeWidgetItem()
275 top_level_item.setText(self.
_column_index[
'service'],
'ERROR')
276 top_level_item.setText(self.
_column_index[
'type'],
'rospy.ServiceException')
277 top_level_item.setText(self.
_column_index[
'expression'], str(e))
281 None,
'/', response._type, response, is_editable=
False)
283 self.response_tree_widget.addTopLevelItem(top_level_item)
285 self.response_tree_widget.expandAll()
286 for i
in range(self.response_tree_widget.columnCount()):
287 self.response_tree_widget.resizeColumnToContents(i)
292 self.request_tree_widget.itemAt(pos), self.request_tree_widget.mapToGlobal(pos))
297 self.response_tree_widget.itemAt(pos), self.response_tree_widget.mapToGlobal(pos))
305 action_item_expand = menu.addAction(QIcon.fromTheme(
'zoom-in'),
"Expand All Children")
306 action_item_collapse = menu.addAction(QIcon.fromTheme(
'zoom-out'),
"Collapse All Children")
307 action = menu.exec_(global_pos)
310 if action
in (action_item_expand, action_item_collapse):
311 expanded = (action
is action_item_expand)
313 def recursive_set_expanded(item):
314 item.setExpanded(expanded)
315 for index
in range(item.childCount()):
316 recursive_set_expanded(item.child(index))
317 recursive_set_expanded(item)