GUI: Better history. Prepare for tagging messages.
This commit is contained in:
parent
3e2236ac73
commit
78e30e735e
|
@ -26,10 +26,16 @@ QErrorPathItem::QErrorPathItem(const ErrorLogger::ErrorMessage::FileLocation &lo
|
|||
{
|
||||
}
|
||||
|
||||
bool operator==(const QErrorPathItem &i1, const QErrorPathItem &i2)
|
||||
{
|
||||
return i1.file == i2.file && i1.col == i2.col && i1.line == i2.line && i1.info == i2.info;
|
||||
}
|
||||
|
||||
ErrorItem::ErrorItem()
|
||||
: severity(Severity::none)
|
||||
, inconclusive(false)
|
||||
, cwe(-1)
|
||||
, tag(NONE)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -40,6 +46,7 @@ ErrorItem::ErrorItem(const ErrorLogger::ErrorMessage &errmsg)
|
|||
, summary(QString::fromStdString(errmsg.shortMessage()))
|
||||
, message(QString::fromStdString(errmsg.verboseMessage()))
|
||||
, cwe(errmsg._cwe.id)
|
||||
, tag(NONE)
|
||||
{
|
||||
for (std::list<ErrorLogger::ErrorMessage::FileLocation>::const_iterator loc = errmsg._callStack.begin();
|
||||
loc != errmsg._callStack.end();
|
||||
|
|
|
@ -59,6 +59,8 @@ public:
|
|||
QString info;
|
||||
};
|
||||
|
||||
bool operator==(const QErrorPathItem &i1, const QErrorPathItem &i2);
|
||||
|
||||
/**
|
||||
* @brief A class containing error data for one error.
|
||||
*
|
||||
|
@ -86,6 +88,10 @@ public:
|
|||
QString message;
|
||||
int cwe;
|
||||
QList<QErrorPathItem> errorPath;
|
||||
|
||||
// Special GUI properties
|
||||
QString sinceDate;
|
||||
enum Tag { NONE, FP, IGNORE, BUG } tag;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ErrorItem);
|
||||
|
@ -103,6 +109,8 @@ public:
|
|||
Severity::SeverityType severity;
|
||||
QString summary;
|
||||
QString message;
|
||||
QString sinceDate;
|
||||
ErrorItem::Tag tag;
|
||||
};
|
||||
|
||||
/// @}
|
||||
|
|
|
@ -872,6 +872,7 @@ void MainWindow::analysisDone()
|
|||
const QString buildDir = prjpath + '/' + mProjectFile->getBuildDir();
|
||||
if (QDir(buildDir).exists()) {
|
||||
mUI.mResults->saveStatistics(buildDir + "/statistics.txt");
|
||||
mUI.mResults->updateFromOldReport(buildDir + "/lastResults.xml");
|
||||
mUI.mResults->save(buildDir + "/lastResults.xml", Report::XMLV2);
|
||||
}
|
||||
}
|
||||
|
@ -1278,6 +1279,13 @@ void MainWindow::stopAnalysis()
|
|||
{
|
||||
mThread->stop();
|
||||
mUI.mResults->disableProgressbar();
|
||||
if (mProjectFile && !mProjectFile->getBuildDir().isEmpty()) {
|
||||
const QString prjpath = QFileInfo(mProjectFile->getFilename()).absolutePath();
|
||||
const QString buildDir = prjpath + '/' + mProjectFile->getBuildDir();
|
||||
if (QDir(buildDir).exists()) {
|
||||
mUI.mResults->updateFromOldReport(buildDir + "/lastResults.xml");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::openHelpContents()
|
||||
|
|
|
@ -47,6 +47,11 @@
|
|||
#include "showtypes.h"
|
||||
#include "threadhandler.h"
|
||||
#include "path.h"
|
||||
#include "xmlreportv2.h"
|
||||
|
||||
// These must match column headers given in ResultsTree::translate()
|
||||
static const unsigned int COLUMN_SINCE_DATE = 6;
|
||||
static const unsigned int COLUMN_TAG = 7;
|
||||
|
||||
ResultsTree::ResultsTree(QWidget * parent) :
|
||||
QTreeView(parent),
|
||||
|
@ -154,6 +159,8 @@ bool ResultsTree::addErrorItem(const ErrorItem &item)
|
|||
line.summary = item.summary;
|
||||
line.message = item.message;
|
||||
line.severity = item.severity;
|
||||
line.sinceDate = item.sinceDate;
|
||||
line.tag = item.tag;
|
||||
//Create the base item for the error and ensure it has a proper
|
||||
//file item as a parent
|
||||
QStandardItem* fileItem = ensureFileItem(item.errorPath.back().file, item.file0, hide);
|
||||
|
@ -232,7 +239,22 @@ QStandardItem *ResultsTree::addBacktraceFiles(QStandardItem *parent,
|
|||
<< createLineNumberItem(QString::number(item.line))
|
||||
<< createNormalItem(childOfMessage ? QString() : item.errorId)
|
||||
<< (childOfMessage ? createNormalItem(QString()) : createCheckboxItem(item.inconclusive))
|
||||
<< createNormalItem(item.summary);
|
||||
<< createNormalItem(item.summary)
|
||||
<< createNormalItem(item.sinceDate);
|
||||
switch (item.tag) {
|
||||
case ErrorItem::NONE:
|
||||
list << createNormalItem("");
|
||||
break;
|
||||
case ErrorItem::FP:
|
||||
list << createNormalItem("fp");
|
||||
break;
|
||||
case ErrorItem::IGNORE:
|
||||
list << createNormalItem("ignore");
|
||||
break;
|
||||
case ErrorItem::BUG:
|
||||
list << createNormalItem("bug");
|
||||
break;
|
||||
};
|
||||
//TODO message has parameter names so we'll need changes to the core
|
||||
//cppcheck so we can get proper translations
|
||||
|
||||
|
@ -1003,12 +1025,86 @@ void ResultsTree::saveErrors(Report *report, QStandardItem *fileItem) const
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
QList<ErrorItem> ResultsTree::getAllErrorItems() const
|
||||
{
|
||||
QList<ErrorItem> ret;
|
||||
for (int i = 0; i < mModel.rowCount(); i++) {
|
||||
const QStandardItem *item = mModel.item(i,0);
|
||||
for (int j = 0; j < item->rowCount(); j++) {
|
||||
const QStandardItem *error = item->child(j,0);
|
||||
ErrorItem errorItem;
|
||||
readErrorItem(error, &errorItem);
|
||||
ret << errorItem;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int indexOf(const QList<ErrorItem> &list, const ErrorItem &item)
|
||||
{
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
if (list[i].errorId == item.errorId &&
|
||||
list[i].errorPath == item.errorPath &&
|
||||
list[i].file0 == item.file0 &&
|
||||
list[i].message == item.message &&
|
||||
list[i].inconclusive == item.inconclusive &&
|
||||
list[i].severity == item.severity) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void ResultsTree::updateFromOldReport(const QString &filename)
|
||||
{
|
||||
QList<ErrorItem> oldErrors;
|
||||
XmlReportV2 oldReport(filename);
|
||||
if (oldReport.open()) {
|
||||
oldErrors = oldReport.read();
|
||||
oldReport.close();
|
||||
}
|
||||
|
||||
// Read current results..
|
||||
for (int i = 0; i < mModel.rowCount(); i++) {
|
||||
QStandardItem *fileItem = mModel.item(i,0);
|
||||
for (int j = 0; j < fileItem->rowCount(); j++) {
|
||||
QStandardItem *error = fileItem->child(j,0);
|
||||
ErrorItem errorItem;
|
||||
readErrorItem(error, &errorItem);
|
||||
int oldErrorIndex = indexOf(oldErrors, errorItem);
|
||||
QVariantMap data = error->data().toMap();
|
||||
|
||||
// New error .. set the "sinceDate" property
|
||||
if (oldErrorIndex < 0 || data["sinceDate"].toString().isEmpty()) {
|
||||
const QString sinceDate = QDate::currentDate().toString(Qt::SystemLocaleShortDate);
|
||||
data["sinceDate"] = sinceDate;
|
||||
error->setData(data);
|
||||
fileItem->child(j, COLUMN_SINCE_DATE)->setText(sinceDate);
|
||||
if (oldErrorIndex < 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
if (errorItem.tag != ErrorItem::NONE)
|
||||
continue;
|
||||
|
||||
const ErrorItem &oldErrorItem = oldErrors[oldErrorIndex];
|
||||
|
||||
if (oldErrorItem.tag == ErrorItem::FP)
|
||||
data["tag"] = "fp";
|
||||
else if (oldErrorItem.tag == ErrorItem::IGNORE)
|
||||
data["tag"] = "ignore";
|
||||
else if (oldErrorItem.tag == ErrorItem::BUG)
|
||||
data["tag"] = "bug";
|
||||
error->setData(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ResultsTree::readErrorItem(const QStandardItem *error, ErrorItem *item) const
|
||||
{
|
||||
//Get error's user data
|
||||
QVariant userdata = error->data();
|
||||
//Convert it to QVariantMap
|
||||
QVariantMap data = userdata.toMap();
|
||||
// Get error's user data
|
||||
QVariantMap data = error->data().toMap();
|
||||
|
||||
item->severity = ShowTypes::ShowTypeToSeverity(ShowTypes::VariantToShowType(data["severity"]));
|
||||
item->summary = data["summary"].toString();
|
||||
|
@ -1016,6 +1112,14 @@ void ResultsTree::readErrorItem(const QStandardItem *error, ErrorItem *item) con
|
|||
item->errorId = data["id"].toString();
|
||||
item->inconclusive = data["inconclusive"].toBool();
|
||||
item->file0 = data["file0"].toString();
|
||||
item->sinceDate = data["sinceDate"].toString();
|
||||
QString tag = data["tag"].toString();
|
||||
if (tag == "fp")
|
||||
item->tag = ErrorItem::FP;
|
||||
else if (tag == "ignore")
|
||||
item->tag = ErrorItem::IGNORE;
|
||||
else if (tag == "bug")
|
||||
item->tag = ErrorItem::BUG;
|
||||
|
||||
if (error->rowCount() == 0) {
|
||||
QErrorPathItem e;
|
||||
|
@ -1161,7 +1265,7 @@ bool ResultsTree::hasResults() const
|
|||
void ResultsTree::translate()
|
||||
{
|
||||
QStringList labels;
|
||||
labels << tr("File") << tr("Severity") << tr("Line") << tr("Id") << tr("Inconclusive") << tr("Summary");
|
||||
labels << tr("File") << tr("Severity") << tr("Line") << tr("Id") << tr("Inconclusive") << tr("Summary") << tr("Since date") << tr("Tag");
|
||||
mModel.setHorizontalHeaderLabels(labels);
|
||||
//TODO go through all the errors in the tree and translate severity and message
|
||||
}
|
||||
|
|
|
@ -103,6 +103,16 @@ public:
|
|||
*/
|
||||
void saveResults(Report *report) const;
|
||||
|
||||
/**
|
||||
* @brief Get all error items
|
||||
*/
|
||||
QList<ErrorItem> getAllErrorItems() const;
|
||||
|
||||
/**
|
||||
* @brief Update items from old report (tag, sinceDate)
|
||||
*/
|
||||
void updateFromOldReport(const QString &filename);
|
||||
|
||||
/**
|
||||
* @brief Update tree settings
|
||||
*
|
||||
|
|
|
@ -149,6 +149,11 @@ void ResultsView::saveStatistics(const QString &filename) const
|
|||
ts << "portability:" << mStatistics->getCount(ShowTypes::ShowPortability) << '\n';
|
||||
}
|
||||
|
||||
void ResultsView::updateFromOldReport(const QString &filename) const
|
||||
{
|
||||
mUI.mTree->updateFromOldReport(filename);
|
||||
}
|
||||
|
||||
void ResultsView::save(const QString &filename, Report::Type type) const
|
||||
{
|
||||
if (!hasResults()) {
|
||||
|
|
|
@ -88,6 +88,11 @@ public:
|
|||
*/
|
||||
void save(const QString &filename, Report::Type type) const;
|
||||
|
||||
/**
|
||||
* @brief Update results from old report (tag, sinceDate)
|
||||
*/
|
||||
void updateFromOldReport(const QString &filename) const;
|
||||
|
||||
/**
|
||||
* @brief Update tree settings
|
||||
*
|
||||
|
|
|
@ -35,6 +35,8 @@ static const char ErrorsElementName[] = "errors";
|
|||
static const char LocationElementName[] = "location";
|
||||
static const char ColAttribute[] = "col";
|
||||
static const char CWEAttribute[] = "cwe";
|
||||
static const char SinceDateAttribute[] = "sinceDate";
|
||||
static const char TagAttribute[] = "tag";
|
||||
static const char FilenameAttribute[] = "file";
|
||||
static const char IncludedFromFilenameAttribute[] = "file0";
|
||||
static const char InconclusiveAttribute[] = "inconclusive";
|
||||
|
@ -120,6 +122,14 @@ void XmlReportV2::writeError(const ErrorItem &error)
|
|||
mXmlWriter->writeAttribute(InconclusiveAttribute, "true");
|
||||
if (error.cwe > 0)
|
||||
mXmlWriter->writeAttribute(CWEAttribute, QString::number(error.cwe));
|
||||
if (!error.sinceDate.isEmpty())
|
||||
mXmlWriter->writeAttribute(SinceDateAttribute, error.sinceDate);
|
||||
if (error.tag == ErrorItem::FP)
|
||||
mXmlWriter->writeAttribute(TagAttribute, "fp");
|
||||
else if (error.tag == ErrorItem::IGNORE)
|
||||
mXmlWriter->writeAttribute(TagAttribute, "ignore");
|
||||
else if (error.tag == ErrorItem::BUG)
|
||||
mXmlWriter->writeAttribute(TagAttribute, "bug");
|
||||
|
||||
for (int i = error.errorPath.count() - 1; i >= 0; i--) {
|
||||
mXmlWriter->writeStartElement(LocationElementName);
|
||||
|
@ -209,6 +219,17 @@ ErrorItem XmlReportV2::readError(QXmlStreamReader *reader)
|
|||
item.inconclusive = true;
|
||||
if (attribs.hasAttribute("", CWEAttribute))
|
||||
item.cwe = attribs.value("", CWEAttribute).toString().toInt();
|
||||
if (attribs.hasAttribute("", SinceDateAttribute))
|
||||
item.sinceDate = attribs.value("", SinceDateAttribute).toString();
|
||||
if (attribs.hasAttribute("", TagAttribute)) {
|
||||
const QString tag = attribs.value("", TagAttribute).toString();
|
||||
if (tag == "fp")
|
||||
item.tag = ErrorItem::FP;
|
||||
else if (tag == "ignore")
|
||||
item.tag = ErrorItem::IGNORE;
|
||||
else if (tag == "bug")
|
||||
item.tag = ErrorItem::BUG;
|
||||
}
|
||||
}
|
||||
|
||||
bool errorRead = false;
|
||||
|
@ -251,5 +272,9 @@ ErrorItem XmlReportV2::readError(QXmlStreamReader *reader)
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (item.errorPath.size() == 1 && item.errorPath[0].info.isEmpty())
|
||||
item.errorPath[0].info = item.message;
|
||||
|
||||
return item;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue