/* Copyright (c) 2015, 2016 Hubert Denkmair This file is part of cangaroo. cangaroo is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. cangaroo is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with cangaroo. If not, see . */ #include "AggregatedTraceViewModel.h" #include #include #include #include AggregatedTraceViewModel::AggregatedTraceViewModel(Backend &backend) : BaseTraceViewModel(backend) { _rootItem = new AggregatedTraceViewItem(0); connect(backend.getTrace(), SIGNAL(beforeAppend(int)), this, SLOT(beforeAppend(int))); connect(backend.getTrace(), SIGNAL(beforeClear()), this, SLOT(beforeClear())); connect(backend.getTrace(), SIGNAL(afterClear()), this, SLOT(afterClear())); connect(&backend, SIGNAL(onSetupChanged()), this, SLOT(onSetupChanged())); } void AggregatedTraceViewModel::createItem(const CanMessage &msg) { AggregatedTraceViewItem *item = new AggregatedTraceViewItem(_rootItem); item->_lastmsg = msg; CanDbMessage *dbmsg = backend()->findDbMessage(msg); if (dbmsg) { for (int i=0; igetSignals().length(); i++) { item->appendChild(new AggregatedTraceViewItem(item)); } } _rootItem->appendChild(item); _map[makeUniqueKey(msg)] = item; } void AggregatedTraceViewModel::updateItem(const CanMessage &msg) { AggregatedTraceViewItem *item = _map.value(makeUniqueKey(msg)); if (item) { item->_prevmsg = item->_lastmsg; item->_lastmsg = msg; } } void AggregatedTraceViewModel::onUpdateModel() { if (!_pendingMessageInserts.isEmpty()) { beginInsertRows(QModelIndex(), _rootItem->childCount(), _rootItem->childCount()+_pendingMessageInserts.size()-1); foreach (CanMessage msg, _pendingMessageInserts) { createItem(msg); } endInsertRows(); _pendingMessageInserts.clear(); } if (!_pendingMessageUpdates.isEmpty()) { foreach (CanMessage msg, _pendingMessageUpdates) { updateItem(msg); } _pendingMessageUpdates.clear(); } if (_rootItem->childCount()>0) { dataChanged(createIndex(0, 0, _rootItem->firstChild()), createIndex(_rootItem->childCount()-1, column_count-1, _rootItem->lastChild())); } } void AggregatedTraceViewModel::onSetupChanged() { beginResetModel(); endResetModel(); } void AggregatedTraceViewModel::beforeAppend(int num_messages) { CanTrace *trace = backend()->getTrace(); int start_id = trace->size(); for (int i=start_id; igetMessage(i); unique_key_t key = makeUniqueKey(*msg); if (_map.contains(key) || _pendingMessageInserts.contains(key)) { _pendingMessageUpdates.append(*msg); } else { _pendingMessageInserts[key] = *msg; } } onUpdateModel(); } void AggregatedTraceViewModel::beforeClear() { beginResetModel(); delete _rootItem; _map.clear(); _rootItem = new AggregatedTraceViewItem(0); } void AggregatedTraceViewModel::afterClear() { endResetModel(); } AggregatedTraceViewModel::unique_key_t AggregatedTraceViewModel::makeUniqueKey(const CanMessage &msg) const { return ((uint64_t)msg.getInterfaceId() << 32) | msg.getRawId(); } double AggregatedTraceViewModel::getTimeDiff(const timeval t1, const timeval t2) const { double diff = t2.tv_sec - t1.tv_sec; diff += ((double)(t2.tv_usec - t1.tv_usec)) / 1000000; return diff; } QModelIndex AggregatedTraceViewModel::index(int row, int column, const QModelIndex &parent) const { if (!hasIndex(row, column, parent)) { return QModelIndex(); } const AggregatedTraceViewItem *parentItem = parent.isValid() ? static_cast(parent.internalPointer()) : _rootItem; const AggregatedTraceViewItem *childItem = parentItem->child(row); if (childItem) { return createIndex(row, column, const_cast(childItem)); } else { return QModelIndex(); } } QModelIndex AggregatedTraceViewModel::parent(const QModelIndex &index) const { if (!index.isValid()) { return QModelIndex(); } AggregatedTraceViewItem *childItem = (AggregatedTraceViewItem*) index.internalPointer(); AggregatedTraceViewItem *parentItem = childItem->parent(); if (parentItem == _rootItem) { return QModelIndex(); } return createIndex(parentItem->row(), 0, parentItem); } int AggregatedTraceViewModel::rowCount(const QModelIndex &parent) const { if (parent.column() > 0) { return 0; } AggregatedTraceViewItem *parentItem; if (parent.isValid()) { parentItem = (AggregatedTraceViewItem*)parent.internalPointer(); } else { parentItem = _rootItem; } return parentItem->childCount(); } QVariant AggregatedTraceViewModel::data_DisplayRole(const QModelIndex &index, int role) const { AggregatedTraceViewItem *item = (AggregatedTraceViewItem *)index.internalPointer(); if (!item) { return QVariant(); } if (item->parent() == _rootItem) { // CanMessage row return data_DisplayRole_Message(index, role, item->_lastmsg, item->_prevmsg); } else { // CanSignal Row return data_DisplayRole_Signal(index, role, item->parent()->_lastmsg); } } QVariant AggregatedTraceViewModel::data_TextColorRole(const QModelIndex &index, int role) const { (void) role; AggregatedTraceViewItem *item = (AggregatedTraceViewItem *)index.internalPointer(); if (!item) { return QVariant(); } if (item->parent() == _rootItem) { // CanMessage row struct timeval now; gettimeofday(&now, 0); int color = getTimeDiff(item->_lastmsg.getTimestamp(), now)*100; if (color>200) { color = 200; } if (color<0) { color = 0; } return QVariant::fromValue(QColor(color, color, color)); } else { // CanSignal Row return data_TextColorRole_Signal(index, role, item->parent()->_lastmsg); } }