rock_widget_collection  0.1
StreamAlignerWidget.cpp
Go to the documentation of this file.
1 #include "StreamAlignerWidget.h"
2 #include "aggregator/StreamAlignerStatus.hpp"
3 #include <QStandardItemModel>
4 #include <QTreeView>
5 #include <QStyledItemDelegate>
6 #include <QApplication>
7 #include <QAbstractItemModel>
8 #include <stdexcept>
9 #include <deque>
10 #include <limits>
11 
13  BufferSize = Qt::UserRole + 2,
15 };
16 
18 public:
19  StreamRepresentation(const aggregator::StreamStatus &status)
20  {
21  name = QString::fromStdString(status.name);
22  };
23 
24  void updateData(const aggregator::StreamStatus &status, const base::Time& time)
25  {
26  bufferStatusSize = QVariant::fromValue<int>(status.buffer_size);
27  bufferStatusFill = QVariant::fromValue<int>(status.buffer_fill);
28  droppedFull= QString("%0").arg(status.samples_dropped_buffer_full);
29  droppedLate= QString("%0").arg(status.samples_dropped_late_arriving);
30  droppedOrdering= QString("%0").arg(status.samples_backward_in_time);
31 
32  // make sure the history buffer is of the desired size
33  const size_t avg_size = 30;
34  statusHistory.push_front( std::make_pair( time, status ) );
35  while( statusHistory.size() > (avg_size+1) )
36  statusHistory.pop_back();
37 
38  const size_t intervals[3] = {1,5,30};
39  float avg_rate[3];
40  for( int i=0; i<3; i++ )
41  {
42  float rate = std::numeric_limits<float>::quiet_NaN();
43  const size_t idx = intervals[i];
44  if( statusHistory.size() > idx )
45  {
46  long sample_diff =
47  statusHistory[idx].second.samples_received -
48  statusHistory.front().second.samples_received;
49 
50  base::Time time_diff =
51  statusHistory[idx].first -
52  statusHistory.front().first;
53 
54  rate = (float)sample_diff / time_diff.toSeconds();
55  }
56  avg_rate[i] = rate;
57  }
58 
59  sampleRate = QString("%0/%1/%2")
60  .arg( avg_rate[0], 0, 'f', 1 )
61  .arg( avg_rate[1], 0, 'f', 1 )
62  .arg( avg_rate[2], 0, 'f', 1 );
63  }
64 
65  QVariant data(int col, int role)
66  {
67  if(role == Qt::DisplayRole || col == 1)
68  {
69  switch(col)
70  {
71  case 0:
72  return name;
73  break;
74  case 1:
75  if(role == BufferSize)
76  return bufferStatusSize;
77  if(role == BufferFill)
78  return bufferStatusFill;
79  break;
80  case 2:
81  return droppedFull;
82  break;
83  case 3:
84  return droppedLate;
85  break;
86  case 4:
87  return droppedOrdering;
88  break;
89  case 5:
90  return sampleRate;
91  break;
92  }
93  }
94  return QVariant();
95  }
96 
97  static QVariant headerData(int col, int role)
98  {
99  if(role == Qt::DisplayRole)
100  {
101  switch(col)
102  {
103  case 0:
104  return QString("Name");
105  break;
106  case 1:
107  return QString("BufferStatus");
108  break;
109  case 2:
110  return QString("Dropped Full");
111  break;
112  case 3:
113  return QString("Dropped Late");
114  break;
115  case 4:
116  return QString("Dropped Ordering");
117  break;
118  case 5:
119  return QString("Samples/s Avg.(1/5/30)");
120  break;
121  }
122  }
123  return QVariant();
124  }
125 
126  QVariant name;
129  QVariant droppedFull;
130  QVariant droppedLate;
131  QVariant droppedOrdering;
132  QVariant sampleRate;
133 
134  std::deque<std::pair<base::Time, aggregator::StreamStatus> > statusHistory;
135 };
136 
138 public:
139  TaskRepresentation( const std::string& name )
140  {
141  taskName = QString::fromStdString(name);
142  childCount = 0;
143  }
144 
146  {
147  for(std::vector<StreamRepresentation *>::const_iterator it = streams.begin(); it != streams.end(); it++)
148  {
149  delete *it;
150  }
151  }
152 
153  void updateData(const aggregator::StreamAlignerStatus& status)
154  {
155  if(status.streams.size() != streams.size())
156  streams.resize(status.streams.size(), NULL);
157 
158  int i = 0;
159  childCount = 0;
160  for(std::vector<aggregator::StreamStatus>::const_iterator it = status.streams.begin(); it != status.streams.end(); it++)
161  {
162 
163  if(!streams[i])
164  {
165  streams[i] = new StreamRepresentation(*it);
166  }
167 
168  streams[i]->updateData(*it, status.time);
169  i++;
170  childCount++;
171  }
172  }
173 
174  QVariant data(int col, int role)
175  {
176  if(role == Qt::DisplayRole && col == 0)
177  return taskName;
178 
179  return QVariant();
180  };
181 
182  QVariant taskName;
183 
184  int getStreamCount() const
185  {
186  return childCount;
187  };
188 
189  QVariant data(int row, int col, int role)
190  {
191  if(row >= childCount)
192  {
193  throw std::runtime_error("Tried to access invalid stream");
194  }
195  return streams[row]->data(col, role);
196  }
197 
198 private:
199  int childCount;
200  std::vector<StreamRepresentation *> streams;
201 };
202 
203 class StreamAlignerModel : public QAbstractItemModel
204 {
205 public:
206  explicit StreamAlignerModel(QObject* parent = 0);
208  virtual int columnCount(const QModelIndex& parent = QModelIndex()) const;
209  virtual QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const;
210  virtual QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const;
211  virtual QModelIndex parent(const QModelIndex& child) const;
212  virtual int rowCount(const QModelIndex& parent = QModelIndex()) const;
213  virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
214  void updateData(const aggregator::StreamAlignerStatus& status);
215 private:
216  std::map<std::string, TaskRepresentation *> taskRepMap;
217  std::vector<TaskRepresentation *> taskRep;
218 
219 };
220 
222 {
223  for(std::vector<TaskRepresentation *>::const_iterator it = taskRep.begin(); it != taskRep.end(); it++)
224  {
225  delete *it;
226  }
227  taskRep.clear();
228  taskRepMap.clear();
229 }
230 
231 void StreamAlignerModel::updateData(const aggregator::StreamAlignerStatus& status)
232 {
233  std::string name = status.name;
234  if( name.empty() )
235  name = "<anonymous>";
236 
237  if(!taskRepMap.count(name))
238  {
239  TaskRepresentation *tp = new TaskRepresentation( name );
240  taskRepMap[name] = tp;
241  taskRep.push_back(tp);
242  emit layoutChanged();
243  }
244 
245  taskRepMap[name]->updateData(status);
246 
247  //inform rest of the world that we got new data
248  if(!taskRep.empty())
249  emit dataChanged(createIndex(0,0,0), createIndex(taskRep.size()-1, 5, 0));
250 }
251 
252 StreamAlignerModel::StreamAlignerModel(QObject* parent): QAbstractItemModel(parent)
253 {
254 }
255 
256 QVariant StreamAlignerModel::headerData(int section, Qt::Orientation orientation, int role) const
257 {
258  return StreamRepresentation::headerData(section, role);
259 }
260 
261 int StreamAlignerModel::rowCount(const QModelIndex& parent) const
262 {
263  if(parent.isValid())
264  {
265  //parent is no task rep
266  if(parent.internalId() != 1)
267  return 0;
268 
269  //return stream count of task rep
270  return taskRep[parent.row()]->getStreamCount();
271  }
272 
273  return taskRep.size();
274 }
275 
276 int StreamAlignerModel::columnCount(const QModelIndex& parent) const
277 {
278  return 6;
279 }
280 
281 QVariant StreamAlignerModel::data(const QModelIndex& index, int role) const
282 {
283  if(!index.isValid())
284  return QVariant();
285 
286  //task rep
287  if(index.internalId() == 1)
288  {
289  return taskRep[index.row()]->data(index.column(), role);
290  }
291 
292  //this index points to a stream
293  return taskRep[index.parent().row()]->data(index.row(), index.column(), role);
294 
295  return QVariant();
296 }
297 
298 QModelIndex StreamAlignerModel::index(int row, int column, const QModelIndex& parent) const
299 {
300  if (!hasIndex(row, column, parent))
301  return QModelIndex();
302 
303  if (!parent.isValid())
304  {
305  //index to root node
306  const int taskCount = taskRep.size();
307  if(row >= taskCount)
308  return QModelIndex();
309  return createIndex(row, column, 1);
310  } else {
311  if(parent.internalId() != 1)
312  throw std::runtime_error("Expected id 1 got something else");
313 
314  if(row < taskRep[parent.row()]->getStreamCount())
315  return createIndex(row, column, (void *) taskRep[parent.row()] );
316  }
317 
318  return QModelIndex();
319 }
320 
321 QModelIndex StreamAlignerModel::parent(const QModelIndex& child) const
322 {
323  if(!child.isValid()) {
324  return QModelIndex();
325  }
326 
327  //top level items have no valid parents
328  if(child.internalId() == 1)
329  return QModelIndex();
330 
331  int i = 0;
332  for(std::vector<TaskRepresentation *>::const_iterator it = taskRep.begin(); it != taskRep.end(); it++) {
333  if(*it == child.internalPointer())
334  return createIndex(i, 0, 1);
335  i++;
336  }
337  return QModelIndex();
338 }
339 
340 class StreamAlignerDelegate: public QStyledItemDelegate
341 {
342 public:
343  void paint(QPainter *painter, const QStyleOptionViewItem &option,
344  const QModelIndex &index) const
345  {
346  if (index.column() == 1 && index.data(BufferSize).toInt()) {
347  int bSize = index.data(BufferSize).toInt();
348  int bFill = index.data(BufferFill).toInt();
349 
350  QStyleOptionProgressBar progressBarOption;
351  progressBarOption.rect = option.rect;
352  progressBarOption.minimum = 0;
353  progressBarOption.maximum = bSize;
354  progressBarOption.progress = bFill;
355  progressBarOption.text = QString::number(bFill) + " / " + QString::number(bSize);
356  progressBarOption.textVisible = true;
357 
358  QApplication::style()->drawControl(QStyle::CE_ProgressBar,
359  &progressBarOption, painter);
360  } else
361  QStyledItemDelegate::paint(painter, option, index);
362  }
363 };
364 
365 
366 StreamAlignerWidget::StreamAlignerWidget(QWidget* parent): QTreeView(parent)
367 {
368  model = new StreamAlignerModel;
369 
371  setItemDelegate(delegate);
372  setModel(model);
373  update();
374 }
375 
377 {
378  return QSize(650,250);
379 }
380 
381 void StreamAlignerWidget::updateData(const aggregator::StreamAlignerStatus& status)
382 {
383  StreamAlignerModel *m = dynamic_cast<StreamAlignerModel *>(model);
384  m->updateData(status);
385 }
386 
388 {
389 }
390 
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
StreamRepresentation(const aggregator::StreamStatus &status)
static QVariant headerData(int col, int role)
StreamAlignerModel(QObject *parent=0)
void updateData(const aggregator::StreamAlignerStatus &data)
virtual QModelIndex parent(const QModelIndex &child) const
void updateData(const aggregator::StreamAlignerStatus &status)
virtual QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
void updateData(const aggregator::StreamStatus &status, const base::Time &time)
void updateData(const aggregator::StreamAlignerStatus &status)
QVariant data(int row, int col, int role)
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
QVariant data(int col, int role)
TaskRepresentation(const std::string &name)
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const
virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
QVariant data(int col, int role)
std::deque< std::pair< base::Time, aggregator::StreamStatus > > statusHistory
StreamAlignerWidget(QWidget *parent)