From 65656b185b1cb279fb7ad4d63ce7ca4e065c608c Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Mon, 29 Jun 2015 22:02:37 -0400 Subject: [PATCH] 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. --- canframemodel.cpp | 136 +++++++++++++++++++++++++++++++++++------ canframemodel.h | 9 +++ mainsettingsdialog.cpp | 3 + mainsettingsdialog.ui | 7 +++ mainwindow.cpp | 43 ++++++++++++- mainwindow.h | 3 + mainwindow.ui | 50 ++++++++++++++- 7 files changed, 229 insertions(+), 22 deletions(-) diff --git a/canframemodel.cpp b/canframemodel.cpp index e3bb856..703b256 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -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 &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* CANFrameModel::getListReference() const { return &frames; } + +const QMap* CANFrameModel::getFiltersReference() const +{ + return &filters; +} diff --git a/canframemodel.h b/canframemodel.h index 12a1e2a..9a5e723 100644 --- a/canframemodel.h +++ b/canframemodel.h @@ -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 &newFrames); const QVector *getListReference() const; //thou shalt not modify these frames externally! + const QMap *getFiltersReference() const; //this neither +signals: + void updatedFiltersList(); private: QVector frames; + QVector filteredFrames; + QMap 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; }; diff --git a/mainsettingsdialog.cpp b/mainsettingsdialog.cpp index 0cae4f2..a8c960a 100644 --- a/mainsettingsdialog.cpp +++ b/mainsettingsdialog.cpp @@ -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(); } diff --git a/mainsettingsdialog.ui b/mainsettingsdialog.ui index 8cd0ed2..6ac5dfb 100644 --- a/mainsettingsdialog.ui +++ b/mainsettingsdialog.ui @@ -41,6 +41,13 @@ + + + + Display time in seconds + + + diff --git a/mainwindow.cpp b/mainwindow.cpp index 9b96455..8e36c89 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -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 *filters = model->getFiltersReference(); + if (filters == NULL) return; + + ui->listFilters->clear(); + + if (filters->isEmpty()) return; + + QMap::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) diff --git a/mainwindow.h b/mainwindow.h index edf7c34..d6807d3 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -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? diff --git a/mainwindow.ui b/mainwindow.ui index 653f26b..736ee77 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -236,6 +236,35 @@ + + + + Frame Filtering: + + + + + + + + 0 + 0 + + + + + 0 + 160 + + + + + 175 + 16777215 + + + + @@ -273,8 +302,12 @@ File + + + + @@ -326,7 +359,7 @@ - Open Log File + Load Log File @@ -374,6 +407,21 @@ Preferences + + + Save Filtered Log File + + + + + Load Filter Definition + + + + + Save Filter Definition + +