2022-12-12 16:45:31 +01:00
|
|
|
// Copyright (C) 2022 The Qt Company Ltd.
|
2023-05-24 10:27:35 +02:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2022-11-28 09:48:11 +01:00
|
|
|
|
|
|
|
|
#include "axivionplugin.h"
|
|
|
|
|
|
|
|
|
|
#include "axivionoutputpane.h"
|
2022-12-13 11:17:12 +01:00
|
|
|
#include "axivionprojectsettings.h"
|
2022-12-14 12:11:03 +01:00
|
|
|
#include "axivionquery.h"
|
|
|
|
|
#include "axivionresultparser.h"
|
2023-09-15 12:25:04 +02:00
|
|
|
#include "axivionsettings.h"
|
2022-12-13 11:17:12 +01:00
|
|
|
#include "axiviontr.h"
|
2023-07-25 18:48:18 +02:00
|
|
|
#include "dashboard/dto.h"
|
2023-11-24 12:29:17 +01:00
|
|
|
#include "dashboard/error.h"
|
2022-11-28 09:48:11 +01:00
|
|
|
|
2022-12-16 15:12:39 +01:00
|
|
|
#include <coreplugin/editormanager/documentmodel.h>
|
2022-12-16 23:11:46 +01:00
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2023-09-15 12:25:04 +02:00
|
|
|
#include <coreplugin/icore.h>
|
2022-12-14 12:11:03 +01:00
|
|
|
#include <coreplugin/messagemanager.h>
|
2023-03-01 17:54:39 +01:00
|
|
|
|
2024-01-12 08:38:31 +01:00
|
|
|
#include <extensionsystem/iplugin.h>
|
2022-12-12 16:45:31 +01:00
|
|
|
#include <extensionsystem/pluginmanager.h>
|
2023-03-01 17:54:39 +01:00
|
|
|
|
2022-12-16 15:12:39 +01:00
|
|
|
#include <projectexplorer/buildsystem.h>
|
2022-12-13 11:17:12 +01:00
|
|
|
#include <projectexplorer/project.h>
|
2023-03-01 17:54:39 +01:00
|
|
|
#include <projectexplorer/projectmanager.h>
|
|
|
|
|
|
2023-11-24 12:29:17 +01:00
|
|
|
#include <solutions/tasking/networkquery.h>
|
|
|
|
|
#include <solutions/tasking/tasktreerunner.h>
|
|
|
|
|
|
2022-12-16 23:11:46 +01:00
|
|
|
#include <texteditor/textdocument.h>
|
|
|
|
|
#include <texteditor/texteditor.h>
|
|
|
|
|
#include <texteditor/textmark.h>
|
2023-03-01 17:54:39 +01:00
|
|
|
|
2023-09-15 12:25:04 +02:00
|
|
|
#include <utils/algorithm.h>
|
2023-11-24 12:29:17 +01:00
|
|
|
#include <utils/async.h>
|
2023-07-25 18:48:18 +02:00
|
|
|
#include <utils/expected.h>
|
2023-08-29 15:42:08 +02:00
|
|
|
#include <utils/networkaccessmanager.h>
|
2022-12-13 11:17:12 +01:00
|
|
|
#include <utils/qtcassert.h>
|
2023-01-13 14:38:39 +01:00
|
|
|
#include <utils/utilsicons.h>
|
2022-11-28 09:48:11 +01:00
|
|
|
|
2023-01-13 14:38:39 +01:00
|
|
|
#include <QAction>
|
2023-08-29 15:42:08 +02:00
|
|
|
#include <QFutureWatcher>
|
2023-09-15 12:25:04 +02:00
|
|
|
#include <QMessageBox>
|
|
|
|
|
#include <QNetworkAccessManager>
|
|
|
|
|
#include <QNetworkReply>
|
2022-12-14 12:11:03 +01:00
|
|
|
#include <QTimer>
|
2022-12-13 15:13:13 +01:00
|
|
|
|
2023-07-25 18:48:18 +02:00
|
|
|
#include <exception>
|
|
|
|
|
#include <memory>
|
|
|
|
|
|
2023-01-09 07:31:50 +01:00
|
|
|
constexpr char AxivionTextMarkId[] = "AxivionTextMark";
|
|
|
|
|
|
2023-11-24 12:29:17 +01:00
|
|
|
using namespace Tasking;
|
|
|
|
|
using namespace Utils;
|
|
|
|
|
|
2022-11-28 09:48:11 +01:00
|
|
|
namespace Axivion::Internal {
|
|
|
|
|
|
2022-12-14 12:11:03 +01:00
|
|
|
class AxivionPluginPrivate : public QObject
|
2022-11-28 09:48:11 +01:00
|
|
|
{
|
|
|
|
|
public:
|
2023-09-15 12:25:04 +02:00
|
|
|
AxivionPluginPrivate();
|
|
|
|
|
void handleSslErrors(QNetworkReply *reply, const QList<QSslError> &errors);
|
2022-12-16 23:01:01 +01:00
|
|
|
void onStartupProjectChanged();
|
2022-12-14 12:11:03 +01:00
|
|
|
void fetchProjectInfo(const QString &projectName);
|
2022-12-16 15:12:39 +01:00
|
|
|
void handleOpenedDocs(ProjectExplorer::Project *project);
|
2022-12-16 23:11:46 +01:00
|
|
|
void onDocumentOpened(Core::IDocument *doc);
|
|
|
|
|
void onDocumentClosed(Core::IDocument * doc);
|
2022-12-16 22:34:56 +01:00
|
|
|
void clearAllMarks();
|
2022-12-16 23:11:46 +01:00
|
|
|
void handleIssuesForFile(const IssuesList &issues);
|
2023-01-13 14:38:39 +01:00
|
|
|
void fetchRuleInfo(const QString &id);
|
2022-12-14 12:11:03 +01:00
|
|
|
|
2023-11-24 12:29:17 +01:00
|
|
|
NetworkAccessManager m_networkAccessManager;
|
2023-01-09 07:41:22 +01:00
|
|
|
AxivionOutputPane m_axivionOutputPane;
|
2023-11-24 12:29:17 +01:00
|
|
|
std::optional<Dto::ProjectInfoDto> m_currentProjectInfo;
|
2023-01-09 07:41:22 +01:00
|
|
|
bool m_runningQuery = false;
|
2023-11-24 12:29:17 +01:00
|
|
|
TaskTreeRunner m_taskTreeRunner;
|
2022-11-28 09:48:11 +01:00
|
|
|
};
|
|
|
|
|
|
2022-12-13 11:17:12 +01:00
|
|
|
static AxivionPluginPrivate *dd = nullptr;
|
|
|
|
|
|
2023-01-13 13:49:40 +01:00
|
|
|
class AxivionTextMark : public TextEditor::TextMark
|
|
|
|
|
{
|
|
|
|
|
public:
|
2023-11-24 12:29:17 +01:00
|
|
|
AxivionTextMark(const FilePath &filePath, const ShortIssue &issue);
|
2023-01-13 13:49:40 +01:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
QString m_id;
|
|
|
|
|
};
|
|
|
|
|
|
2023-11-24 12:29:17 +01:00
|
|
|
AxivionTextMark::AxivionTextMark(const FilePath &filePath, const ShortIssue &issue)
|
2023-01-13 13:49:40 +01:00
|
|
|
: TextEditor::TextMark(filePath, issue.lineNumber, {Tr::tr("Axivion"), AxivionTextMarkId})
|
|
|
|
|
, m_id(issue.id)
|
|
|
|
|
{
|
|
|
|
|
const QString markText = issue.entity.isEmpty() ? issue.message
|
|
|
|
|
: issue.entity + ": " + issue.message;
|
|
|
|
|
setToolTip(issue.errorNumber + " " + markText);
|
|
|
|
|
setPriority(TextEditor::TextMark::NormalPriority);
|
|
|
|
|
setLineAnnotation(markText);
|
2023-01-13 14:38:39 +01:00
|
|
|
setActionsProvider([this]{
|
|
|
|
|
auto action = new QAction;
|
|
|
|
|
action->setIcon(Utils::Icons::INFO.icon());
|
|
|
|
|
action->setToolTip(Tr::tr("Show rule details"));
|
|
|
|
|
QObject::connect(action, &QAction::triggered,
|
|
|
|
|
dd, [this]{ dd->fetchRuleInfo(m_id); });
|
|
|
|
|
return QList{action};
|
|
|
|
|
});
|
2023-01-13 13:49:40 +01:00
|
|
|
}
|
|
|
|
|
|
2024-01-12 08:38:31 +01:00
|
|
|
void fetchProjectInfo(const QString &projectName)
|
2022-12-14 12:11:03 +01:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(dd, return);
|
|
|
|
|
dd->fetchProjectInfo(projectName);
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-24 12:29:17 +01:00
|
|
|
std::optional<Dto::ProjectInfoDto> projectInfo()
|
2022-12-14 13:53:00 +01:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(dd, return {});
|
2023-01-09 07:41:22 +01:00
|
|
|
return dd->m_currentProjectInfo;
|
2022-12-14 13:53:00 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-15 12:25:04 +02:00
|
|
|
// FIXME: extend to give some details?
|
|
|
|
|
// FIXME: move when curl is no more in use?
|
2024-01-12 08:38:31 +01:00
|
|
|
bool handleCertificateIssue()
|
2023-09-15 12:25:04 +02:00
|
|
|
{
|
|
|
|
|
QTC_ASSERT(dd, return false);
|
|
|
|
|
const QString serverHost = QUrl(settings().server.dashboard).host();
|
|
|
|
|
if (QMessageBox::question(Core::ICore::dialogParent(), Tr::tr("Certificate Error"),
|
|
|
|
|
Tr::tr("Server certificate for %1 cannot be authenticated.\n"
|
|
|
|
|
"Do you want to disable SSL verification for this server?\n"
|
|
|
|
|
"Note: This can expose you to man-in-the-middle attack.")
|
|
|
|
|
.arg(serverHost))
|
|
|
|
|
!= QMessageBox::Yes) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
settings().server.validateCert = false;
|
|
|
|
|
settings().apply();
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AxivionPluginPrivate::AxivionPluginPrivate()
|
|
|
|
|
{
|
2023-10-24 13:54:55 +02:00
|
|
|
#if QT_CONFIG(ssl)
|
2023-09-15 12:25:04 +02:00
|
|
|
connect(&m_networkAccessManager, &QNetworkAccessManager::sslErrors,
|
|
|
|
|
this, &AxivionPluginPrivate::handleSslErrors);
|
2023-10-24 13:54:55 +02:00
|
|
|
#endif // ssl
|
2023-09-15 12:25:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AxivionPluginPrivate::handleSslErrors(QNetworkReply *reply, const QList<QSslError> &errors)
|
|
|
|
|
{
|
2023-10-24 13:54:55 +02:00
|
|
|
#if QT_CONFIG(ssl)
|
2023-09-15 12:25:04 +02:00
|
|
|
const QList<QSslError::SslError> accepted{
|
|
|
|
|
QSslError::CertificateNotYetValid, QSslError::CertificateExpired,
|
|
|
|
|
QSslError::InvalidCaCertificate, QSslError::CertificateUntrusted,
|
|
|
|
|
QSslError::HostNameMismatch
|
|
|
|
|
};
|
|
|
|
|
if (Utils::allOf(errors,
|
|
|
|
|
[&accepted](const QSslError &e) { return accepted.contains(e.error()); })) {
|
2024-01-12 08:38:31 +01:00
|
|
|
if (!settings().server.validateCert || handleCertificateIssue())
|
2023-09-15 12:25:04 +02:00
|
|
|
reply->ignoreSslErrors(errors);
|
|
|
|
|
}
|
2023-10-24 13:54:55 +02:00
|
|
|
#else // ssl
|
|
|
|
|
Q_UNUSED(reply)
|
|
|
|
|
Q_UNUSED(errors)
|
|
|
|
|
#endif // ssl
|
2023-09-15 12:25:04 +02:00
|
|
|
}
|
|
|
|
|
|
2022-12-16 23:01:01 +01:00
|
|
|
void AxivionPluginPrivate::onStartupProjectChanged()
|
|
|
|
|
{
|
2023-03-01 17:54:39 +01:00
|
|
|
ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
|
2022-12-16 23:01:01 +01:00
|
|
|
if (!project) {
|
|
|
|
|
clearAllMarks();
|
2023-07-25 18:48:18 +02:00
|
|
|
m_currentProjectInfo = {};
|
2023-01-09 07:41:22 +01:00
|
|
|
m_axivionOutputPane.updateDashboard();
|
2022-12-16 23:01:01 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-08-17 16:27:44 +02:00
|
|
|
const AxivionProjectSettings *projSettings = AxivionProjectSettings::projectSettings(project);
|
2022-12-16 23:01:01 +01:00
|
|
|
fetchProjectInfo(projSettings->dashboardProjectName());
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-24 12:29:17 +01:00
|
|
|
static QUrl urlForProject(const QString &projectName)
|
|
|
|
|
{
|
|
|
|
|
QString dashboard = settings().server.dashboard;
|
|
|
|
|
if (!dashboard.endsWith(QLatin1Char('/')))
|
|
|
|
|
dashboard += QLatin1Char('/');
|
|
|
|
|
return QUrl(dashboard).resolved(QStringLiteral("api/projects/")).resolved(projectName);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static constexpr int httpStatusCodeOk = 200;
|
|
|
|
|
static const QLatin1String jsonContentType{ "application/json" };
|
|
|
|
|
|
|
|
|
|
static void deserialize(QPromise<Dto::ProjectInfoDto> &promise, const QByteArray &input)
|
|
|
|
|
{
|
|
|
|
|
promise.addResult(Dto::ProjectInfoDto::deserialize(input));
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-14 12:11:03 +01:00
|
|
|
void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName)
|
|
|
|
|
{
|
2023-11-24 12:29:17 +01:00
|
|
|
if (m_taskTreeRunner.isRunning()) { // TODO: cache in queue and run when task tree finished
|
2023-08-01 19:59:54 +02:00
|
|
|
QTimer::singleShot(3000, this, [this, projectName] { fetchProjectInfo(projectName); });
|
2022-12-14 12:11:03 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2022-12-16 22:34:56 +01:00
|
|
|
clearAllMarks();
|
2022-12-14 12:11:03 +01:00
|
|
|
if (projectName.isEmpty()) {
|
2023-07-25 18:48:18 +02:00
|
|
|
m_currentProjectInfo = {};
|
2023-01-09 07:41:22 +01:00
|
|
|
m_axivionOutputPane.updateDashboard();
|
2022-12-14 12:11:03 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2023-11-24 12:29:17 +01:00
|
|
|
|
|
|
|
|
const QUrl url = urlForProject(projectName);
|
|
|
|
|
|
2023-11-24 13:45:07 +01:00
|
|
|
struct StorageData
|
|
|
|
|
{
|
|
|
|
|
QByteArray credential;
|
|
|
|
|
QByteArray projectInfoData;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const Storage<StorageData> storage;
|
|
|
|
|
|
|
|
|
|
const auto onCredentialSetup = [storage] {
|
|
|
|
|
storage->credential = QByteArrayLiteral("AxToken ")
|
|
|
|
|
+ settings().server.token.toUtf8();
|
|
|
|
|
};
|
2023-11-24 12:29:17 +01:00
|
|
|
|
2023-11-24 13:45:07 +01:00
|
|
|
const auto onQuerySetup = [this, storage, url](NetworkQuery &query) {
|
2023-11-24 12:29:17 +01:00
|
|
|
QNetworkRequest request(url);
|
|
|
|
|
request.setRawHeader(QByteArrayLiteral("Accept"),
|
|
|
|
|
QByteArray(jsonContentType.data(), jsonContentType.size()));
|
|
|
|
|
request.setRawHeader(QByteArrayLiteral("Authorization"),
|
2023-11-24 13:45:07 +01:00
|
|
|
storage->credential);
|
2023-11-24 12:29:17 +01:00
|
|
|
const QByteArray ua = QByteArrayLiteral("Axivion")
|
|
|
|
|
+ QCoreApplication::applicationName().toUtf8()
|
|
|
|
|
+ QByteArrayLiteral("Plugin/")
|
|
|
|
|
+ QCoreApplication::applicationVersion().toUtf8();
|
|
|
|
|
request.setRawHeader(QByteArrayLiteral("X-Axivion-User-Agent"), ua);
|
|
|
|
|
query.setRequest(request);
|
|
|
|
|
query.setNetworkAccessManager(&m_networkAccessManager);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const auto onQueryDone = [storage, url](const NetworkQuery &query, DoneWith doneWith) {
|
|
|
|
|
QNetworkReply *reply = query.reply();
|
|
|
|
|
const QNetworkReply::NetworkError error = reply->error();
|
|
|
|
|
const int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
|
|
|
|
const QString contentType = reply->header(QNetworkRequest::ContentTypeHeader)
|
|
|
|
|
.toString()
|
|
|
|
|
.split(';')
|
|
|
|
|
.constFirst()
|
|
|
|
|
.trimmed()
|
|
|
|
|
.toLower();
|
|
|
|
|
if (doneWith == DoneWith::Success && statusCode == httpStatusCodeOk
|
|
|
|
|
&& contentType == jsonContentType) {
|
2023-11-24 13:45:07 +01:00
|
|
|
storage->projectInfoData = reply->readAll();
|
2023-11-24 12:29:17 +01:00
|
|
|
return DoneResult::Success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto getError = [&]() -> Error {
|
|
|
|
|
if (contentType == jsonContentType) {
|
|
|
|
|
try {
|
|
|
|
|
return DashboardError(reply->url(), statusCode,
|
|
|
|
|
reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(),
|
|
|
|
|
Dto::ErrorDto::deserialize(reply->readAll()));
|
|
|
|
|
} catch (const Dto::invalid_dto_exception &) {
|
|
|
|
|
// ignore
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (statusCode != 0) {
|
|
|
|
|
return HttpError(reply->url(), statusCode,
|
|
|
|
|
reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString(),
|
|
|
|
|
QString::fromUtf8(reply->readAll())); // encoding?
|
|
|
|
|
}
|
|
|
|
|
return NetworkError(reply->url(), error, reply->errorString());
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
Core::MessageManager::writeFlashing(
|
|
|
|
|
QStringLiteral("Axivion: %1").arg(getError().message()));
|
|
|
|
|
return DoneResult::Error;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const auto onDeserializeSetup = [storage](Async<Dto::ProjectInfoDto> &task) {
|
|
|
|
|
task.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer());
|
2023-11-24 13:45:07 +01:00
|
|
|
task.setConcurrentCallData(deserialize, storage->projectInfoData);
|
2023-11-24 12:29:17 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const auto onDeserializeDone = [this, url](const Async<Dto::ProjectInfoDto> &task,
|
|
|
|
|
DoneWith doneWith) {
|
|
|
|
|
if (doneWith == DoneWith::Success) {
|
|
|
|
|
m_currentProjectInfo = task.future().result();
|
|
|
|
|
m_axivionOutputPane.updateDashboard();
|
|
|
|
|
// handle already opened documents
|
|
|
|
|
if (auto buildSystem = ProjectExplorer::ProjectManager::startupBuildSystem();
|
|
|
|
|
!buildSystem || !buildSystem->isParsing()) {
|
|
|
|
|
handleOpenedDocs(nullptr);
|
|
|
|
|
} else {
|
|
|
|
|
connect(ProjectExplorer::ProjectManager::instance(),
|
|
|
|
|
&ProjectExplorer::ProjectManager::projectFinishedParsing,
|
|
|
|
|
this, &AxivionPluginPrivate::handleOpenedDocs);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const Group recipe {
|
|
|
|
|
storage,
|
2023-11-24 13:45:07 +01:00
|
|
|
Sync(onCredentialSetup),
|
2023-11-24 12:29:17 +01:00
|
|
|
NetworkQueryTask(onQuerySetup, onQueryDone),
|
|
|
|
|
AsyncTask<Dto::ProjectInfoDto>(onDeserializeSetup, onDeserializeDone)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
m_taskTreeRunner.start(recipe);
|
2022-12-14 12:11:03 +01:00
|
|
|
}
|
|
|
|
|
|
2023-01-13 14:38:39 +01:00
|
|
|
void AxivionPluginPrivate::fetchRuleInfo(const QString &id)
|
|
|
|
|
{
|
|
|
|
|
if (m_runningQuery) {
|
2023-08-01 19:59:54 +02:00
|
|
|
QTimer::singleShot(3000, this, [this, id] { fetchRuleInfo(id); });
|
2023-01-13 14:38:39 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const QStringList args = id.split(':');
|
|
|
|
|
QTC_ASSERT(args.size() == 2, return);
|
|
|
|
|
m_runningQuery = true;
|
|
|
|
|
AxivionQuery query(AxivionQuery::RuleInfo, args);
|
|
|
|
|
AxivionQueryRunner *runner = new AxivionQueryRunner(query, this);
|
|
|
|
|
connect(runner, &AxivionQueryRunner::resultRetrieved, this, [this](const QByteArray &result){
|
|
|
|
|
m_runningQuery = false;
|
|
|
|
|
m_axivionOutputPane.updateAndShowRule(ResultParser::parseRuleInfo(result));
|
|
|
|
|
});
|
|
|
|
|
connect(runner, &AxivionQueryRunner::finished, [runner]{ runner->deleteLater(); });
|
|
|
|
|
runner->start();
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-16 15:12:39 +01:00
|
|
|
void AxivionPluginPrivate::handleOpenedDocs(ProjectExplorer::Project *project)
|
|
|
|
|
{
|
2023-03-01 17:54:39 +01:00
|
|
|
if (project && ProjectExplorer::ProjectManager::startupProject() != project)
|
2022-12-16 15:12:39 +01:00
|
|
|
return;
|
|
|
|
|
const QList<Core::IDocument *> openDocuments = Core::DocumentModel::openedDocuments();
|
|
|
|
|
for (Core::IDocument *doc : openDocuments)
|
|
|
|
|
onDocumentOpened(doc);
|
|
|
|
|
if (project)
|
2023-03-01 17:54:39 +01:00
|
|
|
disconnect(ProjectExplorer::ProjectManager::instance(),
|
|
|
|
|
&ProjectExplorer::ProjectManager::projectFinishedParsing,
|
2022-12-16 15:12:39 +01:00
|
|
|
this, &AxivionPluginPrivate::handleOpenedDocs);
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-16 22:34:56 +01:00
|
|
|
void AxivionPluginPrivate::clearAllMarks()
|
|
|
|
|
{
|
|
|
|
|
const QList<Core::IDocument *> openDocuments = Core::DocumentModel::openedDocuments();
|
|
|
|
|
for (Core::IDocument *doc : openDocuments)
|
|
|
|
|
onDocumentClosed(doc);
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-16 23:11:46 +01:00
|
|
|
void AxivionPluginPrivate::onDocumentOpened(Core::IDocument *doc)
|
|
|
|
|
{
|
2023-07-25 18:48:18 +02:00
|
|
|
if (!m_currentProjectInfo) // we do not have a project info (yet)
|
2022-12-16 23:11:46 +01:00
|
|
|
return;
|
|
|
|
|
|
2023-03-01 17:54:39 +01:00
|
|
|
ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
|
2023-11-24 13:45:07 +01:00
|
|
|
// TODO: Sometimes the isKnownFile() returns false after opening a session.
|
|
|
|
|
// This happens randomly on linux.
|
2022-12-16 23:11:46 +01:00
|
|
|
if (!doc || !project->isKnownFile(doc->filePath()))
|
|
|
|
|
return;
|
|
|
|
|
|
2023-11-24 12:29:17 +01:00
|
|
|
const FilePath relative = doc->filePath().relativeChildPath(project->projectDirectory());
|
2022-12-16 23:11:46 +01:00
|
|
|
// for now only style violations
|
2023-11-24 12:29:17 +01:00
|
|
|
const AxivionQuery query(AxivionQuery::IssuesForFileList, {m_currentProjectInfo->name, "SV",
|
|
|
|
|
relative.path()});
|
2022-12-16 23:11:46 +01:00
|
|
|
AxivionQueryRunner *runner = new AxivionQueryRunner(query, this);
|
|
|
|
|
connect(runner, &AxivionQueryRunner::resultRetrieved, this, [this](const QByteArray &result){
|
|
|
|
|
handleIssuesForFile(ResultParser::parseIssuesList(result));
|
|
|
|
|
});
|
|
|
|
|
connect(runner, &AxivionQueryRunner::finished, [runner]{ runner->deleteLater(); });
|
|
|
|
|
runner->start();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AxivionPluginPrivate::onDocumentClosed(Core::IDocument *doc)
|
|
|
|
|
{
|
|
|
|
|
const auto document = qobject_cast<TextEditor::TextDocument *>(doc);
|
|
|
|
|
if (!document)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const TextEditor::TextMarks marks = document->marks();
|
|
|
|
|
for (auto m : marks) {
|
2023-01-12 12:01:51 +01:00
|
|
|
if (m->category().id == AxivionTextMarkId)
|
2022-12-16 23:11:46 +01:00
|
|
|
delete m;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void AxivionPluginPrivate::handleIssuesForFile(const IssuesList &issues)
|
|
|
|
|
{
|
|
|
|
|
if (issues.issues.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
2023-03-01 17:54:39 +01:00
|
|
|
ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject();
|
2022-12-16 23:11:46 +01:00
|
|
|
if (!project)
|
|
|
|
|
return;
|
|
|
|
|
|
2023-11-24 12:29:17 +01:00
|
|
|
const FilePath filePath = project->projectDirectory()
|
2022-12-16 23:11:46 +01:00
|
|
|
.pathAppended(issues.issues.first().filePath);
|
|
|
|
|
|
2023-11-24 12:29:17 +01:00
|
|
|
const Id axivionId(AxivionTextMarkId);
|
2022-12-16 23:11:46 +01:00
|
|
|
for (const ShortIssue &issue : std::as_const(issues.issues)) {
|
|
|
|
|
// FIXME the line location can be wrong (even the whole issue could be wrong)
|
|
|
|
|
// depending on whether this line has been changed since the last axivion run and the
|
|
|
|
|
// current state of the file - some magic has to happen here
|
2023-01-13 13:49:40 +01:00
|
|
|
new AxivionTextMark(filePath, issue);
|
2022-12-16 23:11:46 +01:00
|
|
|
}
|
2022-12-14 12:11:03 +01:00
|
|
|
}
|
|
|
|
|
|
2024-01-12 08:38:31 +01:00
|
|
|
class AxivionPlugin final : public ExtensionSystem::IPlugin
|
|
|
|
|
{
|
|
|
|
|
Q_OBJECT
|
|
|
|
|
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Axivion.json")
|
|
|
|
|
|
|
|
|
|
~AxivionPlugin() final
|
|
|
|
|
{
|
|
|
|
|
AxivionProjectSettings::destroyProjectSettings();
|
|
|
|
|
delete dd;
|
|
|
|
|
dd = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void initialize() final
|
|
|
|
|
{
|
|
|
|
|
dd = new AxivionPluginPrivate;
|
|
|
|
|
|
|
|
|
|
AxivionProjectSettings::setupProjectPanel();
|
|
|
|
|
|
|
|
|
|
connect(ProjectExplorer::ProjectManager::instance(),
|
|
|
|
|
&ProjectExplorer::ProjectManager::startupProjectChanged,
|
|
|
|
|
dd, &AxivionPluginPrivate::onStartupProjectChanged);
|
|
|
|
|
connect(Core::EditorManager::instance(), &Core::EditorManager::documentOpened,
|
|
|
|
|
dd, &AxivionPluginPrivate::onDocumentOpened);
|
|
|
|
|
connect(Core::EditorManager::instance(), &Core::EditorManager::documentClosed,
|
|
|
|
|
dd, &AxivionPluginPrivate::onDocumentClosed);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-11-28 09:48:11 +01:00
|
|
|
} // Axivion::Internal
|
2024-01-12 08:38:31 +01:00
|
|
|
|
|
|
|
|
#include "axivionplugin.moc"
|