25 #include "ui_statsdialog.h"
27 #include <QApplication>
30 #include <QFileDialog>
37 #include <QPlainTextEdit>
39 #include <QPushButton>
40 #include <QStringList>
41 #include <QTextDocument>
48 #include <QAbstractSeries>
51 #include <QDateTimeAxis>
56 #include <QLineSeries>
60 #include <QRegularExpression>
61 #include <QTextStream>
64 #if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
65 QT_CHARTS_USE_NAMESPACE
68 static QLineSeries *numberOfReports(
const QString &fileName,
const QString &severity);
69 static QChartView *createChart(
const QString &statsFile,
const QString &tool);
80 QFont font(
"courier");
81 font.setStyleHint(QFont::Monospace);
82 mUI->mCheckersReport->setFont(font);
84 setWindowFlags(Qt::Window);
103 #ifndef QT_CHARTS_LIB
104 mUI->mTabHistory->setVisible(
false);
108 const QString prjpath = QFileInfo(projectFile->
getFilename()).absolutePath();
109 const QString buildDir = prjpath +
'/' + projectFile->
getBuildDir();
110 if (QDir(buildDir).exists()) {
111 statsFile = buildDir +
"/statistics.txt";
114 mUI->mLblHistoryFile->setText(tr(
"File: ") + (statsFile.isEmpty() ? tr(
"No cppcheck build dir") : statsFile));
115 if (!statsFile.isEmpty()) {
116 QChartView *chartView = createChart(statsFile,
"cppcheck");
117 mUI->mTabHistory->layout()->addWidget(chartView);
120 mUI->mTabHistory->layout()->addWidget(chartView);
123 chartView = createChart(statsFile,
CLANG_TIDY);
124 mUI->mTabHistory->layout()->addWidget(chartView);
129 mUI->mProject->setText(QString());
130 mUI->mPaths->setText(QString());
131 mUI->mIncludePaths->setText(QString());
132 mUI->mDefines->setText(QString());
133 mUI->mUndefines->setText(QString());
139 mUI->mPath->setText(path);
144 mUI->mNumberOfFilesScanned->setText(QString::number(num));
151 const int days = secs / (24 * 60 * 60);
152 secs -= days * (24 * 60 * 60);
153 const int hours = secs / (60 * 60);
154 secs -= hours * (60 * 60);
155 const int mins = secs / 60;
161 parts << ((days == 1) ? tr(
"1 day") : tr(
"%1 days").arg(days));
163 parts << ((hours == 1) ? tr(
"1 hour") : tr(
"%1 hours").arg(hours));
164 if (mins && parts.size() < 2)
165 parts << ((mins == 1) ? tr(
"1 minute") : tr(
"%1 minutes").arg(mins));
166 if (secs && parts.size() < 2)
167 parts << ((secs == 1) ? tr(
"1 second") : tr(
"%1 seconds").arg(secs));
171 parts << tr(
"0.%1 seconds").arg(
int(10.0 *(seconds - secs)));
173 mUI->mScanDuration->setText(parts.join(tr(
" and ")));
177 const QString Stat = QString(
178 "<center><h1>%1 %2</h1></center>\n"
179 "<font color=\"red\"><h3>%3 : %4</h3></font>\n"
180 "<font color=\"green\"><h3>%5 : %6</h3></font>\n"
181 "<font color=\"orange\"><h3>%7 : %8</h3></font>\n"
182 "<font color=\"blue\"><h3>%9 : %10</h3></font>\n"
183 "<font color=\"blue\"><h3>%11 : %12</h3></font>\n"
184 "<font color=\"purple\"><h3>%13 : %14</h3></font>\n")
185 .arg(tr(
"Statistics"))
186 .arg(QDate::currentDate().
toString(
"dd.MM.yyyy"))
191 .arg(tr(
"Style warnings"))
193 .arg(tr(
"Portability warnings"))
195 .arg(tr(
"Performance warnings"))
197 .arg(tr(
"Information messages"))
200 QString fileName = QFileDialog::getSaveFileName((QWidget*)
nullptr, tr(
"Export PDF"), QString(),
"*.pdf");
201 if (QFileInfo(fileName).suffix().isEmpty()) {
202 fileName.append(
".pdf");
204 QPrinter printer(QPrinter::PrinterResolution);
205 printer.setOutputFormat(QPrinter::PdfFormat);
206 printer.setPageSize(QPageSize(QPageSize::A4));
207 printer.setOutputFileName(fileName);
218 QClipboard *clipboard = QApplication::clipboard();
222 const QString projSettings(tr(
"Project Settings"));
223 const QString project(tr(
"Project"));
224 const QString paths(tr(
"Paths"));
225 const QString incPaths(tr(
"Include paths"));
226 const QString defines(tr(
"Defines"));
227 const QString undefines(tr(
"Undefines"));
228 const QString prevScan(tr(
"Previous Scan"));
229 const QString selPath(tr(
"Path selected"));
230 const QString numFiles(tr(
"Number of files scanned"));
231 const QString duration(tr(
"Scan duration"));
232 const QString stats(tr(
"Statistics"));
233 const QString errors(tr(
"Errors"));
234 const QString warnings(tr(
"Warnings"));
235 const QString
style(tr(
"Style warnings"));
236 const QString
portability(tr(
"Portability warnings"));
237 const QString
performance(tr(
"Performance warnings"));
238 const QString
information(tr(
"Information messages"));
241 const QString settings = QString(
251 .arg(
mUI->mProject->text())
253 .arg(
mUI->mPaths->text())
255 .arg(
mUI->mIncludePaths->text())
257 .arg(
mUI->mDefines->text())
259 .arg(
mUI->mUndefines->text());
261 const QString previous = QString(
269 .arg(
mUI->mPath->text())
271 .arg(
mUI->mNumberOfFilesScanned->text())
273 .arg(
mUI->mScanDuration->text());
275 const QString statistics = QString(
298 const QString textSummary = settings + previous + statistics;
301 const QString htmlSettings = QString(
304 " <tr><th>%2:</th><td>%3</td></tr>\n"
305 " <tr><th>%4:</th><td>%5</td></tr>\n"
306 " <tr><th>%6:</th><td>%7</td></tr>\n"
307 " <tr><th>%8:</th><td>%9</td></tr>\n"
308 " <tr><th>%10:</th><td>%11</td></tr>\n"
313 .arg(
mUI->mProject->text())
315 .arg(
mUI->mPaths->text())
317 .arg(
mUI->mIncludePaths->text())
319 .arg(
mUI->mDefines->text())
321 .arg(
mUI->mUndefines->text());
323 const QString htmlPrevious = QString(
326 " <tr><th>%2:</th><td>%3</td></tr>\n"
327 " <tr><th>%4:</th><td>%5</td></tr>\n"
328 " <tr><th>%6:</th><td>%7</td></tr>\n"
333 .arg(
mUI->mPath->text())
335 .arg(
mUI->mNumberOfFilesScanned->text())
337 .arg(
mUI->mScanDuration->text());
339 const QString htmlStatistics = QString(
341 " <tr><th>%2:</th><td>%3</td></tr>\n"
342 " <tr><th>%4:</th><td>%5</td></tr>\n"
343 " <tr><th>%6:</th><td>%7</td></tr>\n"
344 " <tr><th>%8:</th><td>%9</td></tr>\n"
345 " <tr><th>%10:</th><td>%11</td></tr>\n"
346 " <tr><th>%12:</th><td>%13</td></tr>\n"
363 const QString htmlSummary = htmlSettings + htmlPrevious + htmlStatistics;
365 auto *mimeData =
new QMimeData();
366 mimeData->setText(textSummary);
367 mimeData->setHtml(htmlSummary);
368 clipboard->setMimeData(mimeData);
385 QChartView *createChart(
const QString &statsFile,
const QString &tool)
387 auto *chart =
new QChart;
388 chart->addSeries(numberOfReports(statsFile, tool +
"-error"));
389 chart->addSeries(numberOfReports(statsFile, tool +
"-warning"));
390 chart->addSeries(numberOfReports(statsFile, tool +
"-style"));
391 chart->addSeries(numberOfReports(statsFile, tool +
"-performance"));
392 chart->addSeries(numberOfReports(statsFile, tool +
"-portability"));
394 auto *axisX =
new QDateTimeAxis;
395 axisX->setTitleText(
"Date");
396 chart->addAxis(axisX, Qt::AlignBottom);
398 for (QAbstractSeries *s : chart->series()) {
399 s->attachAxis(axisX);
402 auto *axisY =
new QValueAxis;
403 axisY->setLabelFormat(
"%i");
404 axisY->setTitleText(
"Count");
405 chart->addAxis(axisY, Qt::AlignLeft);
408 for (QAbstractSeries *s : chart->series()) {
409 s->attachAxis(axisY);
410 if (
const auto *ls =
dynamic_cast<const QLineSeries*
>(s)) {
411 for (QPointF p : ls->points()) {
420 chart->setTitle(tool);
422 auto *chartView =
new QChartView(chart);
423 chartView->setRenderHint(QPainter::Antialiasing);
427 QLineSeries *numberOfReports(
const QString &fileName,
const QString &severity)
429 auto *series =
new QLineSeries();
430 series->setName(severity);
432 if (f.open(QIODevice::ReadOnly | QIODevice::Text)) {
435 while (!in.atEnd()) {
436 QString line = in.readLine();
437 static const QRegularExpression rxdate(
"^\\[(\\d\\d)\\.(\\d\\d)\\.(\\d\\d\\d\\d)\\]$");
438 const QRegularExpressionMatch matchRes = rxdate.match(line);
439 if (matchRes.hasMatch()) {
440 const int y = matchRes.captured(3).toInt();
441 const int m = matchRes.captured(2).toInt();
442 const int d = matchRes.captured(1).toInt();
444 dt.setDate(QDate(y,m,d));
445 if (t == dt.toMSecsSinceEpoch())
448 t = dt.toMSecsSinceEpoch();
450 if (line.startsWith(severity +
':')) {
451 const int y = line.mid(1+severity.length()).toInt();
452 series->append(t, y);
A class for check statistics.
const QString & getCheckersReport() const
unsigned getCount(const QString &tool, ShowTypes::ShowType type) const
Return statistics for given type.
int getNumberOfActiveCheckers() const
A class that reads and writes project files.
const QString & getFilename() const
Get filename for the project file.
const QString & getRootPath() const
Get project root path.
bool getClangAnalyzer() const
const QStringList & getDefines() const
Get list of defines.
QStringList getCheckPaths() const
Get list of paths to check.
bool getClangTidy() const
const QStringList & getUndefines() const
Get list of undefines.
QStringList getIncludeDirs() const
Get list of include directories.
const QString & getBuildDir() const
A dialog that shows project and scan statistics.
void setScanDuration(double seconds)
Sets the number of seconds to display beside "Scan Duration:".
void setNumberOfFilesScanned(int num)
Sets the number to display beside "Number of Files Scanned:".
void setProject(const ProjectFile *projectFile)
Sets the project to extract statistics from.
void setStatistics(const CheckStatistics *stats)
Sets the numbers of different error/warnings found.
void setPathSelected(const QString &path)
Sets the string to display beside "Path Selected:".
const CheckStatistics * mStatistics
StatsDialog(QWidget *parent=nullptr)
std::string toString(Color c)
@ portability
Portability warning.
@ information
Checking information.
@ performance
Performance warning.
static const QString CPPCHECK("cppcheck")