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


rqt_bag
Author(s): Dirk Thomas , Aaron Blasdel , Austin Hendrix , Tim Field
autogenerated on Fri Feb 19 2021 03:14:14