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 + +