raw_view.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 Defines a raw view: a TopicMessageView that displays the message contents in a tree.
34 """
35 import rospy
36 import array
37 import codecs
38 import math
39 
40 from python_qt_binding.QtCore import Qt
41 from python_qt_binding.QtWidgets import QApplication, QAbstractItemView, QSizePolicy, QTreeWidget, QTreeWidgetItem, QWidget
42 from .topic_message_view import TopicMessageView
43 
44 # compatibility fix for python2/3
45 try:
46  long
47  bytes_to_str = str
48 except NameError:
49  long = int
50  def bytes_to_str(x):
51  return codecs.utf_8_decode(str(x).encode(), 'ignore')[0]
52 
53 
55  name = 'Raw'
56  """
57  Plugin to view a message in a treeview window
58  The message is loaded into a custum treewidget
59  """
60 
61  def __init__(self, timeline, parent, topic):
62  """
63  :param timeline: timeline data object, ''BagTimeline''
64  :param parent: widget that will be added to the ros_gui context, ''QWidget''
65  """
66  super(RawView, self).__init__(timeline, parent, topic)
67  self.message_tree = MessageTree(parent)
68 
69  # This will automatically resize the message_tree to the windowsize
70  parent.layout().addWidget(self.message_tree)
71 
72  def message_viewed(self, bag, msg_details):
73  super(RawView, self).message_viewed(bag, msg_details)
74  _, msg, t = msg_details # topic, msg, t = msg_details
75  if t is None:
76  self.message_cleared()
77  else:
78  self.message_tree.set_message(msg)
79 
80  def message_cleared(self):
81  TopicMessageView.message_cleared(self)
82  self.message_tree.set_message(None)
83 
84 
85 class MessageTree(QTreeWidget):
86 
87  def __init__(self, parent):
88  super(MessageTree, self).__init__(parent)
89  self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
90  self.setHeaderHidden(False)
91  self.setHeaderLabel('')
92  self.setSelectionMode(QAbstractItemView.ExtendedSelection)
93  self._msg = None
94 
95  self._expanded_paths = None
97 
98  @property
99  def msg(self):
100  return self._msg
101 
102  def set_message(self, msg):
103  """
104  Clears the tree view and displays the new message
105  :param msg: message object to display in the treeview, ''msg''
106  """
107  # Remember whether items were expanded or not before deleting
108  if self._msg:
109  for item in self.get_all_items():
110  path = self.get_item_path(item)
111  if item.isExpanded():
112  self._expanded_paths.add(path)
113  elif path in self._expanded_paths:
114  self._expanded_paths.remove(path)
115  self.clear()
116  if msg:
117  self.setHeaderLabel(msg._type)
118 
119  # Populate the tree
120  self._add_msg_object(None, '', '', msg, msg._type)
121 
122  if self._expanded_paths is None:
123  self._expanded_paths = set()
124  else:
125  # Expand those that were previously expanded, and collapse any paths that
126  # we've seen for the first time
127  for item in self.get_all_items():
128  path = self.get_item_path(item)
129  if path in self._expanded_paths:
130  item.setExpanded(True)
131  else:
132  item.setExpanded(False)
133  self._msg = msg
134  QWidget.update(self)
135 
136  # Keyboard handler
137  def on_key_press(self, event):
138  if event.modifiers() & Qt.ControlModifier:
139  key = event.key()
140  if key == ord('C') or key == ord('c'):
141  # Ctrl-C: copy text from selected items to clipboard
143  event.accept()
144  elif key == ord('A') or key == ord('a'):
145  # Ctrl-A: expand the tree and select all items
146  self.expandAll()
147  self.selectAll()
148 
150  # Get tab indented text for all selected items
151  def get_distance(item, ancestor, distance=0):
152  parent = item.parent()
153  if parent == None:
154  return distance
155  else:
156  return get_distance(parent, ancestor, distance + 1)
157  text = ''
158  for i in self.get_all_items():
159  if i in self.selectedItems():
160  text += ('\t' * (get_distance(i, None))) + i.text(0) + '\n'
161  # Copy the text to the clipboard
162  clipboard = QApplication.clipboard()
163  clipboard.setText(text)
164 
165  def get_item_path(self, item):
166  return item.data(0, Qt.UserRole)[0].replace(' ', '') # remove spaces that may get introduced in indexing, e.g. [ 3] is [3]
167 
168  def get_all_items(self):
169  items = []
170  try:
171  root = self.invisibleRootItem()
172  self.traverse(root, items.append)
173  except Exception:
174  # TODO: very large messages can cause a stack overflow due to recursion
175  pass
176  return items
177 
178  def traverse(self, root, function):
179  for i in range(root.childCount()):
180  child = root.child(i)
181  function(child)
182  self.traverse(child, function)
183 
184  def _add_msg_object(self, parent, path, name, obj, obj_type):
185  label = name
186 
187  if hasattr(obj, '__slots__'):
188  subobjs = [(slot, getattr(obj, slot)) for slot in obj.__slots__]
189  elif type(obj) in [list, tuple, array.array]:
190  len_obj = len(obj)
191  if len_obj == 0:
192  subobjs = []
193  else:
194  w = int(math.ceil(math.log10(len_obj)))
195  subobjs = [('[%*d]' % (w, i), subobj) for (i, subobj) in enumerate(obj)]
196  else:
197  subobjs = []
198 
199  if type(obj) in [int, long, float]:
200  if type(obj) == float:
201  obj_repr = '%.6f' % obj
202  else:
203  obj_repr = str(obj)
204 
205  if obj_repr[0] == '-':
206  label += ': %s' % obj_repr
207  else:
208  label += ': %s' % obj_repr
209 
210  elif type(obj) in [str, bool, int, long, float, complex, rospy.Time]:
211  # Ignore any binary data
212  obj_repr = bytes_to_str(obj)
213 
214  # Truncate long representations
215  if len(obj_repr) >= 50:
216  obj_repr = obj_repr[:50] + '...'
217 
218  label += ': ' + obj_repr
219  item = QTreeWidgetItem([label])
220  if name == '':
221  pass
222  elif path.find('.') == -1 and path.find('[') == -1:
223  self.addTopLevelItem(item)
224  else:
225  parent.addChild(item)
226  item.setData(0, Qt.UserRole, (path, obj_type))
227 
228  for subobj_name, subobj in subobjs:
229  if subobj is None:
230  continue
231 
232  if path == '':
233  subpath = subobj_name # root field
234  elif subobj_name.startswith('['):
235  subpath = '%s%s' % (path, subobj_name) # list, dict, or tuple
236  else:
237  subpath = '%s.%s' % (path, subobj_name) # attribute (prefix with '.')
238 
239  if hasattr(subobj, '_type'):
240  subobj_type = subobj._type
241  else:
242  subobj_type = type(subobj).__name__
243 
244  self._add_msg_object(item, subpath, subobj_name, subobj, subobj_type)
rqt_bag.plugins.raw_view.RawView.message_viewed
def message_viewed(self, bag, msg_details)
Definition: raw_view.py:72
rqt_bag.plugins.raw_view.MessageTree._add_msg_object
def _add_msg_object(self, parent, path, name, obj, obj_type)
Definition: raw_view.py:184
rqt_bag.plugins.raw_view.MessageTree.keyPressEvent
keyPressEvent
Definition: raw_view.py:96
rqt_bag.plugins.message_view.MessageView.message_cleared
def message_cleared(self)
Definition: message_view.py:66
rqt_bag.plugins.raw_view.MessageTree.__init__
def __init__(self, parent)
Definition: raw_view.py:87
rqt_bag.plugins.raw_view.MessageTree._msg
_msg
Definition: raw_view.py:93
rqt_bag.plugins.raw_view.MessageTree.msg
def msg(self)
Definition: raw_view.py:99
rqt_bag.plugins.raw_view.MessageTree.traverse
def traverse(self, root, function)
Definition: raw_view.py:178
rqt_bag.plugins.raw_view.RawView.message_cleared
def message_cleared(self)
Definition: raw_view.py:80
rqt_bag.plugins.raw_view.MessageTree.set_message
def set_message(self, msg)
Definition: raw_view.py:102
rqt_bag.plugins.raw_view.RawView.message_tree
message_tree
Definition: raw_view.py:67
rqt_bag.plugins.topic_message_view.TopicMessageView
Definition: topic_message_view.py:38
rqt_bag.plugins.raw_view.MessageTree.get_item_path
def get_item_path(self, item)
Definition: raw_view.py:165
rqt_bag.plugins.raw_view.MessageTree._expanded_paths
_expanded_paths
Definition: raw_view.py:95
rqt_bag.plugins.raw_view.bytes_to_str
bytes_to_str
Definition: raw_view.py:47
rqt_bag.plugins.raw_view.MessageTree.on_key_press
def on_key_press(self, event)
Definition: raw_view.py:137
rqt_bag.plugins.raw_view.MessageTree._copy_text_to_clipboard
def _copy_text_to_clipboard(self)
Definition: raw_view.py:149
rqt_bag.plugins.raw_view.RawView
Definition: raw_view.py:54
rqt_bag.plugins.raw_view.MessageTree
Definition: raw_view.py:85
rqt_bag.plugins.raw_view.RawView.__init__
def __init__(self, timeline, parent, topic)
Definition: raw_view.py:61
rqt_bag.plugins.raw_view.MessageTree.get_all_items
def get_all_items(self)
Definition: raw_view.py:168


rqt_bag
Author(s): Dirk Thomas , Aaron Blasdel , Austin Hendrix , Tim Field
autogenerated on Fri May 2 2025 02:44:16