First implementation

This commit is contained in:
Yury Shuvakin
2024-07-03 19:11:29 +09:00
parent 25a3a8ac11
commit d708fc3499
153 changed files with 17687 additions and 0 deletions

View File

@@ -0,0 +1,71 @@
/*
Copyright (c) 2015, 2016 Hubert Denkmair <hubert@denkmair.de>
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 <http://www.gnu.org/licenses/>.
*/
#include "AggregatedTraceViewItem.h"
AggregatedTraceViewItem::AggregatedTraceViewItem(AggregatedTraceViewItem *parent)
: _parent(parent)
{
}
AggregatedTraceViewItem::~AggregatedTraceViewItem()
{
qDeleteAll(_children);
}
void AggregatedTraceViewItem::appendChild(AggregatedTraceViewItem *child)
{
_children.append(child);
}
AggregatedTraceViewItem *AggregatedTraceViewItem::child(int row) const
{
return _children.value(row);
}
int AggregatedTraceViewItem::childCount() const
{
return _children.count();
}
int AggregatedTraceViewItem::row() const
{
if (_parent) {
return _parent->_children.indexOf(const_cast<AggregatedTraceViewItem*>(this));
} else {
return 0;
}
}
AggregatedTraceViewItem *AggregatedTraceViewItem::parent() const
{
return _parent;
}
AggregatedTraceViewItem *AggregatedTraceViewItem::firstChild() const
{
return _children.first();
}
AggregatedTraceViewItem *AggregatedTraceViewItem::lastChild() const
{
return _children.last();
}

View File

@@ -0,0 +1,48 @@
/*
Copyright (c) 2015, 2016 Hubert Denkmair <hubert@denkmair.de>
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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <sys/time.h>
#include <core/CanMessage.h>
#include <QList>
class AggregatedTraceViewItem
{
public:
AggregatedTraceViewItem(AggregatedTraceViewItem *parent);
virtual ~AggregatedTraceViewItem();
void appendChild(AggregatedTraceViewItem *child);
AggregatedTraceViewItem *child(int row) const;
int childCount() const;
int row() const;
AggregatedTraceViewItem *parent() const;
AggregatedTraceViewItem *firstChild() const;
AggregatedTraceViewItem *lastChild() const;
CanMessage _lastmsg, _prevmsg;
private:
AggregatedTraceViewItem *_parent;
QList<AggregatedTraceViewItem *> _children;
};

View File

@@ -0,0 +1,220 @@
/*
Copyright (c) 2015, 2016 Hubert Denkmair <hubert@denkmair.de>
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 <http://www.gnu.org/licenses/>.
*/
#include "AggregatedTraceViewModel.h"
#include <QColor>
#include <core/Backend.h>
#include <core/CanTrace.h>
#include <core/CanDbMessage.h>
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; i<dbmsg->getSignals().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; i<start_id + num_messages; i++) {
const CanMessage *msg = trace->getMessage(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<AggregatedTraceViewItem*>(parent.internalPointer()) : _rootItem;
const AggregatedTraceViewItem *childItem = parentItem->child(row);
if (childItem) {
return createIndex(row, column, const_cast<AggregatedTraceViewItem*>(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);
}
}

View File

@@ -0,0 +1,76 @@
/*
Copyright (c) 2015, 2016 Hubert Denkmair <hubert@denkmair.de>
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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QAbstractItemModel>
#include <QMap>
#include <QList>
#include <sys/time.h>
#include "BaseTraceViewModel.h"
#include <core/CanMessage.h>
#include <driver/CanInterface.h>
#include "AggregatedTraceViewItem.h"
class CanTrace;
class AggregatedTraceViewModel : public BaseTraceViewModel
{
Q_OBJECT
public:
typedef uint64_t unique_key_t;
typedef QMap<unique_key_t, AggregatedTraceViewItem*> CanIdMap;
public:
AggregatedTraceViewModel(Backend &backend);
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const;
virtual QModelIndex parent(const QModelIndex &child) const;
virtual int rowCount(const QModelIndex &parent) const;
private:
CanIdMap _map;
AggregatedTraceViewItem *_rootItem;
QList<CanMessage> _pendingMessageUpdates;
QMap<unique_key_t, CanMessage> _pendingMessageInserts;
unique_key_t makeUniqueKey(const CanMessage &msg) const;
void createItem(const CanMessage &msg, AggregatedTraceViewItem *item, unique_key_t key);
double getTimeDiff(const timeval t1, const timeval t2) const;
protected:
virtual QVariant data_DisplayRole(const QModelIndex &index, int role) const;
virtual QVariant data_TextColorRole(const QModelIndex &index, int role) const;
private slots:
void createItem(const CanMessage &msg);
void updateItem(const CanMessage &msg);
void onUpdateModel();
void onSetupChanged();
void beforeAppend(int num_messages);
void beforeClear();
void afterClear();
};

View File

@@ -0,0 +1,271 @@
/*
Copyright (c) 2015, 2016 Hubert Denkmair <hubert@denkmair.de>
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 <http://www.gnu.org/licenses/>.
*/
#include "BaseTraceViewModel.h"
#include <QDateTime>
#include <QColor>
#include <core/Backend.h>
#include <core/CanTrace.h>
#include <core/CanMessage.h>
#include <core/CanDbMessage.h>
BaseTraceViewModel::BaseTraceViewModel(Backend &backend)
{
_backend = &backend;
}
int BaseTraceViewModel::columnCount(const QModelIndex &parent) const
{
(void) parent;
return column_count;
}
QVariant BaseTraceViewModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole) {
if (orientation == Qt::Horizontal) {
switch (section) {
case column_timestamp:
return QString("Timestamp");
case column_channel:
return QString("Channel");
case column_direction:
return QString("Rx/Tx");
case column_canid:
return QString("CAN ID");
case column_sender:
return QString("Sender");
case column_name:
return QString("Name");
case column_dlc:
return QString("DLC");
case column_data:
return QString("Data");
case column_comment:
return QString("Comment");
}
}
}
return QVariant();
}
QVariant BaseTraceViewModel::data(const QModelIndex &index, int role) const
{
switch (role) {
case Qt::DisplayRole:
return data_DisplayRole(index, role);
case Qt::TextAlignmentRole:
return data_TextAlignmentRole(index, role);
case Qt::TextColorRole:
return data_TextColorRole(index, role);
default:
return QVariant();
}
}
Backend *BaseTraceViewModel::backend() const
{
return _backend;
}
CanTrace *BaseTraceViewModel::trace() const
{
return _backend->getTrace();
}
timestamp_mode_t BaseTraceViewModel::timestampMode() const
{
return _timestampMode;
}
void BaseTraceViewModel::setTimestampMode(timestamp_mode_t timestampMode)
{
_timestampMode = timestampMode;
}
QVariant BaseTraceViewModel::formatTimestamp(timestamp_mode_t mode, const CanMessage &currentMsg, const CanMessage &lastMsg) const
{
if (mode==timestamp_mode_delta) {
double t_current = currentMsg.getFloatTimestamp();
double t_last = lastMsg.getFloatTimestamp();
if (t_last==0) {
return QVariant();
} else {
return QString().sprintf("%.04lf", t_current-t_last);
}
} else if (mode==timestamp_mode_absolute) {
return currentMsg.getDateTime().toString("hh:mm:ss.zzz");
} else if (mode==timestamp_mode_relative) {
double t_current = currentMsg.getFloatTimestamp();
return QString().sprintf("%.04lf", t_current - backend()->getTimestampAtMeasurementStart());
}
return QVariant();
}
QVariant BaseTraceViewModel::data_DisplayRole(const QModelIndex &index, int role) const
{
(void) index;
(void) role;
return QVariant();
}
QVariant BaseTraceViewModel::data_DisplayRole_Message(const QModelIndex &index, int role, const CanMessage &currentMsg, const CanMessage &lastMsg) const
{
(void) role;
CanDbMessage *dbmsg = backend()->findDbMessage(currentMsg);
switch (index.column()) {
case column_timestamp:
return formatTimestamp(_timestampMode, currentMsg, lastMsg);
case column_channel:
return backend()->getInterfaceName(currentMsg.getInterfaceId());
case column_direction:
return "rx";
case column_canid:
return currentMsg.getIdString();
case column_name:
return (dbmsg) ? dbmsg->getName() : "";
case column_sender:
return (dbmsg) ? dbmsg->getSender()->name() : "";
case column_dlc:
return currentMsg.getLength();
case column_data:
return currentMsg.getDataHexString();
case column_comment:
return (dbmsg) ? dbmsg->getComment() : "";
default:
return QVariant();
}
}
QVariant BaseTraceViewModel::data_DisplayRole_Signal(const QModelIndex &index, int role, const CanMessage &msg) const
{
(void) role;
uint64_t raw_data;
QString value_name;
QString unit;
CanDbMessage *dbmsg = backend()->findDbMessage(msg);
if (!dbmsg) { return QVariant(); }
CanDbSignal *dbsignal = dbmsg->getSignal(index.row());
if (!dbsignal) { return QVariant(); }
switch (index.column()) {
case column_name:
return dbsignal->name();
case column_data:
if (dbsignal->isPresentInMessage(msg)) {
raw_data = dbsignal->extractRawDataFromMessage(msg);
} else {
if (!trace()->getMuxedSignalFromCache(dbsignal, &raw_data)) {
return QVariant();
}
}
value_name = dbsignal->getValueName(raw_data);
if (value_name.isEmpty()) {
unit = dbsignal->getUnit();
if (unit.isEmpty()) {
return dbsignal->convertRawValueToPhysical(raw_data);
} else {
return QString("%1 %2").arg(dbsignal->convertRawValueToPhysical(raw_data)).arg(unit);
}
} else {
return QString("%1 - %2").arg(raw_data).arg(value_name);
}
case column_comment:
return dbsignal->comment().replace('\n', ' ');
default:
return QVariant();
}
}
QVariant BaseTraceViewModel::data_TextAlignmentRole(const QModelIndex &index, int role) const
{
(void) role;
switch (index.column()) {
case column_timestamp: return Qt::AlignRight + Qt::AlignVCenter;
case column_channel: return Qt::AlignCenter + Qt::AlignVCenter;
case column_direction: return Qt::AlignCenter + Qt::AlignVCenter;
case column_canid: return Qt::AlignRight + Qt::AlignVCenter;
case column_sender: return Qt::AlignLeft + Qt::AlignVCenter;
case column_name: return Qt::AlignLeft + Qt::AlignVCenter;
case column_dlc: return Qt::AlignCenter + Qt::AlignVCenter;
case column_data: return Qt::AlignLeft + Qt::AlignVCenter;
case column_comment: return Qt::AlignLeft + Qt::AlignVCenter;
default: return QVariant();
}
}
QVariant BaseTraceViewModel::data_TextColorRole(const QModelIndex &index, int role) const
{
(void) index;
(void) role;
return QVariant();
}
QVariant BaseTraceViewModel::data_TextColorRole_Signal(const QModelIndex &index, int role, const CanMessage &msg) const
{
(void) role;
CanDbMessage *dbmsg = backend()->findDbMessage(msg);
if (!dbmsg) { return QVariant(); }
CanDbSignal *dbsignal = dbmsg->getSignal(index.row());
if (!dbsignal) { return QVariant(); }
if (dbsignal->isPresentInMessage(msg)) {
return QVariant(); // default text color
} else {
return QVariant::fromValue(QColor(200,200,200));
}
}

View File

@@ -0,0 +1,76 @@
/*
Copyright (c) 2015, 2016 Hubert Denkmair <hubert@denkmair.de>
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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QAbstractItemModel>
#include "TraceViewTypes.h"
class Backend;
class CanTrace;
class CanMessage;
class CanDbSignal;
class BaseTraceViewModel : public QAbstractItemModel
{
Q_OBJECT
public:
enum {
column_timestamp,
column_channel,
column_direction,
column_canid,
column_sender,
column_name,
column_dlc,
column_data,
column_comment,
column_count
};
public:
BaseTraceViewModel(Backend &backend);
virtual int columnCount(const QModelIndex &parent) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
virtual QVariant data(const QModelIndex &index, int role) const;
Backend *backend() const;
CanTrace *trace() const;
timestamp_mode_t timestampMode() const;
void setTimestampMode(timestamp_mode_t timestampMode);
protected:
virtual QVariant data_DisplayRole(const QModelIndex &index, int role) const;
virtual QVariant data_DisplayRole_Message(const QModelIndex &index, int role, const CanMessage &currentMsg, const CanMessage &lastMsg) const;
virtual QVariant data_DisplayRole_Signal(const QModelIndex &index, int role, const CanMessage &msg) const;
virtual QVariant data_TextAlignmentRole(const QModelIndex &index, int role) const;
virtual QVariant data_TextColorRole(const QModelIndex &index, int role) const;
virtual QVariant data_TextColorRole_Signal(const QModelIndex &index, int role, const CanMessage &msg) const;
QVariant formatTimestamp(timestamp_mode_t mode, const CanMessage &currentMsg, const CanMessage &lastMsg) const;
private:
Backend *_backend;
timestamp_mode_t _timestampMode;
};

View File

@@ -0,0 +1,143 @@
/*
Copyright (c) 2015, 2016 Hubert Denkmair <hubert@denkmair.de>
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 <http://www.gnu.org/licenses/>.
*/
#include "LinearTraceViewModel.h"
#include <iostream>
#include <stddef.h>
#include <core/Backend.h>
LinearTraceViewModel::LinearTraceViewModel(Backend &backend)
: BaseTraceViewModel(backend)
{
connect(backend.getTrace(), SIGNAL(beforeAppend(int)), this, SLOT(beforeAppend(int)));
connect(backend.getTrace(), SIGNAL(afterAppend()), this, SLOT(afterAppend()));
connect(backend.getTrace(), SIGNAL(beforeClear()), this, SLOT(beforeClear()));
connect(backend.getTrace(), SIGNAL(afterClear()), this, SLOT(afterClear()));
}
QModelIndex LinearTraceViewModel::index(int row, int column, const QModelIndex &parent) const
{
if (parent.isValid() && parent.internalId()) {
return createIndex(row, column, (unsigned int)(0x80000000 | parent.internalId()));
} else {
return createIndex(row, column, row+1);
}
}
QModelIndex LinearTraceViewModel::parent(const QModelIndex &child) const
{
(void) child;
quintptr id = child.internalId();
if (id & 0x80000000) {
return createIndex(id & 0x7FFFFFFF, 0, (unsigned int)(id & 0x7FFFFFFF));
}
return QModelIndex();
}
int LinearTraceViewModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid()) {
quintptr id = parent.internalId();
if (id & 0x80000000) { // node of a message
return 0;
} else { // a message
const CanMessage *msg = trace()->getMessage(id-1);
if (msg) {
CanDbMessage *dbmsg = backend()->findDbMessage(*msg);
return (dbmsg!=0) ? dbmsg->getSignals().length() : 0;
} else {
return 0;
}
}
} else {
return trace()->size();
}
}
int LinearTraceViewModel::columnCount(const QModelIndex &parent) const
{
(void) parent;
return column_count;
}
bool LinearTraceViewModel::hasChildren(const QModelIndex &parent) const
{
return rowCount(parent)>0;
}
void LinearTraceViewModel::beforeAppend(int num_messages)
{
beginInsertRows(QModelIndex(), trace()->size(), trace()->size()+num_messages-1);
}
void LinearTraceViewModel::afterAppend()
{
endInsertRows();
}
void LinearTraceViewModel::beforeClear()
{
beginResetModel();
}
void LinearTraceViewModel::afterClear()
{
endResetModel();
}
QVariant LinearTraceViewModel::data_DisplayRole(const QModelIndex &index, int role) const
{
quintptr id = index.internalId();
int msg_id = (id & ~0x80000000)-1;
const CanMessage *msg = trace()->getMessage(msg_id);
if (!msg) { return QVariant(); }
if (id & 0x80000000) {
return data_DisplayRole_Signal(index, role, *msg);
} else if (id) {
if (msg_id>1) {
const CanMessage *prev_msg = trace()->getMessage(msg_id-1);
return data_DisplayRole_Message(index, role, *msg, *prev_msg);
} else {
return data_DisplayRole_Message(index, role, *msg, CanMessage());
}
}
return QVariant();
}
QVariant LinearTraceViewModel::data_TextColorRole(const QModelIndex &index, int role) const
{
(void) role;
quintptr id = index.internalId();
if (id & 0x80000000) { // CanSignal row
int msg_id = (id & ~0x80000000)-1;
const CanMessage *msg = trace()->getMessage(msg_id);
if (msg) {
return data_TextColorRole_Signal(index, role, *msg);
}
}
return QVariant();
}

View File

@@ -0,0 +1,53 @@
/*
Copyright (c) 2015, 2016 Hubert Denkmair <hubert@denkmair.de>
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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <QAbstractItemModel>
#include <core/CanDb.h>
#include <core/CanTrace.h>
#include "BaseTraceViewModel.h"
class Backend;
class LinearTraceViewModel : public BaseTraceViewModel
{
Q_OBJECT
public:
LinearTraceViewModel(Backend &backend);
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const;
virtual QModelIndex parent(const QModelIndex &child) const;
virtual int rowCount(const QModelIndex &parent) const;
virtual int columnCount(const QModelIndex &parent) const;
virtual bool hasChildren(const QModelIndex &parent) const;
private slots:
void beforeAppend(int num_messages);
void afterAppend();
void beforeClear();
void afterClear();
private:
virtual QVariant data_DisplayRole(const QModelIndex &index, int role) const;
virtual QVariant data_TextColorRole(const QModelIndex &index, int role) const;
};

View File

@@ -0,0 +1,41 @@
#include "TraceFilterModel.h"
TraceFilterModel::TraceFilterModel(QObject *parent)
: QSortFilterProxyModel{parent},
_filterText("")
{
setRecursiveFilteringEnabled(false);
}
void TraceFilterModel::setFilterText(QString filtertext)
{
_filterText = filtertext;
}
bool TraceFilterModel::filterAcceptsRow(int source_row, const QModelIndex & source_parent) const
{
// Pass all on no filter
if(_filterText.length() == 0)
return true;
QModelIndex idx0 = sourceModel()->index(source_row, 1, source_parent); // Channel
QModelIndex idx1 = sourceModel()->index(source_row, 3, source_parent); // CAN ID
QModelIndex idx2 = sourceModel()->index(source_row, 4, source_parent); // Sender
QModelIndex idx3 = sourceModel()->index(source_row, 5, source_parent); // Name
QString datastr0 = sourceModel()->data(idx0).toString();
QString datastr1 = sourceModel()->data(idx1).toString();
QString datastr2 = sourceModel()->data(idx2).toString();
QString datastr3 = sourceModel()->data(idx3).toString();
fprintf(stderr, "Data for acceptance is %s\r\n", datastr1.toStdString().c_str());
if( datastr0.contains(_filterText) ||
datastr1.contains(_filterText) ||
datastr2.contains(_filterText) ||
datastr3.contains(_filterText))
return true;
else
return false;
}

View File

@@ -0,0 +1,21 @@
#ifndef TRACEFILTER_H
#define TRACEFILTER_H
#include <QSortFilterProxyModel>
class TraceFilterModel : public QSortFilterProxyModel
{
public:
explicit TraceFilterModel(QObject *parent = nullptr);
public slots:
void setFilterText(QString filtertext);
private:
QString _filterText;
protected:
virtual bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override;
};
#endif // TRACEFILTER_H

View File

@@ -0,0 +1,30 @@
/*
Copyright (c) 2015, 2016 Hubert Denkmair <hubert@denkmair.de>
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 <http://www.gnu.org/licenses/>.
*/
#pragma once
typedef enum timestamp_mode {
timestamp_mode_absolute,
timestamp_mode_relative,
timestamp_mode_delta,
timestamp_modes_count
} timestamp_mode_t;

View File

@@ -0,0 +1,217 @@
/*
Copyright (c) 2015, 2016 Hubert Denkmair <hubert@denkmair.de>
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 <http://www.gnu.org/licenses/>.
*/
#include "TraceWindow.h"
#include "ui_TraceWindow.h"
#include <QDomDocument>
#include <QSortFilterProxyModel>
#include "LinearTraceViewModel.h"
#include "AggregatedTraceViewModel.h"
#include "TraceFilterModel.h"
TraceWindow::TraceWindow(QWidget *parent, Backend &backend) :
ConfigurableWidget(parent),
ui(new Ui::TraceWindow),
_backend(&backend)
{
ui->setupUi(this);
_linearTraceViewModel = new LinearTraceViewModel(backend);
_linearProxyModel = new QSortFilterProxyModel(this);
_linearProxyModel->setSourceModel(_linearTraceViewModel);
_linearProxyModel->setDynamicSortFilter(true);
_aggregatedTraceViewModel = new AggregatedTraceViewModel(backend);
_aggregatedProxyModel = new QSortFilterProxyModel(this);
_aggregatedProxyModel->setSourceModel(_aggregatedTraceViewModel);
_aggregatedProxyModel->setDynamicSortFilter(true);
_aggFilteredModel = new TraceFilterModel(this);
_aggFilteredModel->setSourceModel(_aggregatedProxyModel);
_linFilteredModel = new TraceFilterModel(this);
_linFilteredModel->setSourceModel(_linearProxyModel);
setMode(mode_aggregated);
setAutoScroll(false);
QFont font("Monospace");
font.setStyleHint(QFont::TypeWriter);
ui->tree->setFont(font);
ui->tree->setAlternatingRowColors(true);
ui->tree->setUniformRowHeights(true);
ui->tree->setColumnWidth(0, 120);
ui->tree->setColumnWidth(1, 70);
ui->tree->setColumnWidth(2, 50);
ui->tree->setColumnWidth(3, 90);
ui->tree->setColumnWidth(4, 200);
ui->tree->setColumnWidth(5, 200);
ui->tree->setColumnWidth(6, 50);
ui->tree->setColumnWidth(7, 200);
ui->tree->sortByColumn(BaseTraceViewModel::column_canid, Qt::AscendingOrder);
ui->cbTimestampMode->addItem("absolute", 0);
ui->cbTimestampMode->addItem("relative", 1);
ui->cbTimestampMode->addItem("delta", 2);
setTimestampMode(timestamp_mode_delta);
connect(_linearTraceViewModel, SIGNAL(rowsInserted(QModelIndex,int,int)), this, SLOT(rowsInserted(QModelIndex,int,int)));
connect(ui->filterLineEdit, SIGNAL(textChanged(QString)), this, SLOT(on_cbFilterChanged()));
}
TraceWindow::~TraceWindow()
{
delete ui;
delete _aggregatedTraceViewModel;
delete _linearTraceViewModel;
}
void TraceWindow::setMode(TraceWindow::mode_t mode)
{
bool isChanged = (_mode != mode);
_mode = mode;
if (_mode==mode_linear) {
ui->tree->setSortingEnabled(false);
ui->tree->setModel(_linFilteredModel); //_linearTraceViewModel);
ui->cbAutoScroll->setEnabled(true);
} else {
ui->tree->setSortingEnabled(true);
ui->tree->setModel(_aggFilteredModel); //_aggregatedProxyModel);
ui->cbAutoScroll->setEnabled(false);
}
if (isChanged) {
ui->cbAggregated->setChecked(_mode==mode_aggregated);
emit(settingsChanged(this));
}
}
void TraceWindow::setAutoScroll(bool doAutoScroll)
{
if (doAutoScroll != _doAutoScroll) {
_doAutoScroll = doAutoScroll;
ui->cbAutoScroll->setChecked(_doAutoScroll);
emit(settingsChanged(this));
}
}
void TraceWindow::setTimestampMode(int mode)
{
timestamp_mode_t new_mode;
if ( (mode>=0) && (mode<timestamp_modes_count) ) {
new_mode = (timestamp_mode_t) mode;
} else {
new_mode = timestamp_mode_absolute;
}
_aggregatedTraceViewModel->setTimestampMode(new_mode);
_linearTraceViewModel->setTimestampMode(new_mode);
if (new_mode != _timestampMode) {
_timestampMode = new_mode;
for (int i=0; i<ui->cbTimestampMode->count(); i++) {
if (ui->cbTimestampMode->itemData(i).toInt() == new_mode) {
ui->cbTimestampMode->setCurrentIndex(i);
}
}
emit(settingsChanged(this));
}
}
bool TraceWindow::saveXML(Backend &backend, QDomDocument &xml, QDomElement &root)
{
if (!ConfigurableWidget::saveXML(backend, xml, root)) {
return false;
}
root.setAttribute("type", "TraceWindow");
root.setAttribute("mode", (_mode==mode_linear) ? "linear" : "aggregated");
root.setAttribute("TimestampMode", _timestampMode);
QDomElement elLinear = xml.createElement("LinearTraceView");
elLinear.setAttribute("AutoScroll", (ui->cbAutoScroll->checkState() == Qt::Checked) ? 1 : 0);
root.appendChild(elLinear);
QDomElement elAggregated = xml.createElement("AggregatedTraceView");
elAggregated.setAttribute("SortColumn", _aggregatedProxyModel->sortColumn());
root.appendChild(elAggregated);
return true;
}
bool TraceWindow::loadXML(Backend &backend, QDomElement &el)
{
if (!ConfigurableWidget::loadXML(backend, el)) {
return false;
}
setMode((el.attribute("mode", "linear") == "linear") ? mode_linear : mode_aggregated);
setTimestampMode(el.attribute("TimestampMode", "0").toInt());
QDomElement elLinear = el.firstChildElement("LinearTraceView");
setAutoScroll(elLinear.attribute("AutoScroll", "0").toInt() != 0);
QDomElement elAggregated = el.firstChildElement("AggregatedTraceView");
int sortColumn = elAggregated.attribute("SortColumn", "-1").toInt();
ui->tree->sortByColumn(sortColumn);
return true;
}
void TraceWindow::rowsInserted(const QModelIndex &parent, int first, int last)
{
(void) parent;
(void) first;
(void) last;
if ((_mode==mode_linear) && (ui->cbAutoScroll->checkState() == Qt::Checked)) {
ui->tree->scrollToBottom();
}
}
void TraceWindow::on_cbAggregated_stateChanged(int i)
{
setMode( (i==Qt::Checked) ? mode_aggregated : mode_linear );
}
void TraceWindow::on_cbAutoScroll_stateChanged(int i)
{
setAutoScroll(i==Qt::Checked);
}
void TraceWindow::on_cbTimestampMode_currentIndexChanged(int index)
{
setTimestampMode((timestamp_mode_t)ui->cbTimestampMode->itemData(index).toInt());
}
void TraceWindow::on_cbFilterChanged()
{
_aggFilteredModel->setFilterText(ui->filterLineEdit->text());
_linFilteredModel->setFilterText(ui->filterLineEdit->text());
_aggFilteredModel->invalidate();
_linFilteredModel->invalidate();
}

View File

@@ -0,0 +1,82 @@
/*
Copyright (c) 2015, 2016 Hubert Denkmair <hubert@denkmair.de>
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 <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <core/ConfigurableWidget.h>
#include "TraceViewTypes.h"
#include "TraceFilterModel.h"
namespace Ui {
class TraceWindow;
}
class QDomDocument;
class QDomElement;
class QSortFilterProxyModel;
class LinearTraceViewModel;
class AggregatedTraceViewModel;
class Backend;
class TraceWindow : public ConfigurableWidget
{
Q_OBJECT
public:
typedef enum mode {
mode_linear,
mode_aggregated
} mode_t;
explicit TraceWindow(QWidget *parent, Backend &backend);
~TraceWindow();
void setMode(mode_t mode);
void setAutoScroll(bool doAutoScroll);
void setTimestampMode(int mode);
virtual bool saveXML(Backend &backend, QDomDocument &xml, QDomElement &root);
virtual bool loadXML(Backend &backend, QDomElement &el);
public slots:
void rowsInserted(const QModelIndex & parent, int first, int last);
private slots:
void on_cbAggregated_stateChanged(int i);
void on_cbAutoScroll_stateChanged(int i);
void on_cbTimestampMode_currentIndexChanged(int index);
void on_cbFilterChanged(void);
private:
Ui::TraceWindow *ui;
Backend *_backend;
mode_t _mode;
bool _doAutoScroll;
timestamp_mode_t _timestampMode;
TraceFilterModel * _aggFilteredModel;
TraceFilterModel * _linFilteredModel;
LinearTraceViewModel *_linearTraceViewModel;
AggregatedTraceViewModel *_aggregatedTraceViewModel;
QSortFilterProxyModel *_aggregatedProxyModel;
QSortFilterProxyModel *_linearProxyModel;
};

View File

@@ -0,0 +1,19 @@
SOURCES += \
$$PWD/TraceFilterModel.cpp \
$$PWD/LinearTraceViewModel.cpp \
$$PWD/AggregatedTraceViewModel.cpp \
$$PWD/BaseTraceViewModel.cpp \
$$PWD/AggregatedTraceViewItem.cpp \
$$PWD/TraceWindow.cpp \
HEADERS += \
$$PWD/LinearTraceViewModel.h \
$$PWD/AggregatedTraceViewModel.h \
$$PWD/BaseTraceViewModel.h \
$$PWD/AggregatedTraceViewItem.h \
$$PWD/TraceFilterModel.h \
$$PWD/TraceWindow.h \
$$PWD/TraceViewTypes.h \
FORMS += \
$$PWD/TraceWindow.ui

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TraceWindow</class>
<widget class="QWidget" name="TraceWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>918</width>
<height>616</height>
</rect>
</property>
<property name="windowTitle">
<string>Trace View</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Timestamps:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="cbTimestampMode"/>
</item>
<item>
<widget class="QCheckBox" name="cbAggregated">
<property name="text">
<string>aggregate by ID</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="cbAutoScroll">
<property name="text">
<string>auto scroll</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Filter: </string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="filterLineEdit"/>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QTreeView" name="tree">
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>