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


rqt_bag
Author(s): Aaron Blasdel, Tim Field
autogenerated on Fri Jun 7 2019 22:05:54