Add tracking of DBC editing in order to warn when exiting without saving, add sorting to DBC routines, add a new screen that allows one to compare two DBC files for changes/differences.

This commit is contained in:
Collin Kidder
2020-07-29 20:45:36 -04:00
parent 4cfb4b903a
commit a5b7410629
14 changed files with 738 additions and 13 deletions
+5 -2
View File
@@ -15,7 +15,8 @@ DEFINES += QCUSTOMPLOT_USE_OPENGL
TARGET = SavvyCAN
TEMPLATE = app
SOURCES += main.cpp\
SOURCES += main.cpp\
re/dbccomparatorwindow.cpp \
mainwindow.cpp \
canframemodel.cpp \
utility.cpp \
@@ -75,7 +76,8 @@ SOURCES += main.cpp\
HEADERS += mainwindow.h \
can_structs.h \
canframemodel.h \
canframemodel.h \ \
re/dbccomparatorwindow.h \
utility.h \
qcustomplot.h \
frameplaybackwindow.h \
@@ -136,6 +138,7 @@ HEADERS += mainwindow.h \
filterutility.h
FORMS += ui/candatagrid.ui \
ui/dbccomparatorwindow.ui \
ui/dbcmessageeditor.ui \
ui/connectionwindow.ui \
ui/dbcloadsavewindow.ui \
+15
View File
@@ -74,6 +74,11 @@ public:
DBC_ATTRIBUTE_VALUE *findAttrValByName(QString name);
DBC_ATTRIBUTE_VALUE *findAttrValByIdx(int idx);
friend bool operator<(const DBC_NODE& l, const DBC_NODE& r)
{
return (l.name.toLower() < r.name.toLower());
}
};
class DBC_MESSAGE; //forward reference so that DBC_SIGNAL can compile before we get to real definition of DBC_MESSAGE
@@ -107,6 +112,11 @@ public: //TODO: this is sloppy. It shouldn't all be public!
QString makePrettyOutput(double floatVal, int64_t intVal, bool outputName = true);
DBC_ATTRIBUTE_VALUE *findAttrValByName(QString name);
DBC_ATTRIBUTE_VALUE *findAttrValByIdx(int idx);
friend bool operator<(const DBC_SIGNAL& l, const DBC_SIGNAL& r)
{
return (l.name.toLower() < r.name.toLower());
}
};
class DBCSignalHandler; //forward declaration to keep from having to include dbchandler.h in this file and thus create a loop
@@ -129,6 +139,11 @@ public:
DBC_ATTRIBUTE_VALUE *findAttrValByName(QString name);
DBC_ATTRIBUTE_VALUE *findAttrValByIdx(int idx);
friend bool operator<(const DBC_MESSAGE& l, const DBC_MESSAGE& r)
{
return (l.name.toLower() < r.name.toLower());
}
};
+48 -1
View File
@@ -92,6 +92,11 @@ int DBCSignalHandler::getCount()
return sigs.count();
}
void DBCSignalHandler::sort()
{
std::sort(sigs.begin(), sigs.end());
}
DBC_MESSAGE* DBCMessageHandler::findMsgByID(uint32_t id)
{
if (messages.count() == 0) return nullptr;
@@ -241,6 +246,15 @@ int DBCMessageHandler::getCount()
return messages.count();
}
void DBCMessageHandler::sort()
{
std::sort(messages.begin(), messages.end());
for (int i = 0; i < messages.count(); i++)
{
messages[i].sigHandler->sort();
}
}
bool DBCMessageHandler::filterLabeling()
{
return filterLabelingEnabled;
@@ -266,6 +280,7 @@ DBCFile::DBCFile()
messageHandler = new DBCMessageHandler;
messageHandler->setMatchingCriteria(EXACT);
messageHandler->setFilterLabeling(false);
isDirty = false;
}
DBCFile::DBCFile(const DBCFile& cpy) : QObject()
@@ -283,6 +298,7 @@ DBCFile::DBCFile(const DBCFile& cpy) : QObject()
dbc_nodes.append(cpy.dbc_nodes);
dbc_attributes.clear();
dbc_attributes.append(cpy.dbc_attributes);
isDirty = cpy.isDirty;
}
DBCFile& DBCFile::operator=(const DBCFile& cpy)
@@ -301,6 +317,12 @@ DBCFile& DBCFile::operator=(const DBCFile& cpy)
return *this;
}
void DBCFile::sort()
{
std::sort(dbc_nodes.begin(), dbc_nodes.end()); //sort node names
messageHandler->sort(); //sort messages, each of which sorts its signals too
}
DBC_NODE* DBCFile::findNodeByIdx(int idx)
{
if (idx < 0) return nullptr;
@@ -380,6 +402,17 @@ void DBCFile::findAttributesByType(DBC_ATTRIBUTE_TYPE typ, QList<DBC_ATTRIBUTE>
}
}
//there's no external way to clear the flag. It is only cleared when the file is saved by this object.
void DBCFile::setDirtyFlag()
{
isDirty = true;
}
bool DBCFile::getDirtyFlag()
{
return isDirty;
}
DBC_MESSAGE* DBCFile::parseMessageLine(QString line)
{
QRegularExpression regex;
@@ -735,6 +768,7 @@ void DBCFile::loadFile(QString fileName)
DBC_MESSAGE *currentMessage = nullptr;
DBC_ATTRIBUTE attr;
int numSigFaults = 0, numMsgFaults = 0;
int linesSinceYield = 0;
bool inMultilineBU = false;
@@ -761,6 +795,12 @@ void DBCFile::loadFile(QString fileName)
rawLine = QString(inFile->readLine());
line = rawLine.simplified();
linesSinceYield++;
if (linesSinceYield > 100)
{
qApp->processEvents();
}
if (inMultilineBU)
{
if (rawLine.startsWith("\t") || rawLine.startsWith(" "))
@@ -998,6 +1038,7 @@ void DBCFile::loadFile(QString fileName)
this->fileName = fileList[fileList.length() - 1]; //whoops... same name as parameter in this function.
filePath = fileName.left(fileName.length() - this->fileName.length());
assocBuses = -1;
isDirty = false;
}
QVariant DBCFile::processAttributeVal(QString input, DBC_ATTRIBUTE_VAL_TYPE typ)
@@ -1214,7 +1255,10 @@ void DBCFile::saveFile(QString fileName)
msgNumber++;
}
msgOutput.append("BO_ " + QString::number(msg->ID) + " " + msg->name + ": " + QString::number(msg->len) +
uint32_t ID = msg->ID;
if (msg->ID > 0x7FF) msg->ID += 0x80000000ul; //set bit 31 if this ID is extended.
msgOutput.append("BO_ " + QString::number(ID) + " " + msg->name + ": " + QString::number(msg->len) +
" " + msg->sender->name + "\n");
if (msg->comment.length() > 0)
{
@@ -1405,6 +1449,8 @@ void DBCFile::saveFile(QString fileName)
outFile->close();
delete outFile;
isDirty = false;
QStringList fileList = fileName.split('/');
this->fileName = fileList[fileList.length() - 1]; //whoops... same name as parameter in this function.
filePath = fileName.left(fileName.length() - this->fileName.length());
@@ -1681,6 +1727,7 @@ DBCFile* DBCHandler::loadJSONFile(QString filename)
}
}
}
thisFile->setDirtyFlag();
return thisFile;
}
+8
View File
@@ -29,6 +29,8 @@ public:
bool removeSignal(QString name);
void removeAllSignals();
int getCount();
void sort();
private:
QList<DBC_SIGNAL> sigs; //signals is a reserved word or I'd have used that
};
@@ -52,6 +54,8 @@ public:
void setMatchingCriteria(MatchingCriteria_t mc);
void setFilterLabeling( bool labelFiltering );
bool filterLabeling();
void sort();
private:
QList<DBC_MESSAGE> messages;
MatchingCriteria_t matchingCriteria;
@@ -79,6 +83,9 @@ public:
QString getPath();
int getAssocBus();
void setAssocBus(int bus);
void setDirtyFlag();
bool getDirtyFlag();
void sort();
DBCMessageHandler *messageHandler;
QList<DBC_NODE> dbc_nodes;
@@ -87,6 +94,7 @@ private:
QString fileName;
QString filePath;
int assocBuses; //-1 = all buses, 0 = first bus, 1 = second bus, etc.
bool isDirty; //has the file been modified?
bool parseAttribute(QString inpString, DBC_ATTRIBUTE &attr);
QVariant processAttributeVal(QString input, DBC_ATTRIBUTE_VAL_TYPE typ);
+6 -2
View File
@@ -399,6 +399,7 @@ void DBCMainEditor::newNode()
itemToNode.insert(nodeItem, nodePtr);
ui->treeDBC->addTopLevelItem(nodeItem);
ui->treeDBC->setCurrentItem(nodeItem);
dbcFile->setDirtyFlag();
}
@@ -465,6 +466,7 @@ void DBCMainEditor::newMessage()
itemToMessage.insert(newMsgItem, msgPtr);
nodeItem->addChild(newMsgItem);
ui->treeDBC->setCurrentItem(newMsgItem);
dbcFile->setDirtyFlag();
}
void DBCMainEditor::newSignal()
@@ -519,7 +521,7 @@ void DBCMainEditor::newSignal()
itemToSignal.insert(newSigItem, sigPtr);
msgItem->addChild(newSigItem);
ui->treeDBC->setCurrentItem(newSigItem);
dbcFile->setDirtyFlag();
}
//gets confirmation before calling the real routines that delete things
@@ -628,6 +630,7 @@ void DBCMainEditor::deleteNode(DBC_NODE *node)
itemToNode.remove(currItem);
ui->treeDBC->removeItemWidget(currItem, 0);
delete currItem;
dbcFile->setDirtyFlag();
}
void DBCMainEditor::deleteMessage(DBC_MESSAGE *msg)
@@ -648,7 +651,7 @@ void DBCMainEditor::deleteMessage(DBC_MESSAGE *msg)
messageToItem.remove(msg);
ui->treeDBC->removeItemWidget(currItem, 0);
delete currItem;
dbcFile->setDirtyFlag();
}
void DBCMainEditor::deleteSignal(DBC_SIGNAL *sig)
@@ -662,4 +665,5 @@ void DBCMainEditor::deleteSignal(DBC_SIGNAL *sig)
signalToItem.remove(sig);
ui->treeDBC->removeItemWidget(currItem, 0);
delete currItem;
dbcFile->setDirtyFlag();
}
+6 -2
View File
@@ -22,6 +22,7 @@ DBCMessageEditor::DBCMessageEditor(QWidget *parent) :
[=]()
{
if (dbcMessage == nullptr) return;
if (dbcMessage->comment != ui->lineComment->text()) dbcFile->setDirtyFlag();
dbcMessage->comment = ui->lineComment->text();
emit updatedTreeInfo(dbcMessage);
});
@@ -30,6 +31,7 @@ DBCMessageEditor::DBCMessageEditor(QWidget *parent) :
[=]()
{
if (dbcMessage == nullptr) return;
if (dbcMessage->ID != Utility::ParseStringToNum(ui->lineFrameID->text())) dbcFile->setDirtyFlag();
dbcMessage->ID = Utility::ParseStringToNum(ui->lineFrameID->text());
emit updatedTreeInfo(dbcMessage);
});
@@ -38,6 +40,7 @@ DBCMessageEditor::DBCMessageEditor(QWidget *parent) :
[=]()
{
if (dbcMessage == nullptr) return;
if (dbcMessage->name != ui->lineMsgName->text().simplified().replace(' ', '_')) dbcFile->setDirtyFlag();
dbcMessage->name = ui->lineMsgName->text().simplified().replace(' ', '_');
emit updatedTreeInfo(dbcMessage);
});
@@ -46,6 +49,7 @@ DBCMessageEditor::DBCMessageEditor(QWidget *parent) :
[=]()
{
if (dbcMessage == nullptr) return;
if (dbcMessage->len != Utility::ParseStringToNum(ui->lineFrameLen->text())) dbcFile->setDirtyFlag();
dbcMessage->len = Utility::ParseStringToNum(ui->lineFrameLen->text());
});
@@ -53,7 +57,7 @@ DBCMessageEditor::DBCMessageEditor(QWidget *parent) :
[=]()
{
QColor newColor = QColorDialog::getColor(dbcMessage->fgColor);
if (dbcMessage->fgColor != newColor) dbcFile->setDirtyFlag();
dbcMessage->fgColor = newColor;
DBC_ATTRIBUTE_VALUE *val = dbcMessage->findAttrValByName("GenMsgForegroundColor");
if (val)
@@ -74,7 +78,7 @@ DBCMessageEditor::DBCMessageEditor(QWidget *parent) :
[=]()
{
QColor newColor = QColorDialog::getColor(dbcMessage->bgColor);
if (dbcMessage->bgColor != newColor) dbcFile->setDirtyFlag();
dbcMessage->bgColor = newColor;
DBC_ATTRIBUTE_VALUE *val = dbcMessage->findAttrValByName("GenMsgBackgroundColor");
if (val)
+2
View File
@@ -22,6 +22,7 @@ DBCNodeEditor::DBCNodeEditor(QWidget *parent) :
[=]()
{
if (dbcNode == nullptr) return;
if (dbcNode->comment != ui->lineComment->text()) dbcFile->setDirtyFlag();
dbcNode->comment = ui->lineComment->text();
emit updatedTreeInfo(dbcNode);
});
@@ -30,6 +31,7 @@ DBCNodeEditor::DBCNodeEditor(QWidget *parent) :
[=]()
{
if (dbcNode == nullptr) return;
if (dbcNode->name != ui->lineMsgName->text()) dbcFile->setDirtyFlag();
dbcNode->name = ui->lineMsgName->text();
emit updatedTreeInfo(dbcNode);
});
+33 -5
View File
@@ -44,6 +44,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
[=]()
{
if (currentSignal == nullptr) return;
if (currentSignal->intelByteOrder != ui->cbIntelFormat->isChecked()) dbcFile->setDirtyFlag();
currentSignal->intelByteOrder = ui->cbIntelFormat->isChecked();
fillSignalForm(currentSignal);
});
@@ -52,7 +53,9 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
[=]()
{
if (currentSignal == nullptr) return;
currentSignal->receiver = dbcFile->findNodeByName(ui->comboReceiver->currentText());
DBC_NODE *node = dbcFile->findNodeByName(ui->comboReceiver->currentText());
if (currentSignal->receiver != node) dbcFile->setDirtyFlag();
currentSignal->receiver = node;
});
connect(ui->comboType, &QComboBox::currentTextChanged,
[=]()
@@ -80,6 +83,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
currentSignal->valType = STRING;
break;
}
dbcFile->setDirtyFlag();
fillSignalForm(currentSignal);
});
connect(ui->txtBias, &QLineEdit::editingFinished,
@@ -89,7 +93,11 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
double temp;
bool result;
temp = ui->txtBias->text().toDouble(&result);
if (result) currentSignal->bias = temp;
if (result)
{
if (currentSignal->bias != temp) dbcFile->setDirtyFlag();
currentSignal->bias = temp;
}
});
connect(ui->txtMaxVal, &QLineEdit::editingFinished,
@@ -99,7 +107,11 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
double temp;
bool result;
temp = ui->txtMaxVal->text().toDouble(&result);
if (result) currentSignal->max = temp;
if (result)
{
if (currentSignal->max != temp) dbcFile->setDirtyFlag();
currentSignal->max = temp;
}
});
connect(ui->txtMinVal, &QLineEdit::editingFinished,
@@ -109,7 +121,11 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
double temp;
bool result;
temp = ui->txtMinVal->text().toDouble(&result);
if (result) currentSignal->min = temp;
if (result)
{
if (currentSignal->min != temp) dbcFile->setDirtyFlag();
currentSignal->min = temp;
}
});
connect(ui->txtScale, &QLineEdit::editingFinished,
[=]()
@@ -118,12 +134,17 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
double temp;
bool result;
temp = ui->txtScale->text().toDouble(&result);
if (result) currentSignal->factor = temp;
if (result)
{
if (currentSignal->factor != temp) dbcFile->setDirtyFlag();
currentSignal->factor = temp;
}
});
connect(ui->txtComment, &QLineEdit::editingFinished,
[=]()
{
if (currentSignal == nullptr) return;
if (currentSignal->comment != ui->txtComment->text().simplified().replace(' ','_')) dbcFile->setDirtyFlag();
currentSignal->comment = ui->txtComment->text().simplified().replace(' ', '_');
emit updatedTreeInfo(currentSignal);
});
@@ -132,6 +153,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
[=]()
{
if (currentSignal == nullptr) return;
if (currentSignal->unitName != ui->txtUnitName->text().simplified().replace(' ','_')) dbcFile->setDirtyFlag();
currentSignal->unitName = ui->txtUnitName->text().simplified().replace(' ', '_');
});
connect(ui->txtBitLength, &QLineEdit::textChanged,
@@ -142,6 +164,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
temp = Utility::ParseStringToNum(ui->txtBitLength->text());
if (temp < 1) return;
if (temp > 64) return;
if (currentSignal->signalSize != temp) dbcFile->setDirtyFlag();
if (currentSignal->valType != SP_FLOAT && currentSignal->valType != DP_FLOAT)
currentSignal->signalSize = temp;
fillSignalForm(currentSignal);
@@ -151,6 +174,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
{
if (currentSignal == nullptr) return;
QString tempNameStr = ui->txtName->text().simplified().replace(' ', '_');
if (currentSignal->name != tempNameStr) dbcFile->setDirtyFlag();
if (tempNameStr.length() > 0) currentSignal->name = tempNameStr;
//need to update the tree too.
emit updatedTreeInfo(currentSignal);
@@ -162,6 +186,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
if (currentSignal == nullptr) return;
int temp;
temp = Utility::ParseStringToNum(ui->txtMultiplexValue->text());
if (currentSignal->multiplexValue != temp) dbcFile->setDirtyFlag();
//TODO: could look up the multiplexor and ensure that the value is within a range that the multiplexor could return
currentSignal->multiplexValue = temp;
});
@@ -175,6 +200,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
//if the set multiplexor for the message was this signal then clear it
if (dbcMessage->multiplexorSignal == currentSignal) dbcMessage->multiplexorSignal = nullptr;
}
dbcFile->setDirtyFlag();
});
connect(ui->rbMultiplexor, &QRadioButton::toggled,
@@ -189,6 +215,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
//we just set that this is the multiplexor so update the message to show that as well.
dbcMessage->multiplexorSignal = currentSignal;
}
dbcFile->setDirtyFlag();
});
connect(ui->rbNotMulti, &QRadioButton::toggled,
@@ -200,6 +227,7 @@ DBCSignalEditor::DBCSignalEditor(QWidget *parent) :
currentSignal->isMultiplexor = false;
if (dbcMessage->multiplexorSignal == currentSignal) dbcMessage->multiplexorSignal = nullptr;
}
dbcFile->setDirtyFlag();
});
installEventFilter(this);
+31 -1
View File
@@ -80,6 +80,7 @@ MainWindow::MainWindow(QWidget *parent) :
bisectWindow = nullptr;
signalViewerWindow = nullptr;
temporalGraphWindow = nullptr;
dbcComparatorWindow = nullptr;
dbcHandler = DBCHandler::getReference();
bDirty = false;
inhibitFilterUpdate = false;
@@ -111,6 +112,7 @@ MainWindow::MainWindow(QWidget *parent) :
connect(ui->actionSave_Decoded_Frames, &QAction::triggered, this, &MainWindow::handleSaveDecoded);
connect(ui->actionSingle_Multi_State_2, &QAction::triggered, this, &MainWindow::showSingleMultiWindow);
connect(ui->actionFile_Comparison, &QAction::triggered, this, &MainWindow::showComparisonWindow);
connect(ui->actionDBC_Comparison, &QAction::triggered, this, &MainWindow::showDBCComparisonWindow);
connect(ui->actionScripting_INterface, &QAction::triggered, this, &MainWindow::showScriptingWindow);
connect(ui->btnNormalize, &QAbstractButton::clicked, this, &MainWindow::normalizeTiming);
connect(ui->actionPreferences, &QAction::triggered, this, &MainWindow::showSettingsDialog);
@@ -257,12 +259,31 @@ void MainWindow::exitApp()
QApplication::quit(); //forces the whole application to terminate when the main window is closed
}
//the close event can be trapped and ignored so put unsaved warnings in here so the user can abort the program closing if they forgot to save things.
void MainWindow::closeEvent(QCloseEvent *event)
{
Q_UNUSED(event);
QMessageBox::StandardButton confirmDialog;
for (int i = 0; i < dbcHandler->getFileCount(); i++)
{
DBCFile *file = dbcHandler->getFileByIdx(i);
if (file->getDirtyFlag())
{
confirmDialog = QMessageBox::question(this, "Unsaved DBC", "DBC File:\n" + file->getFilename() + "\nAppears to have unsaved changes\nReally close without saving?", QMessageBox::Yes|QMessageBox::No);
if (confirmDialog != QMessageBox::Yes)
{
event->ignore();
return;
}
}
}
removeEventFilter(this);
writeSettings();
exitApp();
event->accept();
}
bool MainWindow::eventFilter(QObject *obj, QEvent *event)
@@ -1001,6 +1022,15 @@ void MainWindow::showComparisonWindow()
comparatorWindow->show();
}
void MainWindow::showDBCComparisonWindow()
{
if (!dbcComparatorWindow)
{
dbcComparatorWindow = new DBCComparatorWindow();
}
dbcComparatorWindow->show();
}
void MainWindow::showSingleMultiWindow()
{
if (!discreteStateWindow)
+3
View File
@@ -32,6 +32,7 @@
#include "motorcontrollerconfigwindow.h"
#include "signalviewerwindow.h"
#include "re/temporalgraphwindow.h"
#include "re/dbccomparatorwindow.h"
class CANConnection;
class ConnectionWindow;
@@ -85,6 +86,7 @@ private slots:
void showBisectWindow();
void showSignalViewer();
void showTemporalGraphWindow();
void showDBCComparisonWindow();
void exitApp();
void handleSaveDecoded();
void connectionStatusUpdated(int conns);
@@ -165,6 +167,7 @@ private:
BisectWindow* bisectWindow;
SignalViewerWindow *signalViewerWindow;
TemporalGraphWindow *temporalGraphWindow;
DBCComparatorWindow *dbcComparatorWindow;
//various private storage
QLabel lbStatusConnected;
+399
View File
@@ -0,0 +1,399 @@
#include "dbccomparatorwindow.h"
#include "ui_dbccomparatorwindow.h"
#include "helpwindow.h"
#include <QProgressDialog>
#include <QSettings>
#include <qevent.h>
DBCComparatorWindow::DBCComparatorWindow(QWidget *parent) :
QDialog(parent),
ui(new Ui::DBCComparatorWindow)
{
ui->setupUi(this);
setWindowFlags(Qt::Window);
connect(ui->btnDBCFile1, SIGNAL(clicked(bool)), this, SLOT(loadFirstFile()));
connect(ui->btnDBCFile2, SIGNAL(clicked(bool)), this, SLOT(loadSecondFile()));
connect(ui->btnSaveDetails, SIGNAL(clicked(bool)), this, SLOT(saveDetails()));
ui->lblFirstFile->setText("");
ui->lblSecondFile->setText("");
firstDBC = nullptr;
secondDBC = nullptr;
installEventFilter(this);
}
DBCComparatorWindow::~DBCComparatorWindow()
{
removeEventFilter(this);
delete ui;
}
void DBCComparatorWindow::showEvent(QShowEvent *)
{
readSettings();
}
void DBCComparatorWindow::closeEvent(QCloseEvent *event)
{
Q_UNUSED(event)
writeSettings();
}
bool DBCComparatorWindow::eventFilter(QObject *obj, QEvent *event)
{
if (event->type() == QEvent::KeyRelease) {
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
switch (keyEvent->key())
{
case Qt::Key_F1:
HelpWindow::getRef()->showHelp("filecomparison.html");
break;
}
return true;
} else {
// standard event processing
return QObject::eventFilter(obj, event);
}
return false;
}
void DBCComparatorWindow::readSettings()
{
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
resize(settings.value("DBCComparator/WindowSize", QSize(720, 631)).toSize());
move(settings.value("DBCComparator/WindowPos", QPoint(50, 50)).toPoint());
}
}
void DBCComparatorWindow::writeSettings()
{
QSettings settings;
if (settings.value("Main/SaveRestorePositions", false).toBool())
{
settings.setValue("DBCComparator/WindowSize", size());
settings.setValue("DBCComparator/WindowPos", pos());
}
}
QString DBCComparatorWindow::loadDBC(DBCFile **file)
{
QString filename;
QFileDialog dialog;
QSettings settings;
QStringList filters;
filters.append(QString(tr("DBC Files (*.dbc *.DBC)")));
dialog.setDirectory(settings.value("FileIO/LoadSaveDirectory", dialog.directory().path()).toString());
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
if (dialog.exec() == QDialog::Accepted)
{
filename = dialog.selectedFiles()[0];
QProgressDialog progress(qApp->activeWindow());
progress.setWindowModality(Qt::WindowModal);
progress.setLabelText("Loading file...");
progress.setCancelButton(nullptr);
progress.setRange(0,0);
progress.setMinimumDuration(0);
progress.show();
qApp->processEvents();
if (dialog.selectedNameFilter() == filters[0])
{
if (file[0]) delete file[0];
file[0] = new DBCFile;
file[0]->loadFile(filename);
qDebug() << "Loaded the DBC file into first slot";
}
progress.cancel();
return filename;
}
return QString();
}
void DBCComparatorWindow::loadFirstFile()
{
QString filename;
filename = loadDBC(&firstDBC);
ui->lblFirstFile->setText(filename);
if (firstDBC && secondDBC) calculateDetails();
}
void DBCComparatorWindow::loadSecondFile()
{
QString filename;
filename = loadDBC(&secondDBC);
ui->lblSecondFile->setText(filename);
if (firstDBC && secondDBC) calculateDetails();
}
void DBCComparatorWindow::calculateDetails()
{
QProgressDialog progress(this);
progress.setWindowModality(Qt::WindowModal);
progress.setLabelText("Calculating differences");
progress.setCancelButton(nullptr);
progress.setRange(0,0);
progress.setMinimumDuration(0);
progress.show();
qApp->processEvents();
firstDBC->sort();
secondDBC->sort();
ui->treeDetails->clear();
//Find nodes missing in one of the DBC files
QTreeWidgetItem *nodeDiffRoot = new QTreeWidgetItem();
nodeDiffRoot->setText(0, "Node Differences");
QTreeWidgetItem *nodesMissingDBCFirst = new QTreeWidgetItem();
nodesMissingDBCFirst->setText(0, "Nodes not found in first DBC");
QTreeWidgetItem *nodesMissingDBCSecond = new QTreeWidgetItem();
nodesMissingDBCSecond->setText(0, "Nodes not found in second DBC");
nodeDiffRoot->addChild(nodesMissingDBCFirst);
nodeDiffRoot->addChild(nodesMissingDBCSecond);
ui->treeDetails->addTopLevelItem(nodeDiffRoot);
for (int i = 0; i < firstDBC->dbc_nodes.count(); i++)
{
QString nodeName = firstDBC->dbc_nodes[i].name;
DBC_NODE *node = secondDBC->findNodeByName(nodeName);
if (!node)
{
QTreeWidgetItem *missingNodeItem = new QTreeWidgetItem();
missingNodeItem->setText(0, nodeName);
nodesMissingDBCSecond->addChild(missingNodeItem);
}
}
for (int i = 0; i < secondDBC->dbc_nodes.count(); i++)
{
QString nodeName = secondDBC->dbc_nodes[i].name;
DBC_NODE *node = firstDBC->findNodeByName(nodeName);
if (!node)
{
QTreeWidgetItem *missingNodeItem = new QTreeWidgetItem();
missingNodeItem->setText(0, nodeName);
nodesMissingDBCFirst->addChild(missingNodeItem);
}
}
//Find messages that are missing in one of the DBC files
//If a message exists in both then check for missing signals
QTreeWidgetItem *msgDiffRoot = new QTreeWidgetItem();
msgDiffRoot->setText(0, "Message Differences");
QTreeWidgetItem *msgMissingDBCFirst = new QTreeWidgetItem();
msgMissingDBCFirst->setText(0, "Messages not found in first DBC");
QTreeWidgetItem *msgMissingDBCSecond = new QTreeWidgetItem();
msgMissingDBCSecond->setText(0, "Messages not found in second DBC");
QTreeWidgetItem *msgSignalsDiff = new QTreeWidgetItem();
msgSignalsDiff->setText(0, "Messages with missing signals");
QTreeWidgetItem *sigDiffOne = new QTreeWidgetItem();
sigDiffOne->setText(0, "Missing from first DBC");
QTreeWidgetItem *sigDiffTwo = new QTreeWidgetItem();
sigDiffTwo->setText(0, "Missing from second DBC");
QTreeWidgetItem *sigModifiedRoot = new QTreeWidgetItem();
sigModifiedRoot->setText(0, "Modified Signals");
msgSignalsDiff->addChild(sigDiffOne);
msgSignalsDiff->addChild(sigDiffTwo);
msgDiffRoot->addChild(msgMissingDBCFirst);
msgDiffRoot->addChild(msgMissingDBCSecond);
msgDiffRoot->addChild(msgSignalsDiff);
msgDiffRoot->addChild(sigModifiedRoot);
ui->treeDetails->addTopLevelItem(msgDiffRoot);
QTreeWidgetItem *msgItem;
QTreeWidgetItem *sigTemp;
for (int i = 0; i < firstDBC->messageHandler->getCount(); i++)
{
DBC_MESSAGE *thisMsg = firstDBC->messageHandler->findMsgByIdx(i);
QString msgName = thisMsg->name;
DBC_MESSAGE *otherMsg = secondDBC->messageHandler->findMsgByName(msgName);
if (!otherMsg)
{
QTreeWidgetItem *missingMsgItem = new QTreeWidgetItem();
missingMsgItem->setText(0, msgName);
msgMissingDBCSecond->addChild(missingMsgItem);
}
else //both have Msg. Check sigs for missing
{
bool thisMsgHasMissing = false;
bool thisMsgHasMods = false;
for (int i = 0; i < thisMsg->sigHandler->getCount(); i++)
{
DBC_SIGNAL *thisSig = thisMsg->sigHandler->findSignalByIdx(i);
QString sigName = thisSig->name;
DBC_SIGNAL *otherSig = otherMsg->sigHandler->findSignalByName(sigName);
if (!otherSig)
{
QTreeWidgetItem *missingSigItem = new QTreeWidgetItem();
missingSigItem->setText(0, sigName);
if (!thisMsgHasMissing)
{
thisMsgHasMissing = true;
msgItem = new QTreeWidgetItem();
msgItem->setText(0, msgName);
sigDiffTwo->addChild(msgItem);
}
msgItem->addChild(missingSigItem);
}
else //signal exists on both sides. See if it as changed position or length
{
bool didChange = false;
QTreeWidgetItem *sigItem = new QTreeWidgetItem();
sigItem->setText(0, sigName);
if (thisSig->startBit != otherSig->startBit)
{
didChange = true;
QTreeWidgetItem *sigStartBit = new QTreeWidgetItem();
sigStartBit->setText(0, "Start Bit First DBC: " + QString::number(thisSig->startBit) + " Second: " + QString::number(otherSig->startBit));
sigItem->addChild(sigStartBit);
}
if (thisSig->signalSize != otherSig->signalSize)
{
didChange = true;
QTreeWidgetItem *sigSize = new QTreeWidgetItem();
sigSize->setText(0, "Size First DBC: " + QString::number(thisSig->signalSize) + " Second: " + QString::number(otherSig->signalSize));
sigItem->addChild(sigSize);
}
if (thisSig->bias != otherSig->bias)
{
didChange = true;
QTreeWidgetItem *sigBias = new QTreeWidgetItem();
sigBias->setText(0, "Bias First DBC: " + QString::number(thisSig->bias) + " Second: " + QString::number(otherSig->bias));
sigItem->addChild(sigBias);
}
if (thisSig->factor != otherSig->factor)
{
didChange = true;
QTreeWidgetItem *sigFactor = new QTreeWidgetItem();
sigFactor->setText(0, "Factor First DBC: " + QString::number(thisSig->factor) + " Second: " + QString::number(otherSig->factor));
sigItem->addChild(sigFactor);
}
if (didChange)
{
if (!thisMsgHasMods)
{
thisMsgHasMods = true;
sigTemp = new QTreeWidgetItem();
sigTemp->setText(0, msgName);
sigModifiedRoot->addChild(sigTemp);
}
sigTemp->addChild(sigItem);
}
}
}
thisMsgHasMissing = false;
for (int i = 0; i < otherMsg->sigHandler->getCount(); i++)
{
DBC_SIGNAL *thisSig = otherMsg->sigHandler->findSignalByIdx(i);
QString sigName = thisSig->name;
DBC_SIGNAL *otherSig = thisMsg->sigHandler->findSignalByName(sigName);
if (!otherSig)
{
QTreeWidgetItem *missingSigItem = new QTreeWidgetItem();
missingSigItem->setText(0, sigName);
if (!thisMsgHasMissing)
{
thisMsgHasMissing = true;
msgItem = new QTreeWidgetItem();
msgItem->setText(0, msgName);
sigDiffOne->addChild(msgItem);
}
msgItem->addChild(missingSigItem);
}
}
}
}
for (int i = 0; i < secondDBC->messageHandler->getCount(); i++)
{
QString msgName = secondDBC->messageHandler->findMsgByIdx(i)->name;
DBC_MESSAGE *msg = firstDBC->messageHandler->findMsgByName(msgName);
if (!msg)
{
QTreeWidgetItem *missingMsgItem = new QTreeWidgetItem();
missingMsgItem->setText(0, msgName);
msgMissingDBCFirst->addChild(missingMsgItem);
}
}
QSettings settings;
if (settings.value("InfoCompare/AutoExpand", false).toBool())
{
ui->treeDetails->expandAll();
}
progress.cancel();
qApp->processEvents();
}
void DBCComparatorWindow::saveDetails()
{
QString filename;
QFileDialog dialog(this);
QSettings settings;
QStringList filters;
filters.append(QString(tr("Text File (*.txt)")));
dialog.setFileMode(QFileDialog::AnyFile);
dialog.setNameFilters(filters);
dialog.setViewMode(QFileDialog::Detail);
dialog.setAcceptMode(QFileDialog::AcceptSave);
dialog.setDirectory(settings.value("FileComparator/LoadSaveDirectory", dialog.directory().path()).toString());
if (dialog.exec() == QDialog::Accepted)
{
filename = dialog.selectedFiles()[0];
settings.setValue("FileComparator/LoadSaveDirectory", dialog.directory().path());
if (!filename.contains('.')) filename += ".txt";
QFile *outFile = new QFile(filename);
if (!outFile->open(QIODevice::WriteOnly | QIODevice::Text))
return;
QTreeWidget *tree = ui->treeDetails;
QTreeWidgetItemIterator it(tree);
while (*it) {
QTreeWidgetItem *item = *it;
QString itemText = item->text(0);
while (item->parent())
{
outFile->write(" ");
item = item->parent();
}
outFile->write(itemText.toUtf8() + "\n");
++it;
}
outFile->close();
}
}
+45
View File
@@ -0,0 +1,45 @@
#ifndef DBCCOMPARATORWINDOW_H
#define DBCCOMPARATORWINDOW_H
#include <QDialog>
#include <QDebug>
#include <QTreeWidget>
#include "framefileio.h"
#include "dbc/dbc_classes.h"
#include "dbc/dbchandler.h"
#include "utility.h"
namespace Ui {
class DBCComparatorWindow;
}
class DBCComparatorWindow : public QDialog
{
Q_OBJECT
public:
explicit DBCComparatorWindow(QWidget *parent = 0);
~DBCComparatorWindow();
private slots:
void loadFirstFile();
void loadSecondFile();
void saveDetails();
private:
Ui::DBCComparatorWindow *ui;
DBCFile *firstDBC;
DBCFile *secondDBC;
QString firstDBCFilename;
QString secondDBCFilename;
void calculateDetails();
void showEvent(QShowEvent *);
void closeEvent(QCloseEvent *event);
bool eventFilter(QObject *obj, QEvent *event);
QString loadDBC(DBCFile **file);
void readSettings();
void writeSettings();
};
#endif //DBCCOMPARATORWINDOW_H
+131
View File
@@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DBCComparatorWindow</class>
<widget class="QDialog" name="DBCComparatorWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>720</width>
<height>631</height>
</rect>
</property>
<property name="windowTitle">
<string>DBC Comparator</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout" stretch="8,0,8">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label_2">
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string>Side 1</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblFirstFile">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDBCFile1">
<property name="text">
<string>Load New File</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string>Side 2</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="lblSecondFile">
<property name="text">
<string>TextLabel</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="btnDBCFile2">
<property name="text">
<string>Load A File</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
<item>
<widget class="Line" name="line_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QTreeWidget" name="treeDetails">
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnSaveDetails">
<property name="text">
<string>Save Details to File</string>
</property>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>btnDBCFile1</tabstop>
<tabstop>btnDBCFile2</tabstop>
<tabstop>treeDetails</tabstop>
<tabstop>btnSaveDetails</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>
+6
View File
@@ -304,6 +304,7 @@
<addaction name="actionGraph_Dta"/>
<addaction name="actionFrame_Data_Analysis"/>
<addaction name="actionFile_Comparison"/>
<addaction name="actionDBC_Comparison"/>
<addaction name="actionRange_State_2"/>
<addaction name="actionSingle_Multi_State_2"/>
<addaction name="actionISO_TP_Decoder"/>
@@ -531,6 +532,11 @@
<string>Temporal Graph</string>
</property>
</action>
<action name="actionDBC_Comparison">
<property name="text">
<string>DBC Comparison</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources/>