diff --git a/gui/csvreport.cpp b/gui/csvreport.cpp index 7a4c5efab..db47fcdb2 100644 --- a/gui/csvreport.cpp +++ b/gui/csvreport.cpp @@ -51,19 +51,16 @@ void CsvReport::WriteFooter() // No footer for CSV report } -void CsvReport::WriteError(const QStringList &files, const QStringList &lines, - const QString &id, const QString &severity, const QString &msg) +void CsvReport::WriteError(const ErrorItem &error) { - Q_UNUSED(id); - /* Error as CSV line gui/test.cpp,23,error,Mismatching allocation and deallocation: k */ QString line; - line += QString("%1,%2,").arg(files[files.size() - 1]).arg(lines[lines.size() - 1]); - line += QString("%1,%2").arg(severity).arg(msg); + line += QString("%1,%2,").arg(error.files[error.files.size() - 1]).arg(error.lines[error.lines.size() - 1]); + line += QString("%1,%2").arg(error.severity).arg(error.msg); mTxtWriter << line << endl; } diff --git a/gui/csvreport.h b/gui/csvreport.h index 23e3eadef..5661a03d5 100644 --- a/gui/csvreport.h +++ b/gui/csvreport.h @@ -60,10 +60,9 @@ public: /** * @brief Write error to report. + * @param error Error data. */ - virtual void WriteError(const QStringList &files, const QStringList &lines, - const QString &id, const QString &severity, - const QString &msg); + virtual void WriteError(const ErrorItem &error); private: diff --git a/gui/erroritem.cpp b/gui/erroritem.cpp new file mode 100644 index 000000000..98f620671 --- /dev/null +++ b/gui/erroritem.cpp @@ -0,0 +1,39 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2010 Daniel Marjamäki and Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "erroritem.h" + +ErrorItem::ErrorItem(const ErrorItem &item) +{ + file = item.file; + files = item.files; + lines = item.lines; + id = item.id; + severity = item.severity; + msg = item.msg; +} + +ErrorItem::ErrorItem(const ErrorLine &line) +{ + file = line.file; + files.append(line.file); + lines.append(line.line.toUInt()); + id = line.id; + severity = line.severity; + msg = line.msg; +} diff --git a/gui/erroritem.h b/gui/erroritem.h new file mode 100644 index 000000000..73fc661d9 --- /dev/null +++ b/gui/erroritem.h @@ -0,0 +1,62 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2010 Daniel Marjamäki and Cppcheck team. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef ERRORITEM_H +#define ERRORITEM_H + +#include +#include + +class ErrorLine; + +/// @addtogroup GUI +/// @{ + +/** +* @brief A class containing error data for one error. +*/ +class ErrorItem +{ +public: + ErrorItem() { } + ErrorItem(const ErrorItem &item); + ErrorItem(const ErrorLine &line); + + QString file; + QStringList files; + QList lines; + QString id; + QString severity; + QString msg; +}; + +/** +* @brief A class containing error data for one shown error line. +*/ +class ErrorLine +{ +public: + QString file; + QString line; + QString id; + QString severity; + QString msg; +}; + +/// @} +#endif // ERRORITEM_H diff --git a/gui/gui.pro b/gui/gui.pro index 0ef54b270..84265f8ea 100644 --- a/gui/gui.pro +++ b/gui/gui.pro @@ -50,6 +50,7 @@ HEADERS += mainwindow.h \ applicationdialog.h \ aboutdialog.h \ common.h \ + erroritem.h \ fileviewdialog.h \ projectfile.h \ report.h \ @@ -70,6 +71,7 @@ SOURCES += main.cpp \ aboutdialog.cpp \ fileviewdialog.cpp \ projectfile.cpp \ + erroritem.cpp \ report.cpp \ txtreport.cpp \ xmlreport.cpp \ diff --git a/gui/main.cpp b/gui/main.cpp index 2309e7a64..02ee24eae 100644 --- a/gui/main.cpp +++ b/gui/main.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include "mainwindow.h" int main(int argc, char *argv[]) @@ -27,6 +28,9 @@ int main(int argc, char *argv[]) QApplication app(argc, argv); app.setWindowIcon(QIcon(":icon.png")); + // Register this metatype that is used to transfer error info + qRegisterMetaType>("QList"); + // Set codecs so that UTF-8 strings in sources are handled correctly. QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8")); diff --git a/gui/main.ui b/gui/main.ui index 3e0a708c3..3317d4452 100644 --- a/gui/main.ui +++ b/gui/main.ui @@ -73,6 +73,7 @@ &File + @@ -347,6 +348,11 @@ Error categories + + + &Open XML... + + diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 15d4b08de..81acef2b7 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -56,6 +56,7 @@ MainWindow::MainWindow() : connect(mUI.mActionCheckDirectory, SIGNAL(triggered()), this, SLOT(CheckDirectory())); connect(mUI.mActionSettings, SIGNAL(triggered()), this, SLOT(ProgramSettings())); connect(mUI.mActionClearResults, SIGNAL(triggered()), this, SLOT(ClearResults())); + connect(mUI.mActionOpenXML, SIGNAL(triggered()), this, SLOT(OpenXML())); connect(mUI.mActionShowStyle, SIGNAL(toggled(bool)), this, SLOT(ShowStyle(bool))); connect(mUI.mActionShowErrors, SIGNAL(toggled(bool)), this, SLOT(ShowErrors(bool))); @@ -431,6 +432,22 @@ void MainWindow::ClearResults() mUI.mActionSave->setEnabled(false); } +void MainWindow::OpenXML() +{ + QString selectedFilter; + QString filter(tr("XML files (*.xml)")); + QString selectedFile = QFileDialog::getOpenFileName(this, + tr("Open the report file"), + QString(), + filter, + &selectedFilter); + + if (!selectedFile.isEmpty()) + { + mUI.mResults->ReadErrorsXml(selectedFile); + } +} + void MainWindow::EnableCheckButtons(bool enable) { mUI.mActionStop->setEnabled(!enable); diff --git a/gui/mainwindow.h b/gui/mainwindow.h index 0fa17db2d..3142dccaa 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -67,6 +67,12 @@ public slots: */ void ClearResults(); + /** + * @brief Slot to open XML report file + * + */ + void OpenXML(); + /** * @brief Show errors with type "style" * @param checked Should errors be shown (true) or hidden (false) diff --git a/gui/report.cpp b/gui/report.cpp index 0fbfc4e54..2f5e150e3 100644 --- a/gui/report.cpp +++ b/gui/report.cpp @@ -17,6 +17,7 @@ */ #include +#include "erroritem.h" #include "report.h" Report::Report(const QString &filename, QObject * parent) : @@ -41,6 +42,17 @@ bool Report::Create() return succeed; } +bool Report::Open() +{ + bool succeed = false; + if (!mFile.isOpen()) + { + mFile.setFileName(mFilename); + succeed = mFile.open(QIODevice::ReadOnly | QIODevice::Text); + } + return succeed; +} + void Report::Close() { if (mFile.isOpen()) diff --git a/gui/report.h b/gui/report.h index 5459e31ee..83a22e148 100644 --- a/gui/report.h +++ b/gui/report.h @@ -23,6 +23,7 @@ #include #include #include +#include "erroritem.h" /// @addtogroup GUI /// @{ @@ -50,6 +51,12 @@ public: */ virtual bool Create(); + /** + * @brief Open the existing report (file). + * @return true if succeeded, false if file could not be created. + */ + virtual bool Open(); + /** * @brief Close the report (file). */ @@ -67,10 +74,9 @@ public: /** * @brief Write error to report. + * @param error Error data. */ - virtual void WriteError(const QStringList &files, const QStringList &lines, - const QString &id, const QString &severity, - const QString &msg) = 0; + virtual void WriteError(const ErrorItem &error) = 0; protected: diff --git a/gui/resultstree.cpp b/gui/resultstree.cpp index e69138a81..bd24bb1cd 100644 --- a/gui/resultstree.cpp +++ b/gui/resultstree.cpp @@ -24,14 +24,15 @@ #include #include #include +#include #include +#include "erroritem.h" #include "resultstree.h" #include "xmlreport.h" ResultsTree::ResultsTree(QWidget * parent) : QTreeView(parent), mContextItem(0), - mCheckPath(""), mVisibleErrors(false) { for (int i = 0; i < SHOW_NONE; i++) @@ -67,28 +68,21 @@ QStandardItem *ResultsTree::CreateItem(const QString &name) return item; } -void ResultsTree::AddErrorItem(const QString &file, - const QString &severity, - const QString &message, - const QStringList &files, - const QVariantList &lines, - const QString &id) +void ResultsTree::AddErrorItem(const ErrorItem &item) { - Q_UNUSED(file); - - if (files.isEmpty()) + if (item.files.isEmpty()) { return; } - QString realfile = StripPath(files[0], false); + QString realfile = StripPath(item.files[0], false); if (realfile.isEmpty()) { realfile = tr("Undefined file"); } - bool hide = !mShowTypes[SeverityToShowType(severity)]; + bool hide = !mShowTypes[SeverityToShowType(item.severity)]; //if there is at least one error that is not hidden, we have a visible error if (!hide) @@ -96,48 +90,49 @@ void ResultsTree::AddErrorItem(const QString &file, mVisibleErrors = true; } + ErrorLine line; + line.file = realfile; + line.id = item.id; + line.line = QString::number(item.lines[0]); + line.msg = item.msg; + line.severity = item.severity; //Create the base item for the error and ensure it has a proper //file item as a parent - QStandardItem *item = AddBacktraceFiles(EnsureFileItem(files[0], hide), - realfile, - lines[0].toInt(), - severity, - message, - hide, - SeverityToIcon(severity)); + QStandardItem *stditem = AddBacktraceFiles(EnsureFileItem(line.file, hide), + line, + hide, + SeverityToIcon(line.severity)); - if (!item) + if (!stditem) return; //Add user data to that item QMap data; - data["severity"] = SeverityToShowType(severity); - data["message"] = message; - data["file"] = files[0]; - data["line"] = lines[0]; - data["id"] = id; - item->setData(QVariant(data)); + data["severity"] = SeverityToShowType(item.severity); + data["message"] = item.msg; + data["file"] = item.files[0]; + data["line"] = QString::number(item.lines[0]); + data["id"] = item.id; + stditem->setData(QVariant(data)); //Add backtrace files as children - for (int i = 1; i < files.size() && i < lines.size(); i++) + for (int i = 1; i < item.files.size() && i < item.lines.size(); i++) { + line.file = StripPath(item.files[i], false); + line.line = item.lines[i]; QStandardItem *child_item; - - child_item = AddBacktraceFiles(item, - StripPath(files[i], false), - lines[i].toInt(), - severity, - message, + child_item = AddBacktraceFiles(stditem, + line, hide, ":images/go-down.png"); //Add user data to that item QMap child_data; - child_data["severity"] = SeverityToShowType(severity); - child_data["message"] = message; - child_data["file"] = files[i]; - child_data["line"] = lines[i]; - child_data["id"] = id; + child_data["severity"] = SeverityToShowType(line.severity); + child_data["message"] = line.msg; + child_data["file"] = item.files[i]; + child_data["line"] = line.line; + child_data["id"] = line.id; child_item->setData(QVariant(child_data)); } @@ -150,10 +145,7 @@ void ResultsTree::AddErrorItem(const QString &file, } QStandardItem *ResultsTree::AddBacktraceFiles(QStandardItem *parent, - const QString &file, - const int line, - const QString &severity, - const QString &message, + const ErrorLine &item, const bool hide, const QString &icon) @@ -164,12 +156,12 @@ QStandardItem *ResultsTree::AddBacktraceFiles(QStandardItem *parent, } QList list; - list << CreateItem(file); - list << CreateItem(tr(severity.toLatin1())); - list << CreateItem(QString("%1").arg(line)); + list << CreateItem(item.file); + list << CreateItem(tr(item.severity.toLatin1())); + list << CreateItem(QString("%1").arg(item.line)); //TODO message has parameter names so we'll need changes to the core //cppcheck so we can get proper translations - list << CreateItem(tr(message.toLatin1())); + list << CreateItem(tr(item.msg.toLatin1())); // Check for duplicate rows and don't add them if found for (int i = 0; i < parent->rowCount(); i++) @@ -452,7 +444,7 @@ void ResultsTree::contextMenuEvent(QContextMenuEvent * e) void ResultsTree::StartApplication(QStandardItem *target, int application) { - //If there are now application's specified, tell the user about it + //If there are no applications specified, tell the user about it if (mApplications->GetApplicationCount() == 0) { QMessageBox msg(QMessageBox::Information, @@ -476,6 +468,34 @@ void ResultsTree::StartApplication(QStandardItem *target, int application) //Replace (file) with filename QString file = data["file"].toString(); + + QFileInfo info(file); + if (!info.exists()) + { + if (info.isAbsolute()) + { + QMessageBox msgbox(this); + msgbox.setWindowTitle("Cppcheck"); + msgbox.setText(tr("Could not find the file!")); + msgbox.setIcon(QMessageBox::Critical); + msgbox.exec(); + } + else + { + QDir checkdir(mCheckPath); + if (checkdir.isAbsolute() && checkdir.exists()) + { + file = mCheckPath + "/" + file; + } + else + { + QString dir = AskFileDir(file); + dir += '/'; + file = dir + file; + } + } + } + if (file.indexOf(" ") > -1) { file.insert(0, "\""); @@ -506,6 +526,22 @@ void ResultsTree::StartApplication(QStandardItem *target, int application) } } +QString ResultsTree::AskFileDir(const QString &file) +{ + QString text = tr("Could not find file:\n%1\nPlease select the directory where file is located.").arg(file); + QMessageBox msgbox(this); + msgbox.setWindowTitle("Cppcheck"); + msgbox.setText(text); + msgbox.setIcon(QMessageBox::Warning); + msgbox.exec(); + + QString dir = QFileDialog::getExistingDirectory(this, tr("Select Directory"), + "", + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + mCheckPath = dir; + return dir; +} + void ResultsTree::CopyFilename() { CopyPath(mContextItem, false); @@ -601,8 +637,6 @@ void ResultsTree::SaveErrors(Report *report, QStandardItem *item) return; } - //qDebug() << item->text() << "has" << item->rowCount() << "errors"; - for (int i = 0; i < item->rowCount(); i++) { QStandardItem *error = item->child(i, 0); @@ -622,17 +656,15 @@ void ResultsTree::SaveErrors(Report *report, QStandardItem *item) //Convert it to QVariantMap QVariantMap data = userdata.toMap(); - QString severity = ShowTypeToString(VariantToShowType(data["severity"])); - QString message = data["message"].toString(); - QString id = data["id"].toString(); + ErrorItem item; + item.severity = ShowTypeToString(VariantToShowType(data["severity"])); + item.msg = data["message"].toString(); + item.id = data["id"].toString(); QString file = StripPath(data["file"].toString(), true); - QString line = data["line"].toString(); + unsigned int line = data["line"].toUInt(); - QStringList files; - QStringList lines; - - files << file; - lines << line; + item.files << file; + item.lines << line; for (int j = 0; j < error->rowCount(); j++) { @@ -643,13 +675,13 @@ void ResultsTree::SaveErrors(Report *report, QStandardItem *item) QVariantMap child_data = child_userdata.toMap(); file = StripPath(child_data["file"].toString(), true); - line = child_data["line"].toString(); + line = child_data["line"].toUInt(); - files << file; - lines << line; + item.files << file; + item.lines << line; } - report->WriteError(files, lines, id, severity, message); + report->WriteError(item); } } diff --git a/gui/resultstree.h b/gui/resultstree.h index a234d7af0..5f35c6f63 100644 --- a/gui/resultstree.h +++ b/gui/resultstree.h @@ -25,11 +25,13 @@ #include #include #include +#include #include "common.h" #include "applicationlist.h" -#include class Report; +class ErrorItem; +class ErrorLine; /// @addtogroup GUI /// @{ @@ -50,19 +52,9 @@ public: /** * @brief Add a new item to the tree * - * @param file filename - * @param severity error severity - * @param message error message - * @param files list of files affected by the error - * @param lines list of file line numers affected by the error - * @param id error id + * @param item Error item data */ - void AddErrorItem(const QString &file, - const QString &severity, - const QString &message, - const QStringList &files, - const QVariantList &lines, - const QString &id); + void AddErrorItem(const ErrorItem &item); /** * @brief Clear all errors from the tree @@ -224,19 +216,13 @@ protected: * @brief Add a new error item beneath a file or a backtrace item beneath an error * * @param parent Parent for the item. Either a file item or an error item - * @param file Filename of the error - * @param line Line numer - * @param severity Error severity - * @param message Error message + * @param item Error line data * @param hide Should this be hidden (true) or shown (false) * @param icon Should a default backtrace item icon be added * @return newly created QStandardItem * */ QStandardItem *AddBacktraceFiles(QStandardItem *parent, - const QString &file, - const int line, - const QString &severity, - const QString &message, + const ErrorLine &item, const bool hide, const QString &icon); @@ -276,6 +262,12 @@ protected: */ void LoadSettings(); + /** + * @brief Ask directory where file is located. + * @param file File name. + * @return Directory user chose. + */ + QString AskFileDir(const QString &file); /** * @brief Create a new QStandardItem diff --git a/gui/resultsview.cpp b/gui/resultsview.cpp index f0f3e37f2..2e941979a 100644 --- a/gui/resultsview.cpp +++ b/gui/resultsview.cpp @@ -70,11 +70,19 @@ void ResultsView::Error(const QString &file, const QString &severity, const QString &message, const QStringList &files, - const QVariantList &lines, + const QList &lines, const QString &id) { mErrorsFound = true; - mUI.mTree->AddErrorItem(file, severity, message, files, lines, id); + ErrorItem item; + item.file = file; + item.files = files; + item.id = id; + item.lines = lines; + item.msg = message; + item.severity = severity; + + mUI.mTree->AddErrorItem(item); emit GotResults(); } @@ -217,3 +225,38 @@ void ResultsView::DisableProgressbar() { mUI.mProgress->setEnabled(false); } + +void ResultsView::ReadErrorsXml(const QString &filename) +{ + XmlReport *report = new XmlReport(filename, this); + QList errors; + if (report) + { + if (report->Open()) + errors = report->Read(); + else + { + QMessageBox msgBox; + msgBox.setText(tr("Failed to read the report.")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.exec(); + } + delete report; + report = NULL; + } + else + { + QMessageBox msgBox; + msgBox.setText(tr("Failed to read the report.")); + msgBox.setIcon(QMessageBox::Critical); + msgBox.exec(); + } + + ErrorLine line; + foreach(line, errors) + { + ErrorItem item(line); + mUI.mTree->AddErrorItem(item); + } + mUI.mTree->SetCheckDirectory(""); +} diff --git a/gui/resultsview.h b/gui/resultsview.h index cb3f4abb1..a940fdebb 100644 --- a/gui/resultsview.h +++ b/gui/resultsview.h @@ -129,6 +129,14 @@ public: void Translate(); void DisableProgressbar(); + + /** + * @brief Read errors from report XML file. + * @param filename Report file to read. + * + */ + void ReadErrorsXml(const QString &filename); + signals: /** @@ -161,7 +169,7 @@ public slots: const QString &severity, const QString &message, const QStringList &files, - const QVariantList &lines, + const QList &lines, const QString &id); /** diff --git a/gui/threadhandler.cpp b/gui/threadhandler.cpp index 2dad5df0e..feae8b503 100644 --- a/gui/threadhandler.cpp +++ b/gui/threadhandler.cpp @@ -145,13 +145,13 @@ void ThreadHandler::Initialize(ResultsView *view) const QString &, const QString &, const QStringList &, - const QVariantList &, + const QList &, const QString &)), view, SLOT(Error(const QString &, const QString &, const QString &, const QStringList &, - const QVariantList &, + const QList &, const QString &))); } diff --git a/gui/threadresult.cpp b/gui/threadresult.cpp index 56ca9ee16..165edb528 100644 --- a/gui/threadresult.cpp +++ b/gui/threadresult.cpp @@ -47,7 +47,7 @@ void ThreadResult::reportErr(const ErrorLogger::ErrorMessage &msg) { QMutexLocker locker(&mutex); - QVariantList lines; + QList lines; QStringList files; for (std::list::const_iterator tok = msg._callStack.begin(); diff --git a/gui/threadresult.h b/gui/threadresult.h index c1b1b9a66..494d5db16 100644 --- a/gui/threadresult.h +++ b/gui/threadresult.h @@ -98,7 +98,7 @@ signals: const QString &severity, const QString &message, const QStringList &files, - const QVariantList &lines, + const QList &lines, const QString &id); protected: diff --git a/gui/txtreport.cpp b/gui/txtreport.cpp index 0cf4728ba..0a064f354 100644 --- a/gui/txtreport.cpp +++ b/gui/txtreport.cpp @@ -51,11 +51,8 @@ void TxtReport::WriteFooter() // No footer for txt report } -void TxtReport::WriteError(const QStringList &files, const QStringList &lines, - const QString &id, const QString &severity, const QString &msg) +void TxtReport::WriteError(const ErrorItem &error) { - Q_UNUSED(id); - /* Error example from the core program in text [gui/test.cpp:23] -> [gui/test.cpp:14]: (error) Mismatching allocation and deallocation: k @@ -63,21 +60,21 @@ void TxtReport::WriteError(const QStringList &files, const QStringList &lines, QString line; - for (int i = 0; i < lines.size(); i++) + for (int i = 0; i < error.lines.size(); i++) { - line += QString("[%1:%2]").arg(files[i]).arg(lines[i]); - if (i < lines.size() - 1 && lines.size() > 0) + line += QString("[%1:%2]").arg(error.files[i]).arg(error.lines[i]); + if (i < error.lines.size() - 1 && error.lines.size() > 0) { line += " -> "; } - if (i == lines.size() - 1) + if (i == error.lines.size() - 1) { line += ": "; } } - line += QString("(%1) %2").arg(severity).arg(msg); + line += QString("(%1) %2").arg(error.severity).arg(error.msg); mTxtWriter << line << endl; } diff --git a/gui/txtreport.h b/gui/txtreport.h index f3035536a..8dab58622 100644 --- a/gui/txtreport.h +++ b/gui/txtreport.h @@ -58,10 +58,9 @@ public: /** * @brief Write error to report. + * @param error Error data. */ - virtual void WriteError(const QStringList &files, const QStringList &lines, - const QString &id, const QString &severity, - const QString &msg); + virtual void WriteError(const ErrorItem &error); private: diff --git a/gui/xmlreport.cpp b/gui/xmlreport.cpp index f597bd54a..57873feba 100644 --- a/gui/xmlreport.cpp +++ b/gui/xmlreport.cpp @@ -18,15 +18,29 @@ #include #include +#include +#include "erroritem.h" #include "xmlreport.h" +static const char ResultElementName[] = "results"; +static const char ErrorElementName[] = "error"; +static const char FilenameAttribute[] = "file"; +static const char LineAttribute[] = "line"; +static const char IdAttribute[] = "id"; +static const char SeverityAttribute[] = "severity"; +static const char MsgAttribute[] = "msg"; + XmlReport::XmlReport(const QString &filename, QObject * parent) : - Report(filename, parent) + Report(filename, parent), + mXmlReader(NULL), + mXmlWriter(NULL) { } XmlReport::~XmlReport() { + delete mXmlReader; + delete mXmlWriter; Close(); } @@ -35,7 +49,18 @@ bool XmlReport::Create() bool success = false; if (Report::Create()) { - mXmlWriter.setDevice(Report::GetFile()); + mXmlWriter = new QXmlStreamWriter(Report::GetFile()); + success = true; + } + return success; +} + +bool XmlReport::Open() +{ + bool success = false; + if (Report::Open()) + { + mXmlReader = new QXmlStreamReader(Report::GetFile()); success = true; } return success; @@ -43,19 +68,18 @@ bool XmlReport::Create() void XmlReport::WriteHeader() { - mXmlWriter.setAutoFormatting(true); - mXmlWriter.writeStartDocument(); - mXmlWriter.writeStartElement("results"); + mXmlWriter->setAutoFormatting(true); + mXmlWriter->writeStartDocument(); + mXmlWriter->writeStartElement(ResultElementName); } void XmlReport::WriteFooter() { - mXmlWriter.writeEndElement(); - mXmlWriter.writeEndDocument(); + mXmlWriter->writeEndElement(); + mXmlWriter->writeEndDocument(); } -void XmlReport::WriteError(const QStringList &files, const QStringList &lines, - const QString &id, const QString &severity, const QString &msg) +void XmlReport::WriteError(const ErrorItem &error) { /* Error example from the core program in xml @@ -63,11 +87,73 @@ void XmlReport::WriteError(const QStringList &files, const QStringList &lines, The callstack seems to be ignored here aswell, instead last item of the stack is used */ - mXmlWriter.writeStartElement("error"); - mXmlWriter.writeAttribute("file", files[files.size() - 1]); - mXmlWriter.writeAttribute("line", lines[lines.size() - 1]); - mXmlWriter.writeAttribute("id", id); - mXmlWriter.writeAttribute("severity", severity); - mXmlWriter.writeAttribute("msg", msg); - mXmlWriter.writeEndElement(); + mXmlWriter->writeStartElement(ErrorElementName); + mXmlWriter->writeAttribute(FilenameAttribute, error.files[error.files.size() - 1]); + const QString line = QString::number(error.lines[error.lines.size() - 1]); + mXmlWriter->writeAttribute(LineAttribute, line); + mXmlWriter->writeAttribute(IdAttribute, error.id); + mXmlWriter->writeAttribute(SeverityAttribute, error.severity); + mXmlWriter->writeAttribute(MsgAttribute, error.msg); + mXmlWriter->writeEndElement(); +} + +QList XmlReport::Read() +{ + QList errors; + bool insideResults = false; + if (!mXmlReader) + { + qDebug() << "You must Open() the file before reading it!"; + return errors; + } + while (!mXmlReader->atEnd()) + { + switch (mXmlReader->readNext()) + { + case QXmlStreamReader::StartElement: + if (mXmlReader->name() == ResultElementName) + insideResults = true; + + // Read error element from inside result element + if (insideResults && mXmlReader->name() == ErrorElementName) + { + ErrorLine line = ReadError(mXmlReader); + errors.append(line); + } + break; + + case QXmlStreamReader::EndElement: + if (mXmlReader->name() == ResultElementName) + insideResults = false; + break; + + // Not handled + case QXmlStreamReader::NoToken: + case QXmlStreamReader::Invalid: + case QXmlStreamReader::StartDocument: + case QXmlStreamReader::EndDocument: + case QXmlStreamReader::Characters: + case QXmlStreamReader::Comment: + case QXmlStreamReader::DTD: + case QXmlStreamReader::EntityReference: + case QXmlStreamReader::ProcessingInstruction: + break; + } + } + return errors; +} + +ErrorLine XmlReport::ReadError(QXmlStreamReader *reader) +{ + ErrorLine line; + if (reader->name().toString() == ErrorElementName) + { + QXmlStreamAttributes attribs = reader->attributes(); + line.file = attribs.value("", FilenameAttribute).toString(); + line.line = attribs.value("", LineAttribute).toString(); + line.id = attribs.value("", IdAttribute).toString(); + line.severity = attribs.value("", SeverityAttribute).toString(); + line.msg = attribs.value("", MsgAttribute).toString(); + } + return line; } diff --git a/gui/xmlreport.h b/gui/xmlreport.h index ab017b43e..f850707c3 100644 --- a/gui/xmlreport.h +++ b/gui/xmlreport.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include "report.h" @@ -47,6 +48,11 @@ public: */ virtual bool Create(); + /** + * @brief Open existing report file. + */ + bool Open(); + /** * @brief Write report header. */ @@ -59,16 +65,32 @@ public: /** * @brief Write error to report. + * @param error Error data. */ - virtual void WriteError(const QStringList &files, const QStringList &lines, - const QString &id, const QString &severity, const QString &msg); + virtual void WriteError(const ErrorItem &error); + + /** + * @brief Read contents of the report file. + */ + QList Read(); + +protected: + /** + * @brief Read and parse error item from XML stream. + * @param reader XML stream reader to use. + */ + ErrorLine ReadError(QXmlStreamReader *reader); private: + /** + * @brief XML stream reader for reading the report in XML format. + */ + QXmlStreamReader *mXmlReader; /** * @brief XML stream writer for writing the report in XML format. */ - QXmlStreamWriter mXmlWriter; + QXmlStreamWriter *mXmlWriter; }; /// @} #endif // XML_REPORT_H