#include "filecomparatorwindow.h" #include "ui_filecomparatorwindow.h" #include FileComparatorWindow::FileComparatorWindow(QWidget *parent) : QDialog(parent), ui(new Ui::FileComparatorWindow) { ui->setupUi(this); connect(ui->btnFirstFile, SIGNAL(clicked(bool)), this, SLOT(loadFirstFile())); connect(ui->btnSecondFile, SIGNAL(clicked(bool)), this, SLOT(loadSecondFile())); connect(ui->btnSaveDetails, SIGNAL(clicked(bool)), this, SLOT(saveDetails())); ui->lblFirstFile->setText(""); ui->lblSecondFile->setText(""); } FileComparatorWindow::~FileComparatorWindow() { delete ui; } void FileComparatorWindow::showEvent(QShowEvent *) { readSettings(); } void FileComparatorWindow::closeEvent(QCloseEvent *event) { writeSettings(); } void FileComparatorWindow::readSettings() { QSettings settings; if (settings.value("Main/SaveRestorePositions", false).toBool()) { resize(settings.value("FileComparator/WindowSize", QSize(720, 631)).toSize()); move(settings.value("FileComparator/WindowPos", QPoint(50, 50)).toPoint()); } } void FileComparatorWindow::writeSettings() { QSettings settings; if (settings.value("Main/SaveRestorePositions", false).toBool()) { settings.setValue("FileComparator/WindowSize", size()); settings.setValue("FileComparator/WindowPos", pos()); } } void FileComparatorWindow::loadFirstFile() { firstFileFrames.clear(); QString result = FrameFileIO::loadFrameFile(&firstFileFrames); if (result.length() > 0) { ui->lblFirstFile->setText(result); firstFilename = result; if (firstFileFrames.count() > 0 && secondFileFrames.count() > 0) calculateDetails(); } } void FileComparatorWindow::loadSecondFile() { secondFileFrames.clear(); QString result = FrameFileIO::loadFrameFile(&secondFileFrames); if (result.length() > 0) { ui->lblSecondFile->setText(result); secondFilename = result; if (firstFileFrames.count() > 0 && secondFileFrames.count() > 0) calculateDetails(); } } void FileComparatorWindow::calculateDetails() { QHash firstFileIDs; QHash secondFileIDs; uint64_t shiftBase = 1; //stupid hack to ensure that 64 bit shifting is used. QTreeWidgetItem *firstOnlyBase, *secondOnlyBase, *sharedBase, *bitmapBaseFirst, *bitmapBaseSecond; QTreeWidgetItem *valuesBase, *detail, *sharedItem, *valuesFirst, *valuesSecond; int idx = 0; ui->treeDetails->clear(); firstOnlyBase = new QTreeWidgetItem(); firstOnlyBase->setText(0,"IDs found only in " + firstFilename); secondOnlyBase = new QTreeWidgetItem(); secondOnlyBase->setText(0, "IDs found only in " + secondFilename); sharedBase = new QTreeWidgetItem(); sharedBase->setText(0,"IDs found in both files"); //first we have to fill out the data structures to get ready to do the report for (int x = 0; x < firstFileFrames.count(); x++) { CANFrame frame = firstFileFrames.at(x); if (firstFileIDs.contains(frame.ID)) //if we saw this ID before then add to the QList in there { for (int y = 0; y < frame.len; y++) { firstFileIDs[frame.ID].values[y][frame.data[y]]++; firstFileIDs[frame.ID].bitmap |= frame.data[y] << (8 * y); } } else //never seen this ID before so add one { FrameData *newData = new FrameData(); newData->ID = frame.ID; newData->dataLen = frame.len; //it would be possible to implement a constructor for FrameData //that sets the bitmap and values to zero. That would be cleaner and better. newData->bitmap = 0; //C++ arrays take the form of a single memory block so zap the whole block at once memset(newData->values, 0, 256 * 8); for (int y = 0; y < frame.len; y++) { newData->values[y][frame.data[y]] = 1; newData->bitmap |= frame.data[y] << (8 * y); } firstFileIDs.insert(frame.ID, *newData); } } for (int x = 0; x < secondFileFrames.count(); x++) { CANFrame frame = secondFileFrames.at(x); if (secondFileIDs.contains(frame.ID)) //if we saw this ID before then add to the QList in there { for (int y = 0; y < frame.len; y++) { secondFileIDs[frame.ID].values[y][frame.data[y]]++; secondFileIDs[frame.ID].bitmap |= frame.data[y] << (8 * y); } } else //never seen this ID before so add one { FrameData *newData = new FrameData(); newData->ID = frame.ID; newData->dataLen = frame.len; newData->bitmap = 0; memset(newData->values, 0, 256 * 8); for (int y = 0; y < frame.len; y++) { newData->values[y][frame.data[y]] = 1; newData->bitmap |= frame.data[y] << (8 * y); } secondFileIDs.insert(frame.ID, *newData); } } //now we iterate through the IDs within both files and see which are unique to one file and which //are shared QHash::iterator i; for (i = firstFileIDs.begin(); i != firstFileIDs.end(); ++i) { int keyone = i.key(); if (!secondFileIDs.contains(keyone)) { valuesBase = new QTreeWidgetItem(); valuesBase->setText(0, QString::number(keyone, 16)); firstOnlyBase->addChild(valuesBase); } else //ID was in both files { sharedItem = new QTreeWidgetItem(); sharedItem->setText(0, Utility::formatHexNum(keyone)); sharedBase->addChild(sharedItem); //if the ID was in both files then we can use the data accumulated above in bitmap //and values to figure out what has changed between the two files FrameData first = firstFileIDs[keyone]; FrameData second = secondFileIDs[keyone]; bitmapBaseFirst = new QTreeWidgetItem(); bitmapBaseFirst->setText(0, "Bits set only in " + firstFilename); bitmapBaseSecond = new QTreeWidgetItem(); bitmapBaseSecond->setText(0, "Bits set only in " + secondFilename); sharedItem->addChild(bitmapBaseFirst); sharedItem->addChild(bitmapBaseSecond); //first up, which bits were set in one file but not the other for (int b = 0; b < 64; b++) { detail = new QTreeWidgetItem(); detail->setText(0, QString::number(b) + " (" + QString::number(b / 8) + ":" + QString::number(b % 8) + ")"); if ( (first.bitmap & (shiftBase<addChild(detail); } if ( !(first.bitmap & (shiftBase<addChild(detail); } } for (int i = 0; i < qMax(first.dataLen, second.dataLen); i++) { valuesBase = new QTreeWidgetItem(); valuesBase->setText(0, "Byte " + QString::number(i)); sharedItem->addChild(valuesBase); valuesFirst = new QTreeWidgetItem(); valuesFirst->setText(0, "Values found only in " + firstFilename); valuesSecond = new QTreeWidgetItem(); valuesSecond->setText(0, "Values found only in " + secondFilename); valuesBase->addChild(valuesFirst); valuesBase->addChild(valuesSecond); for (int j = 0; j < 256; j++) { detail = new QTreeWidgetItem(); detail->setText(0, Utility::formatHexNum(j)); if (first.values[i][j] > 0 && second.values[i][j] == 0) { valuesFirst->addChild(detail); } if (second.values[i][j] > 0 && first.values[i][j] == 0) { valuesSecond->addChild(detail); } } } } } QHash::iterator itwo; for (itwo = secondFileIDs.begin(); itwo != secondFileIDs.end(); ++itwo) { int keytwo = itwo.key(); if (!firstFileIDs.contains(keytwo)) { valuesBase = new QTreeWidgetItem(); valuesBase->setText(0, Utility::formatHexNum(keytwo)); secondOnlyBase->addChild(valuesBase); } } ui->treeDetails->addTopLevelItem(firstOnlyBase); ui->treeDetails->addTopLevelItem(secondOnlyBase); ui->treeDetails->addTopLevelItem(sharedBase); ui->treeDetails->setSortingEnabled(true); ui->treeDetails->sortByColumn(0, Qt::AscendingOrder); QSettings settings; if (settings.value("InfoCompare/AutoExpand", false).toBool()) { ui->treeDetails->expandAll(); } } void FileComparatorWindow::saveDetails() { QString filename; QFileDialog dialog(this); QStringList filters; filters.append(QString(tr("Text File (*.txt)"))); dialog.setFileMode(QFileDialog::AnyFile); dialog.setNameFilters(filters); dialog.setViewMode(QFileDialog::Detail); dialog.setAcceptMode(QFileDialog::AcceptSave); if (dialog.exec() == QDialog::Accepted) { filename = dialog.selectedFiles()[0]; 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(); } }