WUT Velma robot API
subsystem_logs.py
Go to the documentation of this file.
1 # Copyright (c) 2021, Robot Control and Pattern Recognition Group, Warsaw University of Technology
2 # All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are met:
6 # * Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer.
8 # * Redistributions in binary form must reproduce the above copyright
9 # notice, this list of conditions and the following disclaimer in the
10 # documentation and/or other materials provided with the distribution.
11 # * Neither the name of the Warsaw University of Technology nor the
12 # names of its contributors may be used to endorse or promote products
13 # derived from this software without specific prior written permission.
14 #
15 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 # DISCLAIMED. IN NO EVENT SHALL <COPYright HOLDER> BE LIABLE FOR ANY
19 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 
26 from __future__ import division
27 import os
28 import math
29 import subprocess
30 
31 from python_qt_binding import loadUi
32 from python_qt_binding.QtCore import Qt, QTimer, Signal, Slot, QRectF, QPointF, QSize, QRect, QPoint
33 from python_qt_binding.QtWidgets import QWidget, QPushButton, QVBoxLayout, QHBoxLayout, QLabel,\
34  QListWidgetItem, QDialog, QGraphicsView, QGraphicsScene, QGraphicsPathItem, QTableWidgetItem, QHeaderView, QStyle, QCommonStyle
35 from python_qt_binding.QtGui import QColor, QPen, QBrush, QPainterPath, QPolygonF, QTransform,\
36  QPainter, QIcon, QPixmap, QPaintEvent, QPalette, QStandardItem, QStandardItemModel
37 from python_qt_binding.QtSvg import QSvgGenerator
38 import roslib
39 import rospkg
40 import rospy
41 from rospy.exceptions import ROSException
42 
43 import xml.dom.minidom as minidom
44 import tempfile
45 
46 from rqt_topic.topic_info import TopicInfo
47 
48 from subsystem_msgs.srv import *
49 
51  def __init__(self, list_view):
52  self.__list_view = list_view
53  self.__loggers_item_model = QStandardItemModel()
54  self.__list_view.setModel(self.__loggers_item_model)
55  self.__all_logger_names = []
56  self.__loggers_vis_set = set()
57  self.__loggers_item_model.itemChanged.connect(self.__loggersItemChanged)
58 
59  def __loggersItemChanged(self, item):
60  #print('__loggersItemChanged {}'.format(item))
61  #print item.index() # returns PyQt5.QtCore.QModelIndex
62  logger_name = item.text()
63  check_state = item.checkState()
64  if check_state == Qt.Checked:
65  if not logger_name in self.__loggers_vis_set:
66  self.__loggers_vis_set.add( logger_name )
67  print('show logger "{}"'.format(logger_name))
68  elif check_state == Qt.Unchecked:
69  if logger_name in self.__loggers_vis_set:
70  self.__loggers_vis_set.remove( logger_name )
71  print('hide logger "{}"'.format(logger_name))
72  else:
73  raise Exception('Wrong check_state')
74 
75  def updateLoggersList(self, logger_list):
76  assert isinstance(logger_list, list)
77  for logger_name in logger_list:
78  assert isinstance( logger_name, str )
79  if not logger_name in self.__all_logger_names:
80  self.__all_logger_names.append( logger_name )
81  item = QStandardItem( logger_name )
82  check_state = Qt.Unchecked
83  item.setCheckState(check_state)
84  item.setCheckable(True)
85  self.__loggers_item_model.appendRow(item)
86 
87  def getActiveLoggers(self):
88  return self.__loggers_vis_set
89 
90 class LogVis:
91  def __init__(self, list_view):
92  self.__list_view = list_view
93  self.__logs_item_model = QStandardItemModel()
94  self.__list_view.setModel(self.__logs_item_model)
95  #self.__all_logger_names = []
96  #self.__loggers_vis_set = set()
97  #self.__logs_item_model.itemChanged.connect(self.__loggersItemChanged)
98  self.__active_loggers = set()
99  self.__logs = []
100  self.__new_logs = []
101 
102  def setActiveLoggers(self, active_loggers):
103  self.__active_loggers = active_loggers
104 
105  def addLog(self, logger_name, log_str, log_time):
106  self.__logs.append( (logger_name, log_str, log_time) )
107  self.__new_logs.append( (logger_name, log_str, log_time) )
108 
109  def updateView(self):
110  # TODO: sort new items wrt. time
111  for logger_name, log_str, log_time in self.__new_logs:
112  if log_time is None:
113  time_str = '???'
114  else:
115  sec_10000 = log_time.secs%10000
116  nsec4 = int(log_time.nsecs/100000)
117  time_str = '{}.{:04d}'.format(sec_10000, nsec4)
118 
119  item = QStandardItem( '{}: {}: {}'.format(time_str, logger_name, log_str) )
120  self.__logs_item_model.insertRow(0, item)
121  #removeRows
122  self.__new_logs = []
123 
124 class LogsDialog(QDialog):
125 
126  @Slot()
127  def closeClick(self):
128  self.close()
129 
130  # TODO: remove:
131  @Slot()
132  def updateClick(self):
133  print 'do nothing'
134  #self.updateLoggersList()
135 
136  def __init__(self, subsystem_name, parent=None):
137  super(LogsDialog, self).__init__(parent)
138 
139  self.parent = parent
140 
141  self.setWindowFlags(Qt.Window)
142 
143  rp = rospkg.RosPack()
144  ui_file = os.path.join(rp.get_path('rqt_agent'), 'resource', 'SubsystemLogs.ui')
145  loadUi(ui_file, self)
146 
147  self.setWindowTitle(subsystem_name + " - state history")
148 
149  self.pushButton_close.clicked.connect(self.closeClick)
150 
151  self.pushButton_update.clicked.connect(self.updateClick)
152 
153  self.logger_selector = LoggerSelector(self.listView)
154  self.logs_vis = LogVis(self.listViewLogs)
155 
156  def parseLogItem(self, log_item):
157  pos = log_item.rfind('Time(')
158  if pos < 0:
159  return log_item, None
160  # else
161  log_str = log_item[0:pos]
162  time_str = log_item[pos+5:-1]
163  fields = time_str.split(';')
164  if len(fields) < 2:
165  return log_item, None
166 
167  try:
168  sec = int(fields[0])
169  nsec = int(fields[1])
170  except:
171  return log_item, None
172  return log_str, rospy.Time(sec, nsec)
173 
174  def update(self, logs):
175  assert isinstance(logs, dict)
176  self.logger_selector.updateLoggersList( logs.keys() )
177  active_loggers = self.logger_selector.getActiveLoggers()
178  self.logs_vis.setActiveLoggers( active_loggers )
179 
180  for logger_name, log_list in logs.iteritems():
181  for log_item in log_list:
182  log_str, log_time = self.parseLogItem(log_item)
183  self.logs_vis.addLog( logger_name, log_str, log_time )
184  #if logger_name in active_loggers:
185 
186  self.logs_vis.updateView()
def setActiveLoggers(self, active_loggers)
def __init__(self, list_view)
def __init__(self, subsystem_name, parent=None)
def addLog(self, logger_name, log_str, log_time)
def updateLoggersList(self, logger_list)