Added "time as seconds" mode. It does what it says. This tends to be easier to view. Also added ID based filtering to the main form. This does work and will filter out any IDs you uncheck. Next up, loading and saving the filter list and saving the filtered frames to file.
This commit is contained in:
+116
-20
@@ -1,6 +1,11 @@
|
||||
#include "canframemodel.h"
|
||||
|
||||
int CANFrameModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return filteredFrames.count();
|
||||
}
|
||||
|
||||
int CANFrameModel::totalFrameCount()
|
||||
{
|
||||
return frames.count();
|
||||
}
|
||||
@@ -14,9 +19,12 @@ CANFrameModel::CANFrameModel(QObject *parent)
|
||||
: QAbstractTableModel(parent)
|
||||
{
|
||||
frames.reserve(10000000); //yes, I'm preallocating 10 million entries in this list. I don't think anyone will exceed this.
|
||||
filteredFrames.reserve(10000000);
|
||||
dbcHandler = NULL;
|
||||
interpretFrames = false;
|
||||
overwriteDups = false;
|
||||
useHexMode = true;
|
||||
timeSeconds = false;
|
||||
timeOffset = 0;
|
||||
}
|
||||
|
||||
@@ -30,6 +38,16 @@ void CANFrameModel::setHexMode(bool mode)
|
||||
}
|
||||
}
|
||||
|
||||
void CANFrameModel::setSecondsMode(bool mode)
|
||||
{
|
||||
if (timeSeconds != mode)
|
||||
{
|
||||
this->beginResetModel();
|
||||
timeSeconds = mode;
|
||||
this->endResetModel();
|
||||
}
|
||||
}
|
||||
|
||||
void CANFrameModel::setDBCHandler(DBCHandler *handler)
|
||||
{
|
||||
dbcHandler = handler;
|
||||
@@ -49,13 +67,17 @@ void CANFrameModel::setInterpetMode(bool mode)
|
||||
|
||||
void CANFrameModel::normalizeTiming()
|
||||
{
|
||||
if (frames.count() == 0) return;
|
||||
this->beginResetModel();
|
||||
if (frames.count() == 0) return;
|
||||
timeOffset = frames[0].timestamp;
|
||||
for (int i = 0; i < frames.count(); i++)
|
||||
{
|
||||
frames[i].timestamp -= timeOffset;
|
||||
}
|
||||
this->beginResetModel();
|
||||
for (int i = 0; i < filteredFrames.count(); i++)
|
||||
{
|
||||
filteredFrames[i].timestamp -= timeOffset;
|
||||
}
|
||||
this->endResetModel();
|
||||
}
|
||||
|
||||
@@ -64,6 +86,13 @@ void CANFrameModel::setOverwriteMode(bool mode)
|
||||
overwriteDups = mode;
|
||||
}
|
||||
|
||||
void CANFrameModel::setFilterState(int ID, bool state)
|
||||
{
|
||||
if (!filters.contains(ID)) return;
|
||||
filters[ID] = state;
|
||||
sendRefresh();
|
||||
}
|
||||
|
||||
void CANFrameModel::recalcOverwrite()
|
||||
{
|
||||
if (!overwriteDups) return; //no need to do a thing if mode is disabled
|
||||
@@ -93,6 +122,16 @@ void CANFrameModel::recalcOverwrite()
|
||||
|
||||
while (frames.count() > lastUnique) frames.removeLast();
|
||||
|
||||
filteredFrames.clear();
|
||||
|
||||
for (int i = 0; i < frames.count(); i++)
|
||||
{
|
||||
if (filters[frames[i].ID])
|
||||
{
|
||||
filteredFrames.append(frames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
@@ -102,16 +141,16 @@ QVariant CANFrameModel::data(const QModelIndex &index, int role) const
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
if (index.row() >= frames.count())
|
||||
if (index.row() >= filteredFrames.count())
|
||||
return QVariant();
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
CANFrame thisFrame = frames.at(index.row());
|
||||
CANFrame thisFrame = filteredFrames.at(index.row());
|
||||
switch (index.column())
|
||||
{
|
||||
case 0: //timestamp
|
||||
|
||||
return QString::number(thisFrame.timestamp);
|
||||
if (!timeSeconds) return QString::number(thisFrame.timestamp);
|
||||
else return QString::number(thisFrame.timestamp / 1000000.0f);
|
||||
break;
|
||||
case 1: //id
|
||||
if (useHexMode)
|
||||
@@ -199,11 +238,23 @@ void CANFrameModel::addFrame(CANFrame &frame, bool autoRefresh = false)
|
||||
{
|
||||
mutex.lock();
|
||||
frame.timestamp -= timeOffset;
|
||||
if (!overwriteDups)
|
||||
|
||||
//if this ID isn't found in the filters list then add it and show it by default
|
||||
if (!filters.contains(frame.ID))
|
||||
{
|
||||
if (autoRefresh) beginInsertRows(QModelIndex(), frames.count() + 1, frames.count() + 1);
|
||||
frames.append(frame);
|
||||
if (autoRefresh) endInsertRows();
|
||||
filters.insert(frame.ID, true);
|
||||
emit updatedFiltersList();
|
||||
}
|
||||
|
||||
if (!overwriteDups)
|
||||
{
|
||||
frames.append(frame);
|
||||
if (filters[frame.ID])
|
||||
{
|
||||
if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + 1);
|
||||
filteredFrames.append(frame);
|
||||
if (autoRefresh) endInsertRows();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -211,27 +262,50 @@ void CANFrameModel::addFrame(CANFrame &frame, bool autoRefresh = false)
|
||||
for (int i = 0; i < frames.count(); i++)
|
||||
{
|
||||
if (frames[i].ID == frame.ID)
|
||||
{
|
||||
if (autoRefresh) beginResetModel();
|
||||
frames.replace(i, frame);
|
||||
if (autoRefresh) endResetModel();
|
||||
{
|
||||
frames.replace(i, frame);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
{
|
||||
if (autoRefresh) beginInsertRows(QModelIndex(), frames.count() + 1, frames.count() + 1);
|
||||
{
|
||||
frames.append(frame);
|
||||
if (autoRefresh) endInsertRows();
|
||||
if (filters[frame.ID])
|
||||
{
|
||||
if (autoRefresh) beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + 1);
|
||||
filteredFrames.append(frame);
|
||||
if (autoRefresh) endInsertRows();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int j = 0; j < filteredFrames.count(); j++)
|
||||
{
|
||||
if (filteredFrames[j].ID == frame.ID)
|
||||
{
|
||||
if (autoRefresh) beginResetModel();
|
||||
filteredFrames.replace(j, frame);
|
||||
if (autoRefresh) endResetModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
void CANFrameModel::sendRefresh()
|
||||
{
|
||||
beginResetModel();
|
||||
filteredFrames.clear();
|
||||
for (int i = 0; i < frames.count(); i++)
|
||||
{
|
||||
if (filters[frames[i].ID])
|
||||
{
|
||||
filteredFrames.append(frames[i]);
|
||||
}
|
||||
}
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
@@ -255,9 +329,10 @@ void CANFrameModel::sendBulkRefresh(int num)
|
||||
|
||||
if (!overwriteDups)
|
||||
{
|
||||
if (num > frames.count()) num = frames.count();
|
||||
if (num > filteredFrames.count()) num = filteredFrames.count();
|
||||
beginInsertRows(QModelIndex(), frames.count() - num, frames.count() - 1);
|
||||
endInsertRows();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -270,8 +345,12 @@ void CANFrameModel::clearFrames()
|
||||
mutex.lock();
|
||||
this->beginResetModel();
|
||||
frames.clear();
|
||||
filteredFrames.clear();
|
||||
filters.clear();
|
||||
this->endResetModel();
|
||||
mutex.unlock();
|
||||
|
||||
emit updatedFiltersList();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -280,12 +359,24 @@ void CANFrameModel::clearFrames()
|
||||
* allows for a mass import of frames into the model
|
||||
*/
|
||||
void CANFrameModel::insertFrames(const QVector<CANFrame> &newFrames)
|
||||
{
|
||||
beginInsertRows(QModelIndex(), frames.count() + 1, frames.count() + newFrames.count());
|
||||
{
|
||||
int insertedFiltered = 0;
|
||||
for (int i = 0; i < newFrames.count(); i++)
|
||||
{
|
||||
frames.append(newFrames[i]);
|
||||
if (!filters.contains(newFrames[i].ID))
|
||||
{
|
||||
filters.insert(newFrames[i].ID, true);
|
||||
emit updatedFiltersList();
|
||||
}
|
||||
if (filters[newFrames[i].ID])
|
||||
{
|
||||
insertedFiltered++;
|
||||
filteredFrames.append(newFrames[i]);
|
||||
}
|
||||
}
|
||||
|
||||
beginInsertRows(QModelIndex(), filteredFrames.count() + 1, filteredFrames.count() + insertedFiltered);
|
||||
endInsertRows();
|
||||
}
|
||||
|
||||
@@ -300,3 +391,8 @@ const QVector<CANFrame>* CANFrameModel::getListReference() const
|
||||
{
|
||||
return &frames;
|
||||
}
|
||||
|
||||
const QMap<int, bool>* CANFrameModel::getFiltersReference() const
|
||||
{
|
||||
return &filters;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ public:
|
||||
QVariant headerData(int section, Qt::Orientation orientation,
|
||||
int role = Qt::DisplayRole) const;
|
||||
int columnCount(const QModelIndex &) const;
|
||||
int totalFrameCount();
|
||||
|
||||
void addFrame(CANFrame &, bool);
|
||||
void sendRefresh();
|
||||
@@ -31,19 +32,27 @@ public:
|
||||
void setInterpetMode(bool);
|
||||
void setOverwriteMode(bool);
|
||||
void setHexMode(bool);
|
||||
void setFilterState(int ID, bool state);
|
||||
void setSecondsMode(bool);
|
||||
void normalizeTiming();
|
||||
void recalcOverwrite();
|
||||
void insertFrames(const QVector<CANFrame> &newFrames);
|
||||
const QVector<CANFrame> *getListReference() const; //thou shalt not modify these frames externally!
|
||||
const QMap<int, bool> *getFiltersReference() const; //this neither
|
||||
|
||||
signals:
|
||||
void updatedFiltersList();
|
||||
|
||||
private:
|
||||
QVector<CANFrame> frames;
|
||||
QVector<CANFrame> filteredFrames;
|
||||
QMap<int, bool> filters;
|
||||
DBCHandler *dbcHandler;
|
||||
QMutex mutex;
|
||||
bool interpretFrames; //should we use the dbcHandler?
|
||||
bool overwriteDups; //should we display all frames or only the newest for each ID?
|
||||
bool useHexMode;
|
||||
bool timeSeconds;
|
||||
uint64_t timeOffset;
|
||||
};
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ MainSettingsDialog::MainSettingsDialog(QWidget *parent) :
|
||||
ui->cbRestorePositions->setChecked(settings->value("Main/SaveRestorePositions", true).toBool());
|
||||
ui->cbValidate->setChecked(settings->value("Main/ValidateComm", true).toBool());
|
||||
ui->spinPlaybackSpeed->setValue(settings->value("Playback/DefSpeed", 5).toInt());
|
||||
ui->cbTimeSeconds->setChecked(settings->value("Main/TimeSeconds", false).toBool());
|
||||
|
||||
//just for simplicity they all call the same function and that function updates all settings at once
|
||||
connect(ui->cbDisplayHex, SIGNAL(toggled(bool)), this, SLOT(updateSettings()));
|
||||
@@ -31,6 +32,7 @@ MainSettingsDialog::MainSettingsDialog(QWidget *parent) :
|
||||
connect(ui->cbRestorePositions, SIGNAL(toggled(bool)), this, SLOT(updateSettings()));
|
||||
connect(ui->cbValidate, SIGNAL(toggled(bool)), this, SLOT(updateSettings()));
|
||||
connect(ui->spinPlaybackSpeed, SIGNAL(valueChanged(int)), this, SLOT(updateSettings()));
|
||||
connect(ui->cbTimeSeconds, SIGNAL(toggled(bool)), this, SLOT(updateSettings()));
|
||||
}
|
||||
|
||||
MainSettingsDialog::~MainSettingsDialog()
|
||||
@@ -55,6 +57,7 @@ void MainSettingsDialog::updateSettings()
|
||||
settings->setValue("Main/SaveRestorePositions", ui->cbRestorePositions->isChecked());
|
||||
settings->setValue("Main/ValidateComm", ui->cbValidate->isChecked());
|
||||
settings->setValue("Playback/DefSpeed", ui->spinPlaybackSpeed->value());
|
||||
settings->setValue("Main/TimeSeconds", ui->cbTimeSeconds->isChecked());
|
||||
|
||||
settings->sync();
|
||||
}
|
||||
|
||||
@@ -41,6 +41,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="cbTimeSeconds">
|
||||
<property name="text">
|
||||
<string>Display time in seconds</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
+42
-1
@@ -38,6 +38,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
useHex = true;
|
||||
|
||||
//These things are used by QSettings to set up setting storage
|
||||
QCoreApplication::setOrganizationName("EVTV");
|
||||
QCoreApplication::setOrganizationDomain("evtv.me");
|
||||
@@ -140,6 +142,8 @@ MainWindow::MainWindow(QWidget *parent) :
|
||||
connect(ui->actionFile_Comparison, SIGNAL(triggered(bool)), this, SLOT(showComparisonWindow()));
|
||||
connect(ui->btnNormalize, SIGNAL(clicked(bool)), this, SLOT(normalizeTiming()));
|
||||
connect(ui->actionPreferences, SIGNAL(triggered(bool)), this, SLOT(showSettingsDialog()));
|
||||
connect(model, SIGNAL(updatedFiltersList()), this, SLOT(updateFilterList()));
|
||||
connect(ui->listFilters, SIGNAL(itemChanged(QListWidgetItem*)), this, SLOT(filterListItemChanged(QListWidgetItem*)));
|
||||
|
||||
lbStatusConnected.setText(tr("Not connected"));
|
||||
updateFileStatus();
|
||||
@@ -242,7 +246,9 @@ void MainWindow::readSettings()
|
||||
{
|
||||
ui->cbAutoScroll->setChecked(true);
|
||||
}
|
||||
model->setHexMode(settings.value("Main/UseHex", true).toBool());
|
||||
useHex = settings.value("Main/UseHex", true).toBool();
|
||||
model->setHexMode(useHex);
|
||||
model->setSecondsMode(settings.value("Main/TimeSeconds", false).toBool());
|
||||
}
|
||||
|
||||
void MainWindow::writeSettings()
|
||||
@@ -277,6 +283,41 @@ void MainWindow::overwriteToggled(bool state)
|
||||
model->setOverwriteMode(state);
|
||||
}
|
||||
|
||||
void MainWindow::updateFilterList()
|
||||
{
|
||||
if (model == NULL) return;
|
||||
const QMap<int, bool> *filters = model->getFiltersReference();
|
||||
if (filters == NULL) return;
|
||||
|
||||
ui->listFilters->clear();
|
||||
|
||||
if (filters->isEmpty()) return;
|
||||
|
||||
QMap<int, bool>::const_iterator filterIter;
|
||||
for (filterIter = filters->begin(); filterIter != filters->end(); ++filterIter)
|
||||
{
|
||||
QListWidgetItem *thisItem = new QListWidgetItem();
|
||||
if (useHex) thisItem->setText(QString::number(filterIter.key(), 16).toUpper().rightJustified(4,'0'));
|
||||
else thisItem->setText(QString::number(filterIter.key()));
|
||||
thisItem->setFlags(thisItem->flags() | Qt::ItemIsUserCheckable);
|
||||
if (filterIter.value()) thisItem->setCheckState(Qt::Checked);
|
||||
else thisItem->setCheckState(Qt::Unchecked);
|
||||
ui->listFilters->addItem(thisItem);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::filterListItemChanged(QListWidgetItem *item)
|
||||
{
|
||||
//qDebug() << item->text();
|
||||
int ID;
|
||||
bool isSet = false;
|
||||
if (useHex) ID = item->text().toInt(NULL, 16);
|
||||
else ID = item->text().toInt();
|
||||
if (item->checkState() == Qt::Checked) isSet = true;
|
||||
|
||||
model->setFilterState(ID, isSet);
|
||||
}
|
||||
|
||||
//most of the work is handled elsewhere. Need only to update the # of frames
|
||||
//and maybe auto scroll
|
||||
void MainWindow::gotFrames(int FPS, int framesSinceLastUpdate)
|
||||
|
||||
@@ -61,6 +61,8 @@ private slots:
|
||||
void showDBCEditor();
|
||||
void toggleCapture();
|
||||
void normalizeTiming();
|
||||
void updateFilterList();
|
||||
void filterListItemChanged(QListWidgetItem *item);
|
||||
|
||||
public slots:
|
||||
void gotFrames(int, int);
|
||||
@@ -88,6 +90,7 @@ private:
|
||||
QThread serialWorkerThread;
|
||||
SerialWorker *worker;
|
||||
QByteArray inputBuffer;
|
||||
bool useHex;
|
||||
bool allowCapture;
|
||||
bool bDirty; //have frames been added or subtracted since the last save/load?
|
||||
|
||||
|
||||
+49
-1
@@ -236,6 +236,35 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item alignment="Qt::AlignHCenter">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Frame Filtering:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="listFilters">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>160</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>175</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -273,8 +302,12 @@
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionOpen_Log_File"/>
|
||||
<addaction name="actionSave_Filtered_Log_File"/>
|
||||
<addaction name="actionSave_Log_File"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionLoad_Filter_Definition"/>
|
||||
<addaction name="actionSave_Filter_Definition"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionLoad_DBC_File"/>
|
||||
<addaction name="actionEdit_Messages_Signals"/>
|
||||
<addaction name="actionSave_DBC_File"/>
|
||||
@@ -326,7 +359,7 @@
|
||||
</action>
|
||||
<action name="actionOpen_Log_File">
|
||||
<property name="text">
|
||||
<string>Open Log File</string>
|
||||
<string>Load Log File</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_Log_File">
|
||||
@@ -374,6 +407,21 @@
|
||||
<string>Preferences</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_Filtered_Log_File">
|
||||
<property name="text">
|
||||
<string>Save Filtered Log File</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLoad_Filter_Definition">
|
||||
<property name="text">
|
||||
<string>Load Filter Definition</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave_Filter_Definition">
|
||||
<property name="text">
|
||||
<string>Save Filter Definition</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources/>
|
||||
|
||||
Reference in New Issue
Block a user