Skip to content

Commit

Permalink
Appstatisticsmonitor: Add statistics monitor plugin
Browse files Browse the repository at this point in the history
The plugin adds a new tab to Navigation Widget. The tab contains
two charts CPU consumption and Memory consumption for started
applications in QtC. There is a combobox by which a monitored
application can be chosen.

Change-Id: I0747c90e73a289d65aabd31672f3accf74f00749
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: hjk <hjk@qt.io>
  • Loading branch information
pointhex committed May 15, 2024
1 parent 19355cc commit de18097
Show file tree
Hide file tree
Showing 14 changed files with 866 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/plugins/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ add_subdirectory(perfprofiler)
add_subdirectory(qbsprojectmanager)
add_subdirectory(ctfvisualizer)
add_subdirectory(squish)
add_subdirectory(appstatisticsmonitor)

# Level 8:
add_subdirectory(boot2qt)
Expand Down
19 changes: 19 additions & 0 deletions src/plugins/appstatisticsmonitor/AppStatisticsMonitor.json.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"Name" : "AppStatisticsMonitor",
"Version" : "${IDE_VERSION}",
"CompatVersion" : "${IDE_VERSION_COMPAT}",
"Experimental" : true,
"Vendor" : "The Qt Company Ltd",
"Copyright" : "(C) ${IDE_COPYRIGHT_YEAR} The Qt Company Ltd",
"License" : [ "Commercial Usage",
"",
"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt Commercial License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and The Qt Company.",
"",
"GNU General Public License Usage",
"",
"Alternatively, this plugin may be used under the terms of the GNU General Public License version 3 as published by the Free Software Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT included in the packaging of this plugin. Please review the following information to ensure the GNU General Public License requirements will be met: https://www.gnu.org/licenses/gpl-3.0.html."
],
"Description" : "AppStatisticsMonitor, a plugin designed to enhance your Qt Creator experience. With its seamless integration, this plugin adds a dedicated tab to your Navigation Widget, providing insightful visualizations of CPU and Memory consumption for running applications within Qt Creator. Simply select the desired application from the combobox to monitor its performance in real-time.",
"Url" : "http://www.qt.io",
${IDE_PLUGIN_DEPENDENCIES}
}
10 changes: 10 additions & 0 deletions src/plugins/appstatisticsmonitor/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
add_qtc_plugin(AppStatisticsMonitor
SKIP_TRANSLATION
PLUGIN_DEPENDS Core ProjectExplorer
SOURCES
appstatisticsmonitorplugin.cpp
chart.cpp chart.h
manager.cpp manager.h
idataprovider.h idataprovider.cpp
)

21 changes: 21 additions & 0 deletions src/plugins/appstatisticsmonitor/appstatisticsmonitor.qbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import qbs 1.0

QtcPlugin {
name: "AppStatisticsMonitor"

Depends { name: "Core" }
Depends { name: "ProjectExplorer" }
Depends { name: "Qt"; submodules: ["widgets", "xml", "network"] }

files: [
"appstatisticsmonitorplugin.cpp",
"chart.h",
"chart.cpp",
"manager.h",
"manager.cpp",
"idataprovider.h",
"idataprovider.cpp",
"tr.h"
]
}

32 changes: 32 additions & 0 deletions src/plugins/appstatisticsmonitor/appstatisticsmonitorplugin.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0

#include "manager.h"

#include <extensionsystem/iplugin.h>

#include <QString>

namespace AppStatisticsMonitor::Internal {

class AppStatisticsMonitorPlugin final : public ExtensionSystem::IPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "AppStatisticsMonitor.json")

private:
void initialize() final;
std::unique_ptr<AppStatisticsMonitorManager> m_appstatisticsmonitorManager;
std::unique_ptr<AppStatisticsMonitorViewFactory> m_appstatisticsmonitorViewFactory;
};

void AppStatisticsMonitorPlugin::initialize()
{
m_appstatisticsmonitorManager = std::make_unique<AppStatisticsMonitorManager>();
m_appstatisticsmonitorViewFactory = std::make_unique<AppStatisticsMonitorViewFactory>(
m_appstatisticsmonitorManager.get());
}

} // namespace AppStatisticsMonitor::Internal

#include <appstatisticsmonitorplugin.moc>
164 changes: 164 additions & 0 deletions src/plugins/appstatisticsmonitor/chart.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0

#include "chart.h"

#include <utils/theme/theme.h>

#include <QPaintEvent>
#include <QPainter>
#include <QPen>
#include <QPointF>
#include <QString>

namespace AppStatisticsMonitor::Internal {

static const int padding = 40;
static const int numPadding = 10;
static const QRectF dataRangeDefault = QRectF(0, 0, 5, 1);

Chart::Chart(const QString &name, QWidget *parent)
: QWidget(parent)
, m_name(name)
{
setMinimumHeight(200);
setMinimumWidth(400);
}

void Chart::addNewPoint(const QPointF &point)
{
m_points.append(point);
update();
}

void Chart::loadNewProcessData(QList<double> data)
{
clear();
for (long i = 0; i < data.size(); ++i) {
m_points.append(QPointF(i + 1, data[i]));
}
update();
}

double Chart::lastPointX() const
{
if (m_points.isEmpty())
return 0;
return m_points.last().x();
}

void Chart::clear()
{
m_points.clear();
addNewPoint({0, 0});
update();
}

void Chart::paintEvent(QPaintEvent *event)
{
Q_UNUSED(event);
QPainter painter(this);

painter.fillRect(rect(), Utils::creatorTheme()->color(Utils::Theme::Token_Background_Default));

// add the name of the chart in the middle of the widget width and on the top
painter.drawText(
rect(),
Qt::AlignHCenter | Qt::AlignTop,
m_name + QString::number(m_points.last().y(), 'g', 4) + "%");

const QRectF dataRange = calculateDataRange();
updateScalingFactors(dataRange);

for (double x = dataRange.left(); x <= dataRange.right(); x += m_xGridStep) {
double xPos = padding + (x - dataRange.left()) * m_xScale;
if (xPos < padding || xPos > width() - padding)
continue;
painter.setPen(Utils::creatorTheme()->color(Utils::Theme::Token_Foreground_Default));
painter.drawLine(xPos, padding, xPos, height() - padding);

painter.setPen(Utils::creatorTheme()->color(Utils::Theme::Token_Text_Muted));
painter.drawText(xPos, height() - numPadding, QString::number(x));
}

for (double y = dataRange.top(); y <= dataRange.bottom(); y += m_yGridStep) {
double yPos = height() - padding - (y - (int) dataRange.top()) * m_yScale;
if (yPos < padding || yPos > height() - padding)
continue;

painter.setPen(Utils::creatorTheme()->color(Utils::Theme::Token_Foreground_Default));
painter.drawLine(padding, yPos, width() - padding, yPos);

painter.setPen(Utils::creatorTheme()->color(Utils::Theme::Token_Text_Muted));
painter.drawText(numPadding, yPos, QString::number(y));
}

painter.setPen(Utils::creatorTheme()->color(Utils::Theme::Token_Foreground_Default));
painter.drawLine(padding, height() - padding, width() - padding, height() - padding); // X axis
painter.drawLine(padding, height() - padding, padding, padding); // Y axis

QPen pen(Utils::creatorTheme()->color(Utils::Theme::Token_Accent_Default));
pen.setWidth(2);
painter.setPen(pen);
painter.setRenderHint(QPainter::Antialiasing);
for (int i = 1; i < m_points.size(); ++i) {
QPointF startPoint(
padding + (m_points[i - 1].x() - dataRange.left()) * m_xScale,
height() - padding - (m_points[i - 1].y() - dataRange.top()) * m_yScale);
QPointF endPoint(
padding + (m_points[i].x() - dataRange.left()) * m_xScale,
height() - padding - (m_points[i].y() - dataRange.top()) * m_yScale);
painter.drawLine(startPoint, endPoint);
}
}

void Chart::addPoint()
{
for (int i = 0; i < 10; ++i) {
double x = m_points.size();
double y = sin(x) + 10 * cos(x / 10) + 10;
m_points.append(QPointF(x, y));
}
update();
}

QRectF Chart::calculateDataRange() const
{
QRectF dataRange = QRectF(0, 0, 0, 0);

if (m_points.isEmpty())
return dataRange;

for (const QPointF &point : m_points) {
dataRange.setLeft(qMin(dataRange.left(), point.x()));
dataRange.setRight(qMax(dataRange.right(), point.x()));

dataRange.setBottom(qMin(dataRange.bottom(), point.y()));
dataRange.setTop(qMax(dataRange.top(), point.y()));
}
dataRange.setRight(round(dataRange.right()) + 1);
dataRange.setTop(round(dataRange.top()) + 1);

dataRange = dataRange.united(dataRangeDefault);
return dataRange;
}

void Chart::updateScalingFactors(const QRectF &dataRange)
{
const double xRange = dataRange.right() - dataRange.left();
double yRange = dataRange.bottom() - dataRange.top();
yRange = yRange == 0 ? dataRange.top() : yRange;

m_xGridStep = qRound(xRange / 10);
m_xGridStep = m_xGridStep == 0 ? 1 : m_xGridStep;

m_yGridStep = yRange / 5;
m_yGridStep = qRound(m_yGridStep * 10.0) / 10.0;
if (yRange > 10)
m_yGridStep = qRound(m_yGridStep);
m_yGridStep = qMax(m_yGridStep, 0.1);

m_xScale = (width() - 2 * padding) / xRange;
m_yScale = (height() - 2 * padding) / yRange;
}
} // namespace AppStatisticsMonitor::Internal
40 changes: 40 additions & 0 deletions src/plugins/appstatisticsmonitor/chart.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once

#include <QList>
#include <QPaintEvent>
#include <QPointF>
#include <QRectF>
#include <QWidget>

namespace AppStatisticsMonitor::Internal {

class Chart : public QWidget
{
public:
Chart(const QString &name, QWidget *parent = nullptr);

void addNewPoint(const QPointF &point);
void loadNewProcessData(QList<double> data);
double lastPointX() const;

void clear();

private:
void paintEvent(QPaintEvent *event) override;
void addPoint();
QRectF calculateDataRange() const;
void updateScalingFactors(const QRectF &dataRange);

private:
QList<QPointF> m_points;
QString m_name;

double m_xScale = 1;
double m_yScale = 1;
double m_xGridStep = 1;
double m_yGridStep = 1;
};

} // namespace AppStatisticsMonitor::Internal

0 comments on commit de18097

Please sign in to comment.