From e1eb1f9ab19bd192ed6e66199d21fbae67a5d2bd Mon Sep 17 00:00:00 2001 From: Collin Kidder Date: Sun, 23 Aug 2015 15:45:56 -0400 Subject: [PATCH] The main screen, flowview, and graphing screens are now linked. If you double click a frame on the main window or a graph in flowview or the graphing window the other two windows will update to show that data as well. --- canframemodel.cpp | 15 +++++++++++++ canframemodel.h | 1 + config.h | 2 +- flowviewwindow.cpp | 55 +++++++++++++++++++++++++++++++++++++++++++++- flowviewwindow.h | 6 +++++ graphingwindow.cpp | 34 +++++++++++++++++++++++++++- graphingwindow.h | 5 +++++ mainwindow.cpp | 41 ++++++++++++++++++++++++++++++++-- mainwindow.h | 5 ++++- 9 files changed, 158 insertions(+), 6 deletions(-) diff --git a/canframemodel.cpp b/canframemodel.cpp index 77bd88c..df8b713 100644 --- a/canframemodel.cpp +++ b/canframemodel.cpp @@ -398,6 +398,21 @@ void CANFrameModel::insertFrames(const QVector &newFrames) if (needFilterRefresh) emit updatedFiltersList(); } +int CANFrameModel::getIndexFromTimeID(int ID, double timestamp) +{ + int bestIndex = -1; + uint64_t intTimeStamp = timestamp * 1000000l; + for (int i = 0; i < frames.count(); i++) + { + if ((frames[i].ID == ID)) + { + if (frames[i].timestamp <= intTimeStamp) bestIndex = i; + else break; //drop out of loop as soon as we pass the proper timestamp + } + } + return bestIndex; +} + void CANFrameModel::loadFilterFile(QString filename) { QFile *inFile = new QFile(filename); diff --git a/canframemodel.h b/canframemodel.h index 34cafde..dee0651 100644 --- a/canframemodel.h +++ b/canframemodel.h @@ -41,6 +41,7 @@ public: void recalcOverwrite(); bool needsFilterRefresh(); void insertFrames(const QVector &newFrames); + int getIndexFromTimeID(int ID, double timestamp); const QVector *getListReference() const; //thou shalt not modify these frames externally! const QVector *getFilteredListReference() const; //Thus saith the Lord, NO. const QMap *getFiltersReference() const; //this neither diff --git a/config.h b/config.h index b78a991..78ef3db 100644 --- a/config.h +++ b/config.h @@ -1,7 +1,7 @@ #ifndef CONFIG #define CONFIG -#define VERSION 135 +#define VERSION 136 //try to keep this in sync. //SavvyCAN will complain if you connect a GVRET board with a revision diff --git a/flowviewwindow.cpp b/flowviewwindow.cpp index cc2406e..1a440fa 100644 --- a/flowviewwindow.cpp +++ b/flowviewwindow.cpp @@ -67,7 +67,8 @@ FlowViewWindow::FlowViewWindow(const QVector *frames, QWidget *parent) connect(ui->spinPlayback, SIGNAL(valueChanged(int)), this, SLOT(changePlaybackSpeed(int))); connect(ui->cbLoopPlayback, SIGNAL(clicked(bool)), this, SLOT(changeLooping(bool))); connect(ui->listFrameID, SIGNAL(currentTextChanged(QString)), this, SLOT(changeID(QString))); - connect(playbackTimer, SIGNAL(timeout()), this, SLOT(timerTriggered())); + connect(playbackTimer, SIGNAL(timeout()), this, SLOT(timerTriggered())); + connect(ui->graphView, SIGNAL(plottableDoubleClick(QCPAbstractPlottable*,QMouseEvent*)), this, SLOT(plottableDoubleClick(QCPAbstractPlottable*,QMouseEvent*))); connect(MainWindow::getReference(), SIGNAL(framesUpdated(int)), this, SLOT(updatedFrames(int))); @@ -143,6 +144,58 @@ void FlowViewWindow::writeSettings() } } +void FlowViewWindow::plottableDoubleClick(QCPAbstractPlottable* plottable, QMouseEvent* event) +{ + int id = 0; + //apply transforms to get the X axis value where we double clicked + double coord = plottable->keyAxis()->pixelToCoord(event->localPos().x()); + if (frameCache.count() > 0) id = frameCache[0].ID; + if (secondsMode) emit sendCenterTimeID(id, coord); + else emit sendCenterTimeID(id, coord / 1000000.0); +} + +void FlowViewWindow::gotCenterTimeID(int32_t ID, double timestamp) +{ + if (secondsMode) timestamp *= 1000000.0; //frames always store timestamp in microseconds + + qDebug() << "timestamp: " << timestamp; + + changeID(QString::number(ID)); //to be sure we're focused on the proper ID + + for (int j = 0; j < ui->listFrameID->count(); j++) + { + int thisNum = Utility::ParseStringToNum(ui->listFrameID->item(j)->text()); + if (thisNum == ID) + { + ui->listFrameID->setCurrentRow(j); + break; + } + } + + int bestIdx = -1; + for (int i = 0; i < frameCache.count(); i++) + { + if (frameCache[i].timestamp > timestamp) + { + bestIdx = i - 1; + break; + } + } + qDebug() << "Best index " << bestIdx; + if (bestIdx > -1) + { + currentPosition = bestIdx; + if (ui->cbAutoRef->isChecked()) + { + memcpy(refBytes, currBytes, 8); + } + + memcpy(currBytes, frameCache.at(currentPosition).data, 8); + + updateDataView(); + } +} + void FlowViewWindow::contextMenuRequestFlow(QPoint pos) { QMenu *menu = new QMenu(this); diff --git a/flowviewwindow.h b/flowviewwindow.h index 9c71e76..684c2aa 100644 --- a/flowviewwindow.h +++ b/flowviewwindow.h @@ -2,6 +2,7 @@ #define FLOWVIEWWINDOW_H #include +#include "qcustomplot.h" #include "can_structs.h" namespace Ui { @@ -33,6 +34,11 @@ private slots: void contextMenuRequestGraph(QPoint pos); void saveFileFlow(); void saveFileGraph(); + void plottableDoubleClick(QCPAbstractPlottable* plottable, QMouseEvent* event); + void gotCenterTimeID(int32_t ID, double timestamp); + +signals: + void sendCenterTimeID(int32_t ID, double timestamp); private: Ui::FlowViewWindow *ui; diff --git a/graphingwindow.cpp b/graphingwindow.cpp index e7fc013..f790375 100644 --- a/graphingwindow.cpp +++ b/graphingwindow.cpp @@ -45,6 +45,7 @@ GraphingWindow::GraphingWindow(DBCHandler *handler, const QVector *fra connect(ui->graphingView, SIGNAL(selectionChangedByUser()), this, SLOT(selectionChanged())); //connect up the mouse controls connect(ui->graphingView, SIGNAL(mousePress(QMouseEvent*)), this, SLOT(mousePress())); + connect(ui->graphingView, SIGNAL(plottableDoubleClick(QCPAbstractPlottable*,QMouseEvent*)), this, SLOT(plottableDoubleClick(QCPAbstractPlottable*,QMouseEvent*))); connect(ui->graphingView, SIGNAL(mouseWheel(QWheelEvent*)), this, SLOT(mouseWheel())); // make bottom and left axes transfer their ranges to top and right axes: @@ -152,6 +153,32 @@ void GraphingWindow::updatedFrames(int numFrames) } } +void GraphingWindow::plottableDoubleClick(QCPAbstractPlottable* plottable, QMouseEvent* event) +{ + int id = 0; + //apply transforms to get the X axis value where we double clicked + double coord = plottable->keyAxis()->pixelToCoord(event->localPos().x()); + id = plottable->property("id").toInt(); + if (secondsMode) emit sendCenterTimeID(id, coord); + else emit sendCenterTimeID(id, coord / 1000000.0); +} + +void GraphingWindow::gotCenterTimeID(int32_t ID, double timestamp) +{ + //its problematic to try to highlight a graph since we get the ID + //and timestamp not the signal in question so there is no real way + //to know which graph. But, if that changes here is a stub + //for (int i = 0; i < graphParams.count(); i++) + //{ + //} + + QCPRange range = ui->graphingView->xAxis->range(); + double offset = range.size() / 2.0; + if (!secondsMode) timestamp *= 1000000.0; //timestamp is always in seconds when being passed so convert if necessary + ui->graphingView->xAxis->setRange(timestamp - offset, timestamp + offset); + ui->graphingView->replot(); +} + void GraphingWindow::titleDoubleClick(QMouseEvent* event, QCPPlotTitle* title) { Q_UNUSED(event) @@ -802,6 +829,9 @@ void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam) } } + params.xbias = 0; + + /* for (int ct = 0; ct < params.x.count(); ct++) { params.x[ct] -= xminval; @@ -809,9 +839,10 @@ void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam) params.xbias = xminval; xmaxval -= xminval; xminval = 0; + */ ui->graphingView->addGraph(); - params.ref = ui->graphingView->graph(); + params.ref = ui->graphingView->graph(); if (createGraphParam) { graphParams.append(params); @@ -826,6 +857,7 @@ void GraphingWindow::createGraph(GraphParams ¶ms, bool createGraphParam) if ((params.endByte != -1) && (params.endByte != params.startByte)) params.graphName += "-" + QString::number(params.endByte); } ui->graphingView->graph()->setName(params.graphName); + ui->graphingView->graph()->setProperty("id", params.ID); ui->graphingView->graph()->setData(refParam->x,refParam->y); ui->graphingView->graph()->setLineStyle(QCPGraph::lsLine); //connect points with lines diff --git a/graphingwindow.h b/graphingwindow.h index 59ce32d..f59c31e 100644 --- a/graphingwindow.h +++ b/graphingwindow.h @@ -42,6 +42,7 @@ private slots: void titleDoubleClick(QMouseEvent *event, QCPPlotTitle *title); void axisLabelDoubleClick(QCPAxis* axis, QCPAxis::SelectablePart part); void legendDoubleClick(QCPLegend* legend, QCPAbstractLegendItem* item); + void plottableDoubleClick(QCPAbstractPlottable* plottable,QMouseEvent* event); void selectionChanged(); void mousePress(); void mouseWheel(); @@ -57,6 +58,10 @@ private slots: void appendToGraph(GraphParams ¶ms, CANFrame &frame); void editSelectedGraph(); void updatedFrames(int); + void gotCenterTimeID(int32_t ID, double timestamp); + +signals: + void sendCenterTimeID(int32_t ID, double timestamp); private: Ui::GraphingWindow *ui; diff --git a/mainwindow.cpp b/mainwindow.cpp index 204cec9..fe17f50 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -126,6 +126,7 @@ MainWindow::MainWindow(QWidget *parent) : connect(ui->actionLoad_DBC_File, SIGNAL(triggered(bool)), this, SLOT(handleLoadDBC())); connect(ui->actionSave_DBC_File, SIGNAL(triggered(bool)), this, SLOT(handleSaveDBC())); connect(ui->canFramesView, SIGNAL(clicked(QModelIndex)), this, SLOT(gridClicked(QModelIndex))); + connect(ui->canFramesView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(gridDoubleClicked(QModelIndex))); connect(ui->cbInterpret, SIGNAL(toggled(bool)), this, SLOT(interpretToggled(bool))); connect(ui->cbOverwrite, SIGNAL(toggled(bool)), this, SLOT(overwriteToggled(bool))); connect(ui->actionEdit_Messages_Signals, SIGNAL(triggered(bool)), this, SLOT(showDBCEditor())); @@ -263,7 +264,8 @@ void MainWindow::readUpdateableSettings() useHex = settings.value("Main/UseHex", true).toBool(); model->setHexMode(useHex); Utility::decimalMode = !useHex; - model->setSecondsMode(settings.value("Main/TimeSeconds", false).toBool()); + secondsMode = settings.value("Main/TimeSeconds", false).toBool(); + model->setSecondsMode(secondsMode); useFiltered = settings.value("Main/UseFiltered", false).toBool(); } @@ -289,6 +291,13 @@ void MainWindow::gridClicked(QModelIndex idx) } } +void MainWindow::gridDoubleClicked(QModelIndex idx) +{ + //grab ID and timestamp and send them away + CANFrame frame = model->getListReference()->at(idx.row()); + emit sendCenterTimeID(frame.ID, frame.timestamp / 1000000.0); +} + void MainWindow::interpretToggled(bool state) { model->setInterpetMode(state); @@ -383,6 +392,17 @@ void MainWindow::addFrameToDisplay(CANFrame &frame, bool autoRefresh = false) } } +//A sub-window is sending us a center on timestamp and ID signal +//try to find the relevant frame in the list and focus on it. +void MainWindow::gotCenterTimeID(int32_t ID, double timestamp) +{ + int idx = model->getIndexFromTimeID(ID, timestamp); + if (idx > -1) + { + ui->canFramesView->selectRow(idx); + } +} + void MainWindow::clearFrames() { ui->canFramesView->scrollToTop(); @@ -397,6 +417,7 @@ void MainWindow::clearFrames() void MainWindow::normalizeTiming() { model->normalizeTiming(); + emit framesUpdated(-2); //claim an all new set of frames because every frame was updated. } void MainWindow::changeBaudRates() @@ -900,6 +921,14 @@ void MainWindow::showGraphingWindow() { if (!graphingWindow) { graphingWindow = new GraphingWindow(dbcHandler, model->getListReference()); + connect(graphingWindow, SIGNAL(sendCenterTimeID(int32_t,double)), this, SLOT(gotCenterTimeID(int32_t,double))); + connect(this, SIGNAL(sendCenterTimeID(int32_t,double)), graphingWindow, SLOT(gotCenterTimeID(int32_t,double))); + } + + if (flowViewWindow) //connect the two external windows together + { + connect(graphingWindow, SIGNAL(sendCenterTimeID(int32_t,double)), flowViewWindow, SLOT(gotCenterTimeID(int32_t,double))); + connect(flowViewWindow, SIGNAL(sendCenterTimeID(int32_t,double)), graphingWindow, SLOT(gotCenterTimeID(int32_t,double))); } graphingWindow->show(); } @@ -987,11 +1016,19 @@ void MainWindow::showFlowViewWindow() flowViewWindow = new FlowViewWindow(model->getListReference()); else flowViewWindow = new FlowViewWindow(model->getFilteredListReference()); + connect(flowViewWindow, SIGNAL(sendCenterTimeID(int32_t,double)), this, SLOT(gotCenterTimeID(int32_t,double))); + connect(this, SIGNAL(sendCenterTimeID(int32_t,double)), flowViewWindow, SLOT(gotCenterTimeID(int32_t,double))); } + + if (graphingWindow) + { + connect(graphingWindow, SIGNAL(sendCenterTimeID(int32_t,double)), flowViewWindow, SLOT(gotCenterTimeID(int32_t,double))); + connect(flowViewWindow, SIGNAL(sendCenterTimeID(int32_t,double)), graphingWindow, SLOT(gotCenterTimeID(int32_t,double))); + } + flowViewWindow->show(); } - //this one always gets the unfiltered list intentionally. void MainWindow::showDBCEditor() { diff --git a/mainwindow.h b/mainwindow.h index c201eae..6d7ea61 100644 --- a/mainwindow.h +++ b/mainwindow.h @@ -59,6 +59,7 @@ private slots: void gotDeviceInfo(int, int); void connectionSucceeded(int, int); void gridClicked(QModelIndex); + void gridDoubleClicked(QModelIndex); void interpretToggled(bool); void overwriteToggled(bool); void showDBCEditor(); @@ -72,7 +73,7 @@ private slots: public slots: void gotFrames(int, int); void updateSettings(); - + void gotCenterTimeID(int32_t ID, double timestamp); signals: void sendSerialPort(QSerialPortInfo *port); @@ -85,6 +86,7 @@ signals: //-1 = frames cleared, -2 = a new file has been loaded (so all frames are different), otherwise # of new frames void framesUpdated(int numFrames); //something has updated the frame list void settingsUpdated(); + void sendCenterTimeID(int32_t ID, double timestamp); private: Ui::MainWindow *ui; @@ -100,6 +102,7 @@ private: bool inhibitFilterUpdate; bool useHex; bool allowCapture; + bool secondsMode; bool bDirty; //have frames been added or subtracted since the last save/load? bool useFiltered; //should sub-windows use the unfiltered or filtered frames list?