messages_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 import os
34 
35 from python_qt_binding import loadUi
36 from python_qt_binding.QtCore import Qt
37 from python_qt_binding.QtGui import QIcon
38 from python_qt_binding.QtWidgets import (QAction, QMenu, QMessageBox,
39  QTreeView, QWidget)
40 import roslib
41 import rosmsg
42 import rospkg
43 import rospy
44 
45 
46 from .messages_tree_view import MessagesTreeView
47 from rqt_py_common import rosaction
48 from rqt_console.text_browse_dialog import TextBrowseDialog
49 
50 
51 class MessagesWidget(QWidget):
52 
53  """
54  This class is intended to be able to handle msg, srv & action (actionlib).
55  The name of the class is kept to use message, by following the habit of
56  rosmsg (a script that can handle both msg & srv).
57  """
58 
59  def __init__(self, mode=rosmsg.MODE_MSG,
60  pkg_name='rqt_msg',
61  ui_filename='messages.ui'):
62  """
63  :param ui_filename: This Qt-based .ui file must have elements that are
64  referred from this class. Otherwise unexpected
65  errors are likely to happen. Best way to avoid that
66  situation when you want to give your own .ui file
67  is to implement all Qt components in
68  rqt_msg/resource/message.ui file.
69  """
70 
71  super(MessagesWidget, self).__init__()
72  self._rospack = rospkg.RosPack()
73  ui_file = os.path.join(self._rospack.get_path(pkg_name), 'resource', ui_filename)
74  loadUi(ui_file, self, {'MessagesTreeView': MessagesTreeView})
75  self.setObjectName(ui_filename)
76  self._mode = mode
77 
78  self._add_button.setIcon(QIcon.fromTheme('list-add'))
79  self._add_button.clicked.connect(self._add_message)
80  self._refresh_packages(mode)
81  self._refresh_msgs(self._package_combo.itemText(0))
82  self._package_combo.currentIndexChanged[str].connect(self._refresh_msgs)
83  self._messages_tree.mousePressEvent = self._handle_mouse_press
84 
85  self._browsers = []
86 
87  def _refresh_packages(self, mode=rosmsg.MODE_MSG):
88  if (self._mode == rosmsg.MODE_MSG) or self._mode == rosmsg.MODE_SRV:
89  packages = sorted([pkg_tuple[0] for pkg_tuple in
90  rosmsg.iterate_packages(self._rospack, self._mode)])
91  elif self._mode == rosaction.MODE_ACTION:
92  packages = sorted([pkg_tuple[0]
93  for pkg_tuple in rosaction.iterate_packages(
94  self._rospack, self._mode)])
95  self._package_list = packages
96  rospy.logdebug('pkgs={}'.format(self._package_list))
97  self._package_combo.clear()
98  self._package_combo.addItems(self._package_list)
99  self._package_combo.setCurrentIndex(0)
100 
101  def _refresh_msgs(self, package=None):
102  if package is None or len(package) == 0:
103  return
104  self._msgs = []
105  if (self._mode == rosmsg.MODE_MSG or
106  self._mode == rosaction.MODE_ACTION):
107  msg_list = rosmsg.list_msgs(package)
108  elif self._mode == rosmsg.MODE_SRV:
109  msg_list = rosmsg.list_srvs(package)
110 
111  rospy.logdebug(
112  '_refresh_msgs package={} msg_list={}'.format(package, msg_list))
113  for msg in msg_list:
114  if (self._mode == rosmsg.MODE_MSG or
115  self._mode == rosaction.MODE_ACTION):
116  msg_class = roslib.message.get_message_class(msg)
117  elif self._mode == rosmsg.MODE_SRV:
118  msg_class = roslib.message.get_service_class(msg)
119 
120  rospy.logdebug('_refresh_msgs msg_class={}'.format(msg_class))
121 
122  if msg_class is not None:
123  self._msgs.append(msg)
124 
125  self._msgs = [x.split('/')[1] for x in self._msgs]
126 
127  self._msgs_combo.clear()
128  self._msgs_combo.addItems(self._msgs)
129 
130  def _add_message(self):
131  if self._msgs_combo.count() == 0:
132  return
133  msg = (self._package_combo.currentText() +
134  '/' + self._msgs_combo.currentText())
135 
136  rospy.logdebug('_add_message msg={}'.format(msg))
137 
138  if (self._mode == rosmsg.MODE_MSG or
139  self._mode == rosaction.MODE_ACTION):
140  msg_class = roslib.message.get_message_class(msg)()
141  if self._mode == rosmsg.MODE_MSG:
142  text_tree_root = 'Msg Root'
143  elif self._mode == rosaction.MODE_ACTION:
144  text_tree_root = 'Action Root'
145  self._messages_tree.model().add_message(msg_class,
146  self.tr(text_tree_root), msg, msg)
147 
148  elif self._mode == rosmsg.MODE_SRV:
149  msg_class = roslib.message.get_service_class(msg)()
150  self._messages_tree.model().add_message(msg_class._request_class,
151  self.tr('Service Request'),
152  msg, msg)
153  self._messages_tree.model().add_message(msg_class._response_class,
154  self.tr('Service Response'),
155  msg, msg)
156  self._messages_tree._recursive_set_editable(
157  self._messages_tree.model().invisibleRootItem(), False)
158 
159  def _handle_mouse_press(self, event,
160  old_pressEvent=QTreeView.mousePressEvent):
161  if (event.buttons() & Qt.RightButton and
162  event.modifiers() == Qt.NoModifier):
163  self._rightclick_menu(event)
164  event.accept()
165  return old_pressEvent(self._messages_tree, event)
166 
167  def _rightclick_menu(self, event):
168  """
169  :type event: QEvent
170  """
171 
172  # QTreeview.selectedIndexes() returns 0 when no node is selected.
173  # This can happen when after booting no left-click has been made yet
174  # (ie. looks like right-click doesn't count). These lines are the
175  # workaround for that problem.
176  selected = self._messages_tree.selectedIndexes()
177  if len(selected) == 0:
178  return
179 
180  menu = QMenu()
181  text_action = QAction(self.tr('View Text'), menu)
182  menu.addAction(text_action)
183  raw_action = QAction(self.tr('View Raw'), menu)
184  menu.addAction(raw_action)
185  remove_action = QAction(self.tr('Remove message'), menu)
186  menu.addAction(remove_action)
187 
188  action = menu.exec_(event.globalPos())
189 
190  if action == raw_action or action == text_action:
191  rospy.logdebug('_rightclick_menu selected={}'.format(selected))
192  selected_type = selected[1].data()
193 
194  if selected_type[-2:] == '[]':
195  selected_type = selected_type[:-2]
196  browsetext = None
197  try:
198  if (self._mode == rosmsg.MODE_MSG or
199  self._mode == rosaction.MODE_ACTION):
200  browsetext = rosmsg.get_msg_text(selected_type,
201  action == raw_action)
202  elif self._mode == rosmsg.MODE_SRV:
203  browsetext = rosmsg.get_srv_text(selected_type,
204  action == raw_action)
205 
206  else:
207  raise
208  except rosmsg.ROSMsgException as e:
209  QMessageBox.warning(self, self.tr('Warning'),
210  self.tr('The selected item component ' +
211  'does not have text to view.'))
212  if browsetext is not None:
213  self._browsers.append(TextBrowseDialog(browsetext,
214  self._rospack))
215  self._browsers[-1].show()
216 
217  if action == remove_action:
218  self._messages_tree.model().removeRow(selected[0].row())
219 
221  for browser in self._browsers:
222  browser.close()
def _handle_mouse_press(self, event, old_pressEvent=QTreeView.mousePressEvent)
def _refresh_packages(self, mode=rosmsg.MODE_MSG)
def __init__(self, mode=rosmsg.MODE_MSG, pkg_name='rqt_msg', ui_filename='messages.ui')


rqt_msg
Author(s): Aaron Blasdel, Dirk Thomas
autogenerated on Fri Mar 3 2023 03:49:53