From 67cf906bedfa4446c25afbd204dc6accb935c0ff Mon Sep 17 00:00:00 2001 From: Niels Weber Date: Mon, 12 Sep 2022 08:52:23 +0000 Subject: [PATCH 01/38] Initial empty repository From e3e8edada42007af4b783641f4ff5551f06ebd2e Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 13 Sep 2022 13:42:26 +0200 Subject: [PATCH 02/38] Initial commit Change-Id: I90b3bb6f443fffd69f50428b0059f1a1773c4038 Reviewed-by: hjk --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000000..df44f43aeb3 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ + +# QtCreator/Axivion Integration Plug-in + +This plug-in integrates Axivion Tools handling into Qt Creator. + +This plug-in is only available as part of the commercial Qt offering. + From 433a7c4c7e15634a53e2701b5aa57234b0b7d5ff Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 28 Nov 2022 09:48:11 +0100 Subject: [PATCH 03/38] Initial plugin skeleton Change-Id: Ibb2c950d07280479ec3e00b7b9abef872d6ed131 Reviewed-by: hjk --- plugins/axivion/Axivion.json.in | 17 ++++ plugins/axivion/CMakeLists.txt | 21 +++++ plugins/axivion/axivion.qbs | 25 ++++++ plugins/axivion/axivion.qrc | 6 ++ plugins/axivion/axivionoutputpane.cpp | 107 ++++++++++++++++++++++++ plugins/axivion/axivionoutputpane.h | 55 ++++++++++++ plugins/axivion/axivionplugin.cpp | 64 ++++++++++++++ plugins/axivion/axivionplugin.h | 42 ++++++++++ plugins/axivion/axivionsettings.cpp | 41 +++++++++ plugins/axivion/axivionsettings.h | 35 ++++++++ plugins/axivion/axivionsettingspage.cpp | 69 +++++++++++++++ plugins/axivion/axivionsettingspage.h | 40 +++++++++ plugins/axivion/axiviontr.h | 30 +++++++ plugins/axivion/images/axivion.png | Bin 0 -> 293 bytes plugins/axivion/images/axivion@2x.png | Bin 0 -> 545 bytes 15 files changed, 552 insertions(+) create mode 100644 plugins/axivion/Axivion.json.in create mode 100644 plugins/axivion/CMakeLists.txt create mode 100644 plugins/axivion/axivion.qbs create mode 100644 plugins/axivion/axivion.qrc create mode 100644 plugins/axivion/axivionoutputpane.cpp create mode 100644 plugins/axivion/axivionoutputpane.h create mode 100644 plugins/axivion/axivionplugin.cpp create mode 100644 plugins/axivion/axivionplugin.h create mode 100644 plugins/axivion/axivionsettings.cpp create mode 100644 plugins/axivion/axivionsettings.h create mode 100644 plugins/axivion/axivionsettingspage.cpp create mode 100644 plugins/axivion/axivionsettingspage.h create mode 100644 plugins/axivion/axiviontr.h create mode 100644 plugins/axivion/images/axivion.png create mode 100644 plugins/axivion/images/axivion@2x.png diff --git a/plugins/axivion/Axivion.json.in b/plugins/axivion/Axivion.json.in new file mode 100644 index 00000000000..7f28cffd1d5 --- /dev/null +++ b/plugins/axivion/Axivion.json.in @@ -0,0 +1,17 @@ +{ + \"Name\" : \"Axivion\", + \"Version\" : \"$$QTCREATOR_VERSION\", + \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\", + \"Revision\" : \"$$QTC_PLUGIN_REVISION\", + \"Experimental\" : true, + \"Vendor\" : \"The Qt Company Ltd\", + \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\", + \"License\" : [ \"Commercial Usage\", + \"\", + \"Licensees holding valid Qt Enterprise licenses may use this plugin in accordance with the Qt Enterprise License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and The Qt Company.\" + ], + \"Category\" : \"Code Analyzer\", + \"Description\" : \"Integration of the axivion dashboard.\", + \"Url\" : \"http://www.qt-project.org\", + $$dependencyList +} diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt new file mode 100644 index 00000000000..3f1633251f5 --- /dev/null +++ b/plugins/axivion/CMakeLists.txt @@ -0,0 +1,21 @@ +find_package(QtCreator COMPONENTS Core REQUIRED) +find_package(Qt5 COMPONENTS Network Widgets REQUIRED) + +find_package(QtCreatorLicenseChecker QUIET) +if (TARGET QtCreator::LicenseChecker) + set(LICENSECHECKER_DEPENDS QtCreator::LicenseChecker) +endif() + +add_qtc_plugin(Axivion + PLUGIN_DEPENDS + QtCreator::Core QtCreator::ProjectExplorer + ${LICENSECHECKER_DEPENDS} + DEPENDS Qt5::Network Qt5::Widgets QtCreator::ExtensionSystem QtCreator::Utils + SOURCES + axivion.qrc + axivionoutputpane.cpp axivionoutputpane.h + axivionplugin.cpp axivionplugin.h + axivionsettings.cpp axivionsettings.h + axivionsettingspage.cpp axivionsettingspage.h + axiviontr.h +) diff --git a/plugins/axivion/axivion.qbs b/plugins/axivion/axivion.qbs new file mode 100644 index 00000000000..d73031f89b0 --- /dev/null +++ b/plugins/axivion/axivion.qbs @@ -0,0 +1,25 @@ +import qbs + +QtcCommercialPlugin { + name: "Axivion" + + Depends { name: "Core" } + Depends { name: "ProjectExplorer" } + Depends { name: "ExtensionSystem" } + Depends { name: "Utils" } + Depends { name: "Qt.widgets" } + Depends { name: "Qt.network" } + + files: [ + "axivion.qrc", + "axivionoutputpane.cpp", + "axivionoutputpane.h", + "axivionplugin.cpp", + "axivionplugin.h", + "axivionsettings.cpp", + "axivionsettings.h", + "axivionsettingspage.cpp", + "axivionsettingspage.h", + "axiviontr.h", + ] +} diff --git a/plugins/axivion/axivion.qrc b/plugins/axivion/axivion.qrc new file mode 100644 index 00000000000..13d0b616c91 --- /dev/null +++ b/plugins/axivion/axivion.qrc @@ -0,0 +1,6 @@ + + + images/axivion.png + images/axivion@2x.png + + diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp new file mode 100644 index 00000000000..4bc51cefbe4 --- /dev/null +++ b/plugins/axivion/axivionoutputpane.cpp @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "axivionoutputpane.h" + +#include "axiviontr.h" + +#include + +#include + +namespace Axivion::Internal { + +AxivionOutputPane::AxivionOutputPane(QObject *parent) + : Core::IOutputPane(parent) +{ + m_outputWidget = new QStackedWidget; +} + +AxivionOutputPane::~AxivionOutputPane() +{ + if (!m_outputWidget->parent()) + delete m_outputWidget; +} + +QWidget *AxivionOutputPane::outputWidget(QWidget *parent) +{ + if (m_outputWidget) + m_outputWidget->setParent(parent); + else + QTC_CHECK(false); + return m_outputWidget; +} + +QList AxivionOutputPane::toolBarWidgets() const +{ + QList buttons; + return buttons; +} + +QString AxivionOutputPane::displayName() const +{ + return Tr::tr("Axivion"); +} + +int AxivionOutputPane::priorityInStatusBar() const +{ + return -1; +} + +void AxivionOutputPane::clearContents() +{ +} + +void AxivionOutputPane::setFocus() +{ +} + +bool AxivionOutputPane::hasFocus() const +{ + return false; +} + +bool AxivionOutputPane::canFocus() const +{ + return true; +} + +bool AxivionOutputPane::canNavigate() const +{ + return true; +} + +bool AxivionOutputPane::canNext() const +{ + return false; +} + +bool AxivionOutputPane::canPrevious() const +{ + return false; +} + +void AxivionOutputPane::goToNext() +{ +} + +void AxivionOutputPane::goToPrev() +{ +} + +} // namespace Axivion::Internal diff --git a/plugins/axivion/axivionoutputpane.h b/plugins/axivion/axivionoutputpane.h new file mode 100644 index 00000000000..352a885e205 --- /dev/null +++ b/plugins/axivion/axivionoutputpane.h @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#pragma once + +#include + +QT_BEGIN_NAMESPACE +class QStackedWidget; +QT_END_NAMESPACE + +namespace Axivion::Internal { + +class AxivionOutputPane : public Core::IOutputPane +{ + Q_OBJECT +public: + explicit AxivionOutputPane(QObject *parent = nullptr); + ~AxivionOutputPane(); + + // IOutputPane interface + QWidget *outputWidget(QWidget *parent) override; + QList toolBarWidgets() const override; + QString displayName() const override; + int priorityInStatusBar() const override; + void clearContents() override; + void setFocus() override; + bool hasFocus() const override; + bool canFocus() const override; + bool canNavigate() const override; + bool canNext() const override; + bool canPrevious() const override; + void goToNext() override; + void goToPrev() override; + +private: + QStackedWidget *m_outputWidget = nullptr; +}; + +} // namespace Axivion::Internal diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp new file mode 100644 index 00000000000..d11e39ef303 --- /dev/null +++ b/plugins/axivion/axivionplugin.cpp @@ -0,0 +1,64 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "axivionplugin.h" + +#include "axivionoutputpane.h" +#include "axivionsettings.h" +#include "axivionsettingspage.h" + + +#ifdef LICENSECHECKER +# include +#endif + +#include + +namespace Axivion::Internal { + +class AxivionPluginPrivate +{ +public: + AxivionSettings axivionSettings; + AxivionSettingsPage axivionSettingsPage{&axivionSettings}; + AxivionOutputPane axivionOutputPane; +}; + +AxivionPlugin::~AxivionPlugin() +{ + delete d; +} + +bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessage) +{ + Q_UNUSED(arguments) + Q_UNUSED(errorMessage) + +#ifdef LICENSECHECKER + LicenseChecker::LicenseCheckerPlugin *licenseChecker + = ExtensionSystem::PluginManager::getObject(); + + if (!licenseChecker || !licenseChecker->hasValidLicense() || !licenseChecker->enterpriseFeatures()) + return true; +#endif // LICENSECHECKER + + d = new AxivionPluginPrivate; + return true; +} + +} // Axivion::Internal diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h new file mode 100644 index 00000000000..6fec8944695 --- /dev/null +++ b/plugins/axivion/axivionplugin.h @@ -0,0 +1,42 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#pragma once + +#include + +namespace Axivion::Internal { + +class AxivionPlugin final : public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Axivion.json") + +public: + AxivionPlugin() = default; + ~AxivionPlugin() final; + +private: + bool initialize(const QStringList &arguments, QString *errorMessage) final; + void extensionsInitialized() final {} + + class AxivionPluginPrivate *d = nullptr; +}; + +} // namespace Axivion::Internal + diff --git a/plugins/axivion/axivionsettings.cpp b/plugins/axivion/axivionsettings.cpp new file mode 100644 index 00000000000..56fe191561d --- /dev/null +++ b/plugins/axivion/axivionsettings.cpp @@ -0,0 +1,41 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "axivionsettings.h" + +#include + +namespace Axivion::Internal { + +AxivionSettings::AxivionSettings() +{ +} + +void AxivionSettings::toSettings(QSettings *s) const +{ + s->beginGroup("Axivion"); + s->endGroup(); +} + +void AxivionSettings::fromSettings(QSettings *s) +{ + s->beginGroup("Axivion"); + s->endGroup(); +} + +} // namespace Axivion::Internal diff --git a/plugins/axivion/axivionsettings.h b/plugins/axivion/axivionsettings.h new file mode 100644 index 00000000000..e4a63a66d3c --- /dev/null +++ b/plugins/axivion/axivionsettings.h @@ -0,0 +1,35 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#pragma once + +QT_BEGIN_NAMESPACE +class QSettings; +QT_END_NAMESPACE + +namespace Axivion::Internal { + +class AxivionSettings +{ +public: + AxivionSettings(); + void toSettings(QSettings *s) const; + void fromSettings(QSettings *s); +}; + +} // namespace Axivion::Internal diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp new file mode 100644 index 00000000000..5f2cec3d13f --- /dev/null +++ b/plugins/axivion/axivionsettingspage.cpp @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#include "axivionsettingspage.h" + +#include "axivionsettings.h" +#include "axiviontr.h" + +#include +#include + +#include +#include + +namespace Axivion::Internal { + +class AxivionSettingsWidget : public Core::IOptionsPageWidget +{ +public: + explicit AxivionSettingsWidget(AxivionSettings *settings); + + void apply() override; +private: + AxivionSettings *m_settings; +}; + +AxivionSettingsWidget::AxivionSettingsWidget(AxivionSettings *settings) + : m_settings(settings) +{ + using namespace Utils::Layouting; + + auto label = new QLabel(Tr::tr("...Placeholder...")); + Row { + Column { label, st } + }.attachTo(this); +} + +void AxivionSettingsWidget::apply() +{ + // set m_settings from widget + m_settings->toSettings(Core::ICore::settings()); +} + +AxivionSettingsPage::AxivionSettingsPage(AxivionSettings *settings) +{ + setId("Axivion.Settings.General"); + setDisplayName(Tr::tr("General")); + setCategory("XY.Axivion"); + setDisplayCategory(Tr::tr("Axivion")); + setCategoryIconPath(":/axivion/images/axivion.png"); + setWidgetCreator([this] { return new AxivionSettingsWidget(m_settings); }); +} + +} // Axivion::Internal diff --git a/plugins/axivion/axivionsettingspage.h b/plugins/axivion/axivionsettingspage.h new file mode 100644 index 00000000000..64c0c01f9eb --- /dev/null +++ b/plugins/axivion/axivionsettingspage.h @@ -0,0 +1,40 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#pragma once + +#include + +#include + +namespace Axivion::Internal { + +class AxivionSettings; +class AxivionSettingsWidget; + +class AxivionSettingsPage : public Core::IOptionsPage +{ + Q_OBJECT +public: + explicit AxivionSettingsPage(AxivionSettings *settings); + +private: + AxivionSettings *m_settings; +}; + +} // namespace Axivion::Internal diff --git a/plugins/axivion/axiviontr.h b/plugins/axivion/axiviontr.h new file mode 100644 index 00000000000..062dd6b9598 --- /dev/null +++ b/plugins/axivion/axiviontr.h @@ -0,0 +1,30 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd +** All rights reserved. +** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us +** +** This file is part of the Qt Enterprise Axivion Add-on. +** +** Licensees holding valid Qt Enterprise licenses may use this file in +** accordance with the Qt Enterprise License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. +** +** If you have questions regarding the use of this file, please use +** contact form at http://www.qt.io/contact-us +** +****************************************************************************/ + +#pragma once + +#include + +namespace Axivion { + +struct Tr +{ + Q_DECLARE_TR_FUNCTIONS(Axivion) +}; + +} // namespace Axivion diff --git a/plugins/axivion/images/axivion.png b/plugins/axivion/images/axivion.png new file mode 100644 index 0000000000000000000000000000000000000000..647f5972ce24886687e9e9f0bbbdc345e2c282d1 GIT binary patch literal 293 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4h9AWhNCh`Dhvz^Z#-QbLo_BHy|~wlIZ))t z$KOrqyl>2!T60(Jv}=mhNxI+_kW=FNXqmyf&K&}OG)%NIl*KaNnD7e(2*1DoNX#rM z{nSs<;s+N0I%gaE=x>Yqy`Eunpw9k$=DzK_X5Mt-+&p)xb;E?$0>_iX*1t1fW7a18 zQ?X@R$ioDaM*q!r7pBU$DX;t`>;I-fWA-J>2QzZ?)u+vT%CKF4zZCi6M114n+qV{EsZDeCf90(4M8D8xNm^Q(WxVcJ w2B(FLe8--?yLY+pBagiK$8R5u{=5I3D}Pu0TU>UIl^w|cp00i_>zopr0Dy#k1ONa4 literal 0 HcmV?d00001 diff --git a/plugins/axivion/images/axivion@2x.png b/plugins/axivion/images/axivion@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..15bac95f52ccb37024001078617d7ccb8d117928 GIT binary patch literal 545 zcmeAS@N?(olHy`uVBq!ia0y~yU@!n-4h9AWhN8@6(F_cXFFaiwLp(a)PKnfK4istl z&Aznk`9@%eve?RS+ic4UHhTFP5rgsj$ zI#uh|z^DAc{?Q(}BUd&jO)ZIDma6|SRk`PwNsaLrfydKb`THAdU%UBhus9fL@lSl; z^O>`_!ucTYriZtg7q@?0)4|ecRk(P?i8g^XH{PcHQCiU?cQk(6ek+YO_h-5fE7w>Z zXSw_-*3XsUmVd>WW)&F`t>y_V3lh8MGkfmPzfdO@@%YGYW$wEiS9#ASrKnCZIi$Vn z#&WW^$d8@J8qL;oXWY{K6-jQw}XT+I&%6k}vzc zyv5^5Et=<=4X*8U@LATnH~XT;E?pnvy0*X5d4eSzPJ{;Ee{gonw$iqb!hcS(S Date: Wed, 30 Nov 2022 12:05:53 +0100 Subject: [PATCH 04/38] Tweak cmake files Preparation for integration into super repository. Change-Id: I9e932466a63d4ea4943dae147a0a928918fb6c96 Reviewed-by: hjk --- CMakeLists.txt | 11 +++++++++++ plugins/axivion/CMakeLists.txt | 1 + 2 files changed, 12 insertions(+) create mode 100644 CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000000..7a3dd57ae3c --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.16) + +project(Axivion) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) +set(CMAKE_AUTOUIC ON) +set(CMAKE_CXX_STANDARD 17) + +add_subdirectory(plugins/axivion) + diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index 3f1633251f5..c5dd9dcf6f3 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -7,6 +7,7 @@ if (TARGET QtCreator::LicenseChecker) endif() add_qtc_plugin(Axivion + BUILD_DEFAULT OFF PLUGIN_DEPENDS QtCreator::Core QtCreator::ProjectExplorer ${LICENSECHECKER_DEPENDS} From 37a4aceaded4702a9c14f44edb6a5042971d4be5 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 7 Dec 2022 12:04:05 +0100 Subject: [PATCH 05/38] Build plugin with cmake also by default Partially reverts bba09b7152. Change-Id: I781569340a97160eeaffb544de33123cecc041d1 Reviewed-by: hjk --- plugins/axivion/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index c5dd9dcf6f3..3f1633251f5 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -7,7 +7,6 @@ if (TARGET QtCreator::LicenseChecker) endif() add_qtc_plugin(Axivion - BUILD_DEFAULT OFF PLUGIN_DEPENDS QtCreator::Core QtCreator::ProjectExplorer ${LICENSECHECKER_DEPENDS} From 0cb28bb969598e20a924972b1282eead168eb737 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 8 Dec 2022 08:25:49 +0100 Subject: [PATCH 06/38] Fix compile on Linux Change-Id: I1971951d64cc971c8b4cf9a480e3f705eee0d33f Reviewed-by: David Schulz --- plugins/axivion/axivionsettings.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/plugins/axivion/axivionsettings.h b/plugins/axivion/axivionsettings.h index e4a63a66d3c..bfd4315de4f 100644 --- a/plugins/axivion/axivionsettings.h +++ b/plugins/axivion/axivionsettings.h @@ -18,6 +18,8 @@ #pragma once +#include + QT_BEGIN_NAMESPACE class QSettings; QT_END_NAMESPACE From 5a468556d7a3c9b03890c97b63d44cd05564d170 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 8 Dec 2022 08:32:22 +0100 Subject: [PATCH 07/38] Fix passing settings Change-Id: I6473138391f6e7c44f2815049649300df828add7 Reviewed-by: David Schulz --- plugins/axivion/axivionsettingspage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index 5f2cec3d13f..aa9269392a4 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -57,6 +57,7 @@ void AxivionSettingsWidget::apply() } AxivionSettingsPage::AxivionSettingsPage(AxivionSettings *settings) + : m_settings(settings) { setId("Axivion.Settings.General"); setDisplayName(Tr::tr("General")); From ffc9eff670b4dc30c251a6280bc861f471f3bc3f Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 12 Dec 2022 16:45:31 +0100 Subject: [PATCH 08/38] Provide minimal settings to work with Change-Id: I73d09612ac2bb66c4f359ecfffc01650d56359ee Reviewed-by: David Schulz Reviewed-by: hjk --- plugins/axivion/axivionoutputpane.cpp | 21 +-- plugins/axivion/axivionoutputpane.h | 21 +-- plugins/axivion/axivionplugin.cpp | 24 +--- plugins/axivion/axivionplugin.h | 21 +-- plugins/axivion/axivionsettings.cpp | 126 ++++++++++++++--- plugins/axivion/axivionsettings.h | 50 ++++--- plugins/axivion/axivionsettingspage.cpp | 181 +++++++++++++++++++++--- plugins/axivion/axivionsettingspage.h | 49 ++++--- plugins/axivion/axiviontr.h | 21 +-- 9 files changed, 346 insertions(+), 168 deletions(-) diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp index 4bc51cefbe4..d7896e02d0f 100644 --- a/plugins/axivion/axivionoutputpane.cpp +++ b/plugins/axivion/axivionoutputpane.cpp @@ -1,20 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #include "axivionoutputpane.h" @@ -104,4 +89,4 @@ void AxivionOutputPane::goToPrev() { } -} // namespace Axivion::Internal +} // Axivion::Internal diff --git a/plugins/axivion/axivionoutputpane.h b/plugins/axivion/axivionoutputpane.h index 352a885e205..63ec48097ec 100644 --- a/plugins/axivion/axivionoutputpane.h +++ b/plugins/axivion/axivionoutputpane.h @@ -1,20 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #pragma once @@ -52,4 +37,4 @@ private: QStackedWidget *m_outputWidget = nullptr; }; -} // namespace Axivion::Internal +} // Axivion::Internal diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index d11e39ef303..639ff50b465 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -1,20 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2015 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #include "axivionplugin.h" @@ -22,13 +7,13 @@ #include "axivionsettings.h" #include "axivionsettingspage.h" +#include +#include #ifdef LICENSECHECKER # include #endif -#include - namespace Axivion::Internal { class AxivionPluginPrivate @@ -58,6 +43,7 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa #endif // LICENSECHECKER d = new AxivionPluginPrivate; + d->axivionSettings.fromSettings(Core::ICore::settings()); return true; } diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h index 6fec8944695..f22f2823e19 100644 --- a/plugins/axivion/axivionplugin.h +++ b/plugins/axivion/axivionplugin.h @@ -1,20 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #pragma once @@ -38,5 +23,5 @@ private: class AxivionPluginPrivate *d = nullptr; }; -} // namespace Axivion::Internal +} // Axivion::Internal diff --git a/plugins/axivion/axivionsettings.cpp b/plugins/axivion/axivionsettings.cpp index 56fe191561d..2f827f9e750 100644 --- a/plugins/axivion/axivionsettings.cpp +++ b/plugins/axivion/axivionsettings.cpp @@ -1,41 +1,131 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #include "axivionsettings.h" +#include + +#include +#include #include +#include namespace Axivion::Internal { +const char curlKeyC[] = "Curl"; + +AxivionServer::AxivionServer(const Utils::Id &id, const QString &dashboard, + const QString &description, const QString &token) + : id(id) + , dashboard(dashboard) + , description(description) + , token(token) +{ +} + +bool AxivionServer::operator==(const AxivionServer &other) const +{ + return id == other.id && dashboard == other.dashboard + && description == other.description && token == other.token; +} + +bool AxivionServer::operator!=(const AxivionServer &other) const +{ + return !(*this == other); +} + +QJsonObject AxivionServer::toJson() const +{ + QJsonObject result; + result.insert("id", id.toString()); + result.insert("dashboard", dashboard); + result.insert("description", description); + result.insert("token", token); + return result; +} + +AxivionServer AxivionServer::fromJson(const QJsonObject &json) +{ + const AxivionServer invalidServer; + const QJsonValue id = json.value("id"); + if (id == QJsonValue::Undefined) + return invalidServer; + const QJsonValue dashboard = json.value("dashboard"); + if (dashboard == QJsonValue::Undefined) + return invalidServer; + const QJsonValue description = json.value("description"); + if (description == QJsonValue::Undefined) + return invalidServer; + const QJsonValue token = json.value("token"); + if (token == QJsonValue::Undefined) + return invalidServer; + return { Utils::Id::fromString(id.toString()), dashboard.toString(), + description.toString(), token.toString() }; +} + +QStringList AxivionServer::curlArguments() const +{ + QStringList args { "-sS" }; // silent, but show error + if (dashboard.startsWith("https://") && !validateCert) + args << "-k"; + return args; +} + AxivionSettings::AxivionSettings() { } +static Utils::FilePath tokensFilePath(const QSettings *s) +{ + return Utils::FilePath::fromString(s->fileName()).parentDir() + .pathAppended("qtcreator/axivion.json"); +} + +static void writeTokenFile(const Utils::FilePath &filePath, const AxivionServer &server) +{ + QJsonDocument doc; + doc.setObject(server.toJson()); + // FIXME error handling? + filePath.writeFileContents(doc.toJson()); + filePath.setPermissions(QFile::ReadUser | QFile::WriteUser); +} + +static AxivionServer readTokenFile(const Utils::FilePath &filePath) +{ + if (!filePath.exists()) + return {}; + Utils::expected_str contents = filePath.fileContents(); + if (!contents) + return {}; + const QJsonDocument doc = QJsonDocument::fromJson(*contents); + if (!doc.isObject()) + return {}; + return AxivionServer::fromJson(doc.object()); +} + void AxivionSettings::toSettings(QSettings *s) const { + writeTokenFile(tokensFilePath(s), server); + s->beginGroup("Axivion"); + s->setValue(curlKeyC, curl.toVariant()); s->endGroup(); } void AxivionSettings::fromSettings(QSettings *s) { s->beginGroup("Axivion"); + curl = Utils::FilePath::fromVariant(curlKeyC); s->endGroup(); + + server = readTokenFile(tokensFilePath(s)); + + if (curl.isEmpty() || !curl.exists()) { + const QString curlPath = QStandardPaths::findExecutable( + Utils::HostOsInfo::withExecutableSuffix("curl")); + if (!curlPath.isEmpty()) + curl = Utils::FilePath::fromString(curlPath); + } } -} // namespace Axivion::Internal +} // Axivion::Internal diff --git a/plugins/axivion/axivionsettings.h b/plugins/axivion/axivionsettings.h index bfd4315de4f..20763bee9ee 100644 --- a/plugins/axivion/axivionsettings.h +++ b/plugins/axivion/axivionsettings.h @@ -1,37 +1,51 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #pragma once +#include +#include + #include QT_BEGIN_NAMESPACE +class QJsonObject; class QSettings; QT_END_NAMESPACE namespace Axivion::Internal { +class AxivionServer +{ +public: + AxivionServer() = default; + AxivionServer(const Utils::Id &id, const QString &dashboardUrl, + const QString &description, const QString &token); + + bool operator==(const AxivionServer &other) const; + bool operator!=(const AxivionServer &other) const; + + QJsonObject toJson() const; + static AxivionServer fromJson(const QJsonObject &json); + QStringList curlArguments() const; + + Utils::Id id; + QString dashboard; + QString description; + QString token; + + bool validateCert = true; +}; + class AxivionSettings { public: AxivionSettings(); void toSettings(QSettings *s) const; void fromSettings(QSettings *s); + + AxivionServer server; // shall we have more than one? + Utils::FilePath curl; }; -} // namespace Axivion::Internal +} // Axivion::Internal diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index aa9269392a4..ffe5122442e 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -1,20 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #include "axivionsettingspage.h" @@ -23,12 +8,115 @@ #include #include +#include +#include +#include #include -#include +#include +#include +#include +#include + +using namespace Utils; namespace Axivion::Internal { +// may allow some invalid, but does some minimal check for legality +static bool hostValid(const QString &host) +{ + static const QRegularExpression ip(R"(^(\d+).(\d+).(\d+).(\d+)$)"); + static const QRegularExpression dn(R"(^([a-zA-Z0-9][a-zA-Z0-9-]+\.)+[a-zA-Z0-9][a-zA-Z0-9-]+$)"); + const QRegularExpressionMatch match = ip.match(host); + if (match.hasMatch()) { + for (int i = 1; i < 5; ++i) { + int val = match.captured(i).toInt(); + if (val < 0 || val > 255) + return false; + } + return true; + } + return (host == "localhost") || dn.match(host).hasMatch(); +} + +static bool isUrlValid(const QString &in) +{ + const QUrl url(in); + return hostValid(url.host()) && url.scheme() == "https" || url.scheme() == "http"; +} + +DashboardWidget::DashboardWidget(Mode mode, QWidget *parent) + : QWidget(parent) + , m_mode(mode) +{ + auto labelStyle = mode == Display ? StringAspect::LabelDisplay : StringAspect::LineEditDisplay; + m_dashboardUrl.setLabelText(Tr::tr("Dashboard URL:")); + m_dashboardUrl.setDisplayStyle(labelStyle); + m_dashboardUrl.setValidationFunction([](FancyLineEdit *edit, QString *){ + return isUrlValid(edit->text()); + }); + m_description.setLabelText(Tr::tr("Description:")); + m_description.setDisplayStyle(labelStyle); + m_description.setPlaceHolderText(Tr::tr("Non-empty description")); + + m_token.setLabelText(Tr::tr("Access token:")); + m_token.setDisplayStyle(labelStyle); + m_token.setPlaceHolderText(Tr::tr("IDE Access Token")); + m_token.setVisible(mode == Edit); + + using namespace Layouting; + + Row { + Form { + m_dashboardUrl, + m_description, + m_token + } + }.attachTo(this, mode == Edit ? WithMargins : WithoutMargins); + + auto checkValidity = [this](){ + bool old = m_valid; + m_valid = isValid(); + if (old != m_valid) + emit validChanged(m_valid); + }; + if (mode == Edit) { + connect(&m_dashboardUrl, &StringAspect::valueChanged, + this, checkValidity); + connect(&m_description, &StringAspect::valueChanged, + this, checkValidity); + connect(&m_token, &StringAspect::valueChanged, + this, checkValidity); + } +} + +AxivionServer DashboardWidget::dashboardServer() const +{ + AxivionServer result; + if (m_id.isValid()) + result.id = m_id; + else + result.id = m_mode == Edit ? Utils::Id::fromName(QUuid::createUuid().toByteArray()) : m_id; + result.dashboard = m_dashboardUrl.value(); + result.description = m_description.value(); + result.token = m_token.value(); + return result; +} + +void DashboardWidget::setDashboardServer(const AxivionServer &server) +{ + m_id = server.id; + m_dashboardUrl.setValue(server.dashboard); + m_description.setValue(server.description); + m_token.setValue(server.token); +} + +bool DashboardWidget::isValid() const +{ + return !m_token.value().isEmpty() && !m_description.value().isEmpty() + && isUrlValid(m_dashboardUrl.value()); +} + class AxivionSettingsWidget : public Core::IOptionsPageWidget { public: @@ -36,26 +124,73 @@ public: void apply() override; private: + void showEditServerDialog(); + AxivionSettings *m_settings; + + Utils::StringAspect m_curlPC; + DashboardWidget *m_dashboardDisplay = nullptr; + QPushButton *m_edit = nullptr; }; AxivionSettingsWidget::AxivionSettingsWidget(AxivionSettings *settings) : m_settings(settings) { - using namespace Utils::Layouting; + using namespace Layouting; - auto label = new QLabel(Tr::tr("...Placeholder...")); - Row { - Column { label, st } + m_dashboardDisplay = new DashboardWidget(DashboardWidget::Display, this); + m_dashboardDisplay->setDashboardServer(m_settings->server); + m_edit = new QPushButton(Tr::tr("Edit..."), this); + m_curlPC.setLabelText(Tr::tr("curl:")); + m_curlPC.setDisplayStyle(StringAspect::PathChooserDisplay); + m_curlPC.setExpectedKind(PathChooser::ExistingCommand); + m_curlPC.setFilePath(m_settings->curl); + Grid { + Form { + m_dashboardDisplay, br, + m_curlPC, br, + }, Column { m_edit, st } }.attachTo(this); + + connect(m_edit, &QPushButton::clicked, this, &AxivionSettingsWidget::showEditServerDialog); } void AxivionSettingsWidget::apply() { - // set m_settings from widget + m_settings->server = m_dashboardDisplay->dashboardServer(); + m_settings->curl = m_curlPC.filePath(); m_settings->toSettings(Core::ICore::settings()); } +void AxivionSettingsWidget::showEditServerDialog() +{ + const AxivionServer old = m_dashboardDisplay->dashboardServer(); + QDialog d; + d.setWindowTitle(Tr::tr("Edit Dashboard Configuration")); + QVBoxLayout *layout = new QVBoxLayout; + DashboardWidget *dashboardWidget = new DashboardWidget(DashboardWidget::Edit, this); + dashboardWidget->setDashboardServer(old); + layout->addWidget(dashboardWidget); + auto buttons = new QDialogButtonBox(QDialogButtonBox::Cancel, this); + auto modify = buttons->addButton(Tr::tr("Modify"), QDialogButtonBox::AcceptRole); + modify->setEnabled(m_dashboardDisplay->isValid()); + connect(buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, &d, &QDialog::reject); + connect(modify, &QPushButton::clicked, &d, &QDialog::accept); + connect(dashboardWidget, &DashboardWidget::validChanged, + modify, &QPushButton::setEnabled); + layout->addWidget(buttons); + d.setLayout(layout); + d.resize(500, 200); + + if (d.exec() != QDialog::Accepted) + return; + if (dashboardWidget->isValid()) { + const AxivionServer server = dashboardWidget->dashboardServer(); + if (server != old) + m_dashboardDisplay->setDashboardServer(server); + } +} + AxivionSettingsPage::AxivionSettingsPage(AxivionSettings *settings) : m_settings(settings) { diff --git a/plugins/axivion/axivionsettingspage.h b/plugins/axivion/axivionsettingspage.h index 64c0c01f9eb..02cfb81ffa9 100644 --- a/plugins/axivion/axivionsettingspage.h +++ b/plugins/axivion/axivionsettingspage.h @@ -1,32 +1,45 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #pragma once #include +#include +#include #include +#include namespace Axivion::Internal { +class AxivionServer; class AxivionSettings; class AxivionSettingsWidget; +class DashboardWidget : public QWidget +{ + Q_OBJECT +public: + enum Mode { Display, Edit }; + explicit DashboardWidget(Mode m = Display, QWidget *parent = nullptr); + + AxivionServer dashboardServer() const; + void setDashboardServer(const AxivionServer &server); + + bool isValid() const; + +signals: + void validChanged(bool valid); +private: + Mode m_mode = Display; + Utils::Id m_id; + Utils::StringAspect m_dashboardUrl; + Utils::StringAspect m_description; + Utils::StringAspect m_token; + bool m_valid = false; +}; + + class AxivionSettingsPage : public Core::IOptionsPage { Q_OBJECT @@ -37,4 +50,4 @@ private: AxivionSettings *m_settings; }; -} // namespace Axivion::Internal +} // Axivion::Internal diff --git a/plugins/axivion/axiviontr.h b/plugins/axivion/axiviontr.h index 062dd6b9598..5a8398730a1 100644 --- a/plugins/axivion/axiviontr.h +++ b/plugins/axivion/axiviontr.h @@ -1,20 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2022 The Qt Company Ltd -** All rights reserved. -** For any questions to The Qt Company, please use contact form at http://www.qt.io/contact-us -** -** This file is part of the Qt Enterprise Axivion Add-on. -** -** Licensees holding valid Qt Enterprise licenses may use this file in -** accordance with the Qt Enterprise License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. -** -** If you have questions regarding the use of this file, please use -** contact form at http://www.qt.io/contact-us -** -****************************************************************************/ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial #pragma once @@ -27,4 +12,4 @@ struct Tr Q_DECLARE_TR_FUNCTIONS(Axivion) }; -} // namespace Axivion +} // Axivion From 1df3f216a27cdf79a9d05054473500f31209b904 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 13 Dec 2022 11:17:12 +0100 Subject: [PATCH 09/38] Provide project settings Currently incomplete due to missing underlying infrastructure which will be added separately. Change-Id: Ied6d09e9a0834370afca5f7be9c2fbd2da210a2e Reviewed-by: David Schulz --- plugins/axivion/CMakeLists.txt | 1 + plugins/axivion/axivion.qbs | 2 + plugins/axivion/axivionplugin.cpp | 44 +++++++- plugins/axivion/axivionplugin.h | 10 +- plugins/axivion/axivionprojectsettings.cpp | 124 +++++++++++++++++++++ plugins/axivion/axivionprojectsettings.h | 61 ++++++++++ 6 files changed, 237 insertions(+), 5 deletions(-) create mode 100644 plugins/axivion/axivionprojectsettings.cpp create mode 100644 plugins/axivion/axivionprojectsettings.h diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index 3f1633251f5..e5b4045b628 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -15,6 +15,7 @@ add_qtc_plugin(Axivion axivion.qrc axivionoutputpane.cpp axivionoutputpane.h axivionplugin.cpp axivionplugin.h + axivionprojectsettings.h axivionprojectsettings.cpp axivionsettings.cpp axivionsettings.h axivionsettingspage.cpp axivionsettingspage.h axiviontr.h diff --git a/plugins/axivion/axivion.qbs b/plugins/axivion/axivion.qbs index d73031f89b0..3e28ee0903b 100644 --- a/plugins/axivion/axivion.qbs +++ b/plugins/axivion/axivion.qbs @@ -16,6 +16,8 @@ QtcCommercialPlugin { "axivionoutputpane.h", "axivionplugin.cpp", "axivionplugin.h", + "axivionprojectsettings.h", + "axivionprojectsettings.cpp", "axivionsettings.cpp", "axivionsettings.h", "axivionsettingspage.cpp", diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 639ff50b465..7156ad66566 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -4,11 +4,16 @@ #include "axivionplugin.h" #include "axivionoutputpane.h" +#include "axivionprojectsettings.h" #include "axivionsettings.h" #include "axivionsettingspage.h" +#include "axiviontr.h" #include #include +#include +#include +#include #ifdef LICENSECHECKER # include @@ -22,11 +27,19 @@ public: AxivionSettings axivionSettings; AxivionSettingsPage axivionSettingsPage{&axivionSettings}; AxivionOutputPane axivionOutputPane; + QHash projectSettings; }; +static AxivionPluginPrivate *dd = nullptr; + AxivionPlugin::~AxivionPlugin() { - delete d; + if (!dd->projectSettings.isEmpty()) { + qDeleteAll(dd->projectSettings); + dd->projectSettings.clear(); + } + delete dd; + dd = nullptr; } bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessage) @@ -42,9 +55,34 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa return true; #endif // LICENSECHECKER - d = new AxivionPluginPrivate; - d->axivionSettings.fromSettings(Core::ICore::settings()); + dd = new AxivionPluginPrivate; + dd->axivionSettings.fromSettings(Core::ICore::settings()); + + auto panelFactory = new ProjectExplorer::ProjectPanelFactory; + panelFactory->setPriority(250); + panelFactory->setDisplayName(Tr::tr("Axivion")); + panelFactory->setCreateWidgetFunction([](ProjectExplorer::Project *project){ + return new AxivionProjectSettingsWidget(project); + }); + ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); return true; } +AxivionSettings *AxivionPlugin::settings() +{ + QTC_ASSERT(dd, return nullptr); + return &dd->axivionSettings; +} + +AxivionProjectSettings *AxivionPlugin::projectSettings(ProjectExplorer::Project *project) +{ + QTC_ASSERT(project, return nullptr); + QTC_ASSERT(dd, return nullptr); + + auto &settings = dd->projectSettings[project]; + if (!settings) + settings = new AxivionProjectSettings(project); + return settings; +} + } // Axivion::Internal diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h index f22f2823e19..a9d49b37e15 100644 --- a/plugins/axivion/axivionplugin.h +++ b/plugins/axivion/axivionplugin.h @@ -5,8 +5,13 @@ #include +namespace ProjectExplorer { class Project; } + namespace Axivion::Internal { +class AxivionSettings; +class AxivionProjectSettings; + class AxivionPlugin final : public ExtensionSystem::IPlugin { Q_OBJECT @@ -16,11 +21,12 @@ public: AxivionPlugin() = default; ~AxivionPlugin() final; + static AxivionSettings *settings(); + static AxivionProjectSettings *projectSettings(ProjectExplorer::Project *project); + private: bool initialize(const QStringList &arguments, QString *errorMessage) final; void extensionsInitialized() final {} - - class AxivionPluginPrivate *d = nullptr; }; } // Axivion::Internal diff --git a/plugins/axivion/axivionprojectsettings.cpp b/plugins/axivion/axivionprojectsettings.cpp new file mode 100644 index 00000000000..2d1bb3efa95 --- /dev/null +++ b/plugins/axivion/axivionprojectsettings.cpp @@ -0,0 +1,124 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial + +#include "axivionprojectsettings.h" + +#include "axivionplugin.h" +#include "axivionsettings.h" +#include "axiviontr.h" + +#include +#include + +#include +#include +#include + +namespace Axivion::Internal { + +const char PSK_PROJECTNAME[] = "Axivion.ProjectName"; + +AxivionProjectSettings::AxivionProjectSettings(ProjectExplorer::Project *project) + : m_project{project} +{ + load(); + connect(project, &ProjectExplorer::Project::settingsLoaded, + this, &AxivionProjectSettings::load); + connect(project, &ProjectExplorer::Project::aboutToSaveSettings, + this, &AxivionProjectSettings::save); +} + +void AxivionProjectSettings::load() +{ + m_dashboardProjectName = m_project->namedSettings(PSK_PROJECTNAME).toString(); +} + +void AxivionProjectSettings::save() +{ + m_project->setNamedSettings(PSK_PROJECTNAME, m_dashboardProjectName); +} + +AxivionProjectSettingsWidget::AxivionProjectSettingsWidget(ProjectExplorer::Project *project, + QWidget *parent) + : ProjectExplorer::ProjectSettingsWidget{parent} + , m_projectSettings(AxivionPlugin::projectSettings(project)) + , m_globalSettings(AxivionPlugin::settings()) +{ + setUseGlobalSettingsCheckBoxVisible(false); + setUseGlobalSettingsLabelVisible(true); + setGlobalSettingsId("Axivion.Settings.General"); // FIXME move id to constants + // setup ui + auto verticalLayout = new QVBoxLayout(this); + verticalLayout->setContentsMargins(0, 0, 0, 0); + + m_linkedProject = new QLabel(this); + verticalLayout->addWidget(m_linkedProject); + + m_dashboardProjects = new QTreeWidget(this); + m_dashboardProjects->setHeaderHidden(true); + m_dashboardProjects->setRootIsDecorated(false); + verticalLayout->addWidget(new QLabel(Tr::tr("Dashboard projects:"))); + verticalLayout->addWidget(m_dashboardProjects); + + m_infoLabel = new Utils::InfoLabel(this); + m_infoLabel->setVisible(false); + verticalLayout->addWidget(m_infoLabel); + + auto horizontalLayout = new QHBoxLayout; + horizontalLayout->setContentsMargins(0, 0, 0, 0); + m_fetchProjects = new QPushButton(Tr::tr("Fetch Projects")); + horizontalLayout->addWidget(m_fetchProjects); + m_link = new QPushButton(Tr::tr("Link Project")); + m_link->setEnabled(false); + horizontalLayout->addWidget(m_link); + m_unlink = new QPushButton(Tr::tr("Unlink Project")); + m_unlink->setEnabled(false); + horizontalLayout->addWidget(m_unlink); + verticalLayout->addLayout(horizontalLayout); + + connect(m_dashboardProjects, &QTreeWidget::itemSelectionChanged, + this, &AxivionProjectSettingsWidget::updateEnabledStates); + connect(m_fetchProjects, &QPushButton::clicked, + this, &AxivionProjectSettingsWidget::fetchProjects); + + updateUi(); +} + +void AxivionProjectSettingsWidget::fetchProjects() +{ + m_dashboardProjects->clear(); + m_fetchProjects->setEnabled(false); + // TODO perform query and populate m_dashboardProjects +} + +void AxivionProjectSettingsWidget::updateUi() +{ + const QString projectName = m_projectSettings->dashboardProjectName(); + if (projectName.isEmpty()) + m_linkedProject->setText(Tr::tr("This project is not linked to a dashboard project.")); + else + m_linkedProject->setText(Tr::tr("This project is linked to \"%1\".").arg(projectName)); + updateEnabledStates(); +} + +void AxivionProjectSettingsWidget::updateEnabledStates() +{ + const bool hasDashboardSettings = m_globalSettings->curl.isExecutableFile() + && !m_globalSettings->server.dashboard.isEmpty() + && !m_globalSettings->server.token.isEmpty(); + const bool linked = !m_projectSettings->dashboardProjectName().isEmpty(); + const bool linkable = m_dashboardProjects->topLevelItemCount() + && !m_dashboardProjects->selectedItems().isEmpty(); + + m_fetchProjects->setEnabled(hasDashboardSettings); + m_link->setEnabled(!linked && linkable); + m_unlink->setEnabled(linked); + + if (!hasDashboardSettings) { + m_infoLabel->setText(Tr::tr("Incomplete or misconfigured settings.")); + m_infoLabel->setType(Utils::InfoLabel::NotOk); + m_infoLabel->setVisible(true); + } +} + +} // Axivion::Internal diff --git a/plugins/axivion/axivionprojectsettings.h b/plugins/axivion/axivionprojectsettings.h new file mode 100644 index 00000000000..9501494c5fd --- /dev/null +++ b/plugins/axivion/axivionprojectsettings.h @@ -0,0 +1,61 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial + +#pragma once + +#include "axivionsettings.h" + +#include + +#include + +QT_BEGIN_NAMESPACE +class QLabel; +class QPushButton; +class QTreeWidget; +QT_END_NAMESPACE + +namespace ProjectExplorer { class Project; } + +namespace Utils { class InfoLabel; } + +namespace Axivion::Internal { + +class AxivionProjectSettings : public QObject +{ +public: + explicit AxivionProjectSettings(ProjectExplorer::Project *project); + + void setDashboardProjectName(const QString &name) { m_dashboardProjectName = name; } + QString dashboardProjectName() const { return m_dashboardProjectName; } + +private: + void load(); + void save(); + + ProjectExplorer::Project *m_project = nullptr; + QString m_dashboardProjectName; +}; + +class AxivionProjectSettingsWidget : public ProjectExplorer::ProjectSettingsWidget +{ +public: + explicit AxivionProjectSettingsWidget(ProjectExplorer::Project *project, + QWidget *parent = nullptr); + +private: + void fetchProjects(); + void updateUi(); + void updateEnabledStates(); + + AxivionProjectSettings *m_projectSettings = nullptr; + AxivionSettings *m_globalSettings; + QLabel *m_linkedProject = nullptr; + QTreeWidget *m_dashboardProjects = nullptr; + QPushButton *m_fetchProjects = nullptr; + QPushButton *m_link = nullptr; + QPushButton *m_unlink = nullptr; + Utils::InfoLabel *m_infoLabel = nullptr; +}; + +} // Axivion::Internal From 82bd1de9364f593211b5d141787a82789d6b4bae Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Tue, 13 Dec 2022 15:13:13 +0100 Subject: [PATCH 10/38] Provide first query mechanism Allow to link current project to a dashboard project. Change-Id: If73caab0e26b4b5151dbab1a6c9db72857fddacc Reviewed-by: David Schulz --- plugins/axivion/CMakeLists.txt | 2 + plugins/axivion/axivion.qbs | 4 ++ plugins/axivion/axivionplugin.cpp | 31 +++++++++ plugins/axivion/axivionplugin.h | 8 ++- plugins/axivion/axivionprojectsettings.cpp | 61 +++++++++++++++++ plugins/axivion/axivionprojectsettings.h | 6 ++ plugins/axivion/axivionquery.cpp | 79 ++++++++++++++++++++++ plugins/axivion/axivionquery.h | 40 +++++++++++ plugins/axivion/axivionresultparser.cpp | 62 +++++++++++++++++ plugins/axivion/axivionresultparser.h | 36 ++++++++++ plugins/axivion/axivionsettingspage.cpp | 2 + 11 files changed, 330 insertions(+), 1 deletion(-) create mode 100644 plugins/axivion/axivionquery.cpp create mode 100644 plugins/axivion/axivionquery.h create mode 100644 plugins/axivion/axivionresultparser.cpp create mode 100644 plugins/axivion/axivionresultparser.h diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index e5b4045b628..61ad3c7857a 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -16,6 +16,8 @@ add_qtc_plugin(Axivion axivionoutputpane.cpp axivionoutputpane.h axivionplugin.cpp axivionplugin.h axivionprojectsettings.h axivionprojectsettings.cpp + axivionquery.h axivionquery.cpp + axivionresultparser.h axivionresultparser.cpp axivionsettings.cpp axivionsettings.h axivionsettingspage.cpp axivionsettingspage.h axiviontr.h diff --git a/plugins/axivion/axivion.qbs b/plugins/axivion/axivion.qbs index 3e28ee0903b..1e437bb357a 100644 --- a/plugins/axivion/axivion.qbs +++ b/plugins/axivion/axivion.qbs @@ -18,6 +18,10 @@ QtcCommercialPlugin { "axivionplugin.h", "axivionprojectsettings.h", "axivionprojectsettings.cpp", + "axivionquery.h", + "axivionquery.cpp", + "axivionresultparser.h", + "axivionresultparser.cpp", "axivionsettings.cpp", "axivionsettings.h", "axivionsettingspage.cpp", diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 7156ad66566..62f4fa081be 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -19,6 +19,8 @@ # include #endif +#include + namespace Axivion::Internal { class AxivionPluginPrivate @@ -30,8 +32,14 @@ public: QHash projectSettings; }; +static AxivionPlugin *s_instance = nullptr; static AxivionPluginPrivate *dd = nullptr; +AxivionPlugin::AxivionPlugin() +{ + s_instance = this; +} + AxivionPlugin::~AxivionPlugin() { if (!dd->projectSettings.isEmpty()) { @@ -42,6 +50,11 @@ AxivionPlugin::~AxivionPlugin() dd = nullptr; } +AxivionPlugin *AxivionPlugin::instance() +{ + return s_instance; +} + bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessage) { Q_UNUSED(arguments) @@ -85,4 +98,22 @@ AxivionProjectSettings *AxivionPlugin::projectSettings(ProjectExplorer::Project return settings; } +bool AxivionPlugin::handleCertificateIssue() +{ + QTC_ASSERT(dd, return false); + + const QString serverHost = QUrl(dd->axivionSettings.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; + } + dd->axivionSettings.server.validateCert = false; + emit s_instance->settingsChanged(); + return true; +} + } // Axivion::Internal diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h index a9d49b37e15..0d71d005b96 100644 --- a/plugins/axivion/axivionplugin.h +++ b/plugins/axivion/axivionplugin.h @@ -18,12 +18,18 @@ class AxivionPlugin final : public ExtensionSystem::IPlugin Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Axivion.json") public: - AxivionPlugin() = default; + AxivionPlugin(); ~AxivionPlugin() final; + static AxivionPlugin *instance(); static AxivionSettings *settings(); static AxivionProjectSettings *projectSettings(ProjectExplorer::Project *project); + static bool handleCertificateIssue(); + +signals: + void settingsChanged(); + private: bool initialize(const QStringList &arguments, QString *errorMessage) final; void extensionsInitialized() final {} diff --git a/plugins/axivion/axivionprojectsettings.cpp b/plugins/axivion/axivionprojectsettings.cpp index 2d1bb3efa95..7e8dc7dfc87 100644 --- a/plugins/axivion/axivionprojectsettings.cpp +++ b/plugins/axivion/axivionprojectsettings.cpp @@ -4,11 +4,14 @@ #include "axivionprojectsettings.h" #include "axivionplugin.h" +#include "axivionquery.h" +#include "axivionresultparser.h" #include "axivionsettings.h" #include "axiviontr.h" #include #include +#include #include #include @@ -80,6 +83,12 @@ AxivionProjectSettingsWidget::AxivionProjectSettingsWidget(ProjectExplorer::Proj this, &AxivionProjectSettingsWidget::updateEnabledStates); connect(m_fetchProjects, &QPushButton::clicked, this, &AxivionProjectSettingsWidget::fetchProjects); + connect(m_link, &QPushButton::clicked, + this, &AxivionProjectSettingsWidget::linkProject); + connect(m_unlink, &QPushButton::clicked, + this, &AxivionProjectSettingsWidget::unlinkProject); + connect(AxivionPlugin::instance(), &AxivionPlugin::settingsChanged, + this, &AxivionProjectSettingsWidget::onSettingsChanged); updateUi(); } @@ -88,7 +97,59 @@ void AxivionProjectSettingsWidget::fetchProjects() { m_dashboardProjects->clear(); m_fetchProjects->setEnabled(false); + m_infoLabel->setVisible(false); // TODO perform query and populate m_dashboardProjects + const AxivionQuery query(AxivionQuery::DashboardInfo); + AxivionQueryRunner *runner = new AxivionQueryRunner(query, this); + connect(runner, &AxivionQueryRunner::resultRetrieved, + this, [this](const QByteArray &result){ + onDashboardInfoReceived(ResultParser::parseDashboardInfo(result)); + }); + connect(runner, &AxivionQueryRunner::finished, this, [runner]{ runner->deleteLater(); }); + runner->start(); +} + +void AxivionProjectSettingsWidget::onDashboardInfoReceived(const DashboardInfo &info) +{ + if (!info.error.isEmpty()) { + if (info.error.contains("credentials")) { + m_infoLabel->setText("Authentication failed. Check credentials settings."); + m_infoLabel->setType(Utils::InfoLabel::Error); + m_infoLabel->setVisible(true); + } + // send error to general message and discard results + // FIXME currently we do not get all errors - e.g. wrong curl calls + updateEnabledStates(); + return; + } + + for (const Project &project : info.projects) + new QTreeWidgetItem(m_dashboardProjects, {project.name}); + updateEnabledStates(); +} + +void AxivionProjectSettingsWidget::onSettingsChanged() +{ + m_dashboardProjects->clear(); + m_infoLabel->setVisible(false); + updateUi(); +} + +void AxivionProjectSettingsWidget::linkProject() +{ + const QList selected = m_dashboardProjects->selectedItems(); + QTC_ASSERT(selected.size() == 1, return); + + m_projectSettings->setDashboardProjectName(selected.first()->text(0)); + updateUi(); +} + +void AxivionProjectSettingsWidget::unlinkProject() +{ + QTC_ASSERT(!m_projectSettings->dashboardProjectName().isEmpty(), return); + + m_projectSettings->setDashboardProjectName({}); + updateUi(); } void AxivionProjectSettingsWidget::updateUi() diff --git a/plugins/axivion/axivionprojectsettings.h b/plugins/axivion/axivionprojectsettings.h index 9501494c5fd..c9bf147a51d 100644 --- a/plugins/axivion/axivionprojectsettings.h +++ b/plugins/axivion/axivionprojectsettings.h @@ -21,6 +21,8 @@ namespace Utils { class InfoLabel; } namespace Axivion::Internal { +class DashboardInfo; + class AxivionProjectSettings : public QObject { public: @@ -45,6 +47,10 @@ public: private: void fetchProjects(); + void onDashboardInfoReceived(const DashboardInfo &info); + void onSettingsChanged(); + void linkProject(); + void unlinkProject(); void updateUi(); void updateEnabledStates(); diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp new file mode 100644 index 00000000000..bff033fc125 --- /dev/null +++ b/plugins/axivion/axivionquery.cpp @@ -0,0 +1,79 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial + +#include "axivionquery.h" + +#include "axivionplugin.h" +#include "axivionsettings.h" + +#include +#include + +using namespace Utils; + +namespace Axivion::Internal { + +AxivionQuery::AxivionQuery(QueryType type, const QStringList ¶meters) + : m_type(type) + , m_parameters(parameters) +{ +} + +QString AxivionQuery::toString() const +{ + QString query = "/api"; // common for all + switch (m_type) { + case NoQuery: + return {}; + case DashboardInfo: + return query; + } + + return {}; +} + +AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *parent) + : QObject(parent) +{ + const AxivionSettings *settings = AxivionPlugin::settings(); + const AxivionServer server = settings->server; + + QStringList args = server.curlArguments(); + // TODO handle paginated results + args << "--header" << "Authorization: AxToken " + server.token; + + QString url = server.dashboard; + while (url.endsWith('/')) url.chop(1); + url += query.toString(); + args << url; + + m_process.setCommand({settings->curl, args}); + connect(&m_process, &QtcProcess::done, this, [this]{ + if (m_process.result() != ProcessResult::FinishedWithSuccess) { + const int exitCode = m_process.exitCode(); + if (m_process.exitStatus() == QProcess::NormalExit + && (exitCode == 35 || exitCode == 60) + && AxivionPlugin::handleCertificateIssue()) { + // prepend -k for re-requesting same query + CommandLine cmdline = m_process.commandLine(); + cmdline.prependArgs({"-k"}); + m_process.close(); + m_process.setCommand(cmdline); + start(); + return; + } + // output error to general message + } else { + emit resultRetrieved(m_process.readAllStandardOutput()); + } + emit finished(); + }); +} + +void AxivionQueryRunner::start() +{ + QTC_ASSERT(!m_process.isRunning(), return); + m_process.start(); +} + +} // Axivion::Internal diff --git a/plugins/axivion/axivionquery.h b/plugins/axivion/axivionquery.h new file mode 100644 index 00000000000..85721b07033 --- /dev/null +++ b/plugins/axivion/axivionquery.h @@ -0,0 +1,40 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial + +#pragma once + +#include + +#include + +namespace Axivion::Internal { + +class AxivionQuery +{ +public: + enum QueryType {NoQuery, DashboardInfo}; + explicit AxivionQuery(QueryType type, const QStringList ¶meters = {}); + + QString toString() const; + +private: + QueryType m_type = NoQuery; + QStringList m_parameters; +}; + +class AxivionQueryRunner : public QObject +{ + Q_OBJECT +public: + explicit AxivionQueryRunner(const AxivionQuery &query, QObject *parent = nullptr); + void start(); + +signals: + void finished(); + void resultRetrieved(const QByteArray &json); + +private: + Utils::QtcProcess m_process; +}; + +} // Axivion::Internal diff --git a/plugins/axivion/axivionresultparser.cpp b/plugins/axivion/axivionresultparser.cpp new file mode 100644 index 00000000000..59f90854d37 --- /dev/null +++ b/plugins/axivion/axivionresultparser.cpp @@ -0,0 +1,62 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial + +#include "axivionresultparser.h" + +#include +#include +#include + +namespace Axivion::Internal { + + +namespace ResultParser { + +DashboardInfo parseDashboardInfo(const QByteArray &input) +{ + DashboardInfo result; + + QJsonParseError error; + const QJsonDocument doc = QJsonDocument::fromJson(input, &error); + if (error.error != QJsonParseError::NoError) { + if (input.startsWith("Authentication failed:")) + result.error = QString::fromUtf8(input); + else + result.error = error.errorString(); + return result; + } + + if (!doc.isObject()) { + result.error = "Not an object."; + return result; + } + const QJsonObject object = doc.object(); + result.mainUrl = object.value("mainUrl").toString(); + + if (!object.contains("projects")) { + result.error = "Missing projects information."; + return result; + } + const QJsonValue projects = object.value("projects"); + if (!projects.isArray()) { + result.error = "Projects information not an array."; + return result; + } + const QJsonArray array = projects.toArray(); + for (const QJsonValue &val : array) { + if (!val.isObject()) + continue; + const QJsonObject projectObject = val.toObject(); + Project project; + project.name = projectObject.value("name").toString(); + project.url = projectObject.value("url").toString(); + if (project.name.isEmpty() || project.url.isEmpty()) + continue; + result.projects.append(project); + } + return result; +} + +} // ResultParser + +} // Axivion::Internal diff --git a/plugins/axivion/axivionresultparser.h b/plugins/axivion/axivionresultparser.h new file mode 100644 index 00000000000..57a0127cc02 --- /dev/null +++ b/plugins/axivion/axivionresultparser.h @@ -0,0 +1,36 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial + +#pragma once + +#include + +namespace Axivion::Internal { + +class BaseResult +{ +public: + QString error; +}; + +class Project : public BaseResult +{ +public: + QString name; + QString url; +}; + +class DashboardInfo : public BaseResult +{ +public: + QString mainUrl; + QList projects; +}; + +namespace ResultParser { + +DashboardInfo parseDashboardInfo(const QByteArray &input); + +} // ResultParser + +} // Axivion::Internal diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index ffe5122442e..bd0ddee04c9 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -3,6 +3,7 @@ #include "axivionsettingspage.h" +#include "axivionplugin.h" #include "axivionsettings.h" #include "axiviontr.h" @@ -160,6 +161,7 @@ void AxivionSettingsWidget::apply() m_settings->server = m_dashboardDisplay->dashboardServer(); m_settings->curl = m_curlPC.filePath(); m_settings->toSettings(Core::ICore::settings()); + emit AxivionPlugin::instance()->settingsChanged(); } void AxivionSettingsWidget::showEditServerDialog() From cc0b392e873b28c38b0cea93d1a8e7f698c7efa5 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 16 Dec 2022 08:55:20 +0100 Subject: [PATCH 11/38] Tweak error handling a bit Always get http headers of the response to be able to handle issues more explicitly. These headers also contain additional information we will need later on. Change-Id: I062e97726a473c16b29cd84be0aa37260bac4ed8 Reviewed-by: David Schulz --- plugins/axivion/axivionprojectsettings.cpp | 10 +-- plugins/axivion/axivionquery.cpp | 4 +- plugins/axivion/axivionresultparser.cpp | 76 ++++++++++++++++++---- 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/plugins/axivion/axivionprojectsettings.cpp b/plugins/axivion/axivionprojectsettings.cpp index 7e8dc7dfc87..3d8b11c70dc 100644 --- a/plugins/axivion/axivionprojectsettings.cpp +++ b/plugins/axivion/axivionprojectsettings.cpp @@ -112,13 +112,9 @@ void AxivionProjectSettingsWidget::fetchProjects() void AxivionProjectSettingsWidget::onDashboardInfoReceived(const DashboardInfo &info) { if (!info.error.isEmpty()) { - if (info.error.contains("credentials")) { - m_infoLabel->setText("Authentication failed. Check credentials settings."); - m_infoLabel->setType(Utils::InfoLabel::Error); - m_infoLabel->setVisible(true); - } - // send error to general message and discard results - // FIXME currently we do not get all errors - e.g. wrong curl calls + m_infoLabel->setText(info.error); + m_infoLabel->setType(Utils::InfoLabel::Error); + m_infoLabel->setVisible(true); updateEnabledStates(); return; } diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp index bff033fc125..8b8cf48938f 100644 --- a/plugins/axivion/axivionquery.cpp +++ b/plugins/axivion/axivionquery.cpp @@ -39,7 +39,7 @@ AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *paren const AxivionServer server = settings->server; QStringList args = server.curlArguments(); - // TODO handle paginated results + args << "-i"; args << "--header" << "Authorization: AxToken " + server.token; QString url = server.dashboard; @@ -62,7 +62,7 @@ AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *paren start(); return; } - // output error to general message + emit resultRetrieved(m_process.readAllStandardError()); } else { emit resultRetrieved(m_process.readAllStandardOutput()); } diff --git a/plugins/axivion/axivionresultparser.cpp b/plugins/axivion/axivionresultparser.cpp index 59f90854d37..5ef89a1cce1 100644 --- a/plugins/axivion/axivionresultparser.cpp +++ b/plugins/axivion/axivionresultparser.cpp @@ -6,9 +6,69 @@ #include #include #include +#include + +#include namespace Axivion::Internal { +static std::pair splitHeaderAndBody(const QByteArray &input) +{ + QByteArray header; + QByteArray json; + int emptyLine = input.indexOf("\r\n\r\n"); // we always get \r\n as line separator + if (emptyLine != -1) { + header = input.left(emptyLine); + json = input.mid(emptyLine + 4); + } else { + json = input; + } + return {header, json}; +} + +static int httpStatus(const QByteArray &header) +{ + int firstHeaderEnd = header.indexOf("\r\n"); + if (firstHeaderEnd == -1) + return 600; // unexpected header + const QString firstLine = QString::fromUtf8(header.first(firstHeaderEnd)); + static const QRegularExpression regex(R"(^HTTP/\d\.\d (\d{3}) .*$)"); + const QRegularExpressionMatch match = regex.match(firstLine); + return match.hasMatch() ? match.captured(1).toInt() : 601; +} + +static std::pair prehandleHeaderAndBody(const QByteArray &header, + const QByteArray &body) +{ + BaseResult result; + if (header.isEmpty()) { + result.error = QString::fromUtf8(body); // we likely had a curl problem + return {result, {}}; + } + int status = httpStatus(header); + if ((status > 399) || (status > 299 && body.isEmpty())) { // FIXME handle some explicitly? + const QString statusStr = QString::number(status); + if (body.isEmpty() || body.startsWith('<')) // likely an html response or redirect + result.error = QLatin1String("(%1)").arg(statusStr); + else + result.error = QLatin1String("%1 (%2)").arg(QString::fromUtf8(body)).arg(statusStr); + return {result, {}}; + } + + QJsonParseError error; + const QJsonDocument doc = QJsonDocument::fromJson(body, &error); + if (error.error != QJsonParseError::NoError) { + result.error = error.errorString(); + return {result, doc}; + } + + if (!doc.isObject()) { + result.error = "Not an object."; + return {result, {}}; + } + + return {result, doc}; +} namespace ResultParser { @@ -16,18 +76,10 @@ DashboardInfo parseDashboardInfo(const QByteArray &input) { DashboardInfo result; - QJsonParseError error; - const QJsonDocument doc = QJsonDocument::fromJson(input, &error); - if (error.error != QJsonParseError::NoError) { - if (input.startsWith("Authentication failed:")) - result.error = QString::fromUtf8(input); - else - result.error = error.errorString(); - return result; - } - - if (!doc.isObject()) { - result.error = "Not an object."; + auto [header, body] = splitHeaderAndBody(input); + auto [error, doc] = prehandleHeaderAndBody(header, body); + if (!error.error.isEmpty()) { + result.error = error.error; return result; } const QJsonObject object = doc.object(); From b741b2eeebca2e99187a4a7fe92b01a7eddd9d62 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 14 Dec 2022 12:11:03 +0100 Subject: [PATCH 12/38] Provide functionality for fetching project information Change-Id: Id0968c08eb3017eb6f902c3cea3a363bc3f0c35c Reviewed-by: David Schulz --- plugins/axivion/axivionoutputpane.cpp | 5 + plugins/axivion/axivionoutputpane.h | 1 + plugins/axivion/axivionplugin.cpp | 69 ++++++++- plugins/axivion/axivionplugin.h | 2 + plugins/axivion/axivionprojectsettings.cpp | 4 +- plugins/axivion/axivionquery.cpp | 6 + plugins/axivion/axivionquery.h | 2 +- plugins/axivion/axivionresultparser.cpp | 155 +++++++++++++++++++++ plugins/axivion/axivionresultparser.h | 44 ++++++ 9 files changed, 285 insertions(+), 3 deletions(-) diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp index d7896e02d0f..81df73cbc4f 100644 --- a/plugins/axivion/axivionoutputpane.cpp +++ b/plugins/axivion/axivionoutputpane.cpp @@ -89,4 +89,9 @@ void AxivionOutputPane::goToPrev() { } +void AxivionOutputPane::updateDashboard() +{ + +} + } // Axivion::Internal diff --git a/plugins/axivion/axivionoutputpane.h b/plugins/axivion/axivionoutputpane.h index 63ec48097ec..81b1647154c 100644 --- a/plugins/axivion/axivionoutputpane.h +++ b/plugins/axivion/axivionoutputpane.h @@ -33,6 +33,7 @@ public: void goToNext() override; void goToPrev() override; + void updateDashboard(); private: QStackedWidget *m_outputWidget = nullptr; }; diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 62f4fa081be..f3e6cd8c184 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -5,14 +5,18 @@ #include "axivionoutputpane.h" #include "axivionprojectsettings.h" +#include "axivionquery.h" +#include "axivionresultparser.h" #include "axivionsettings.h" #include "axivionsettingspage.h" #include "axiviontr.h" #include +#include #include #include #include +#include #include #ifdef LICENSECHECKER @@ -20,16 +24,22 @@ #endif #include +#include namespace Axivion::Internal { -class AxivionPluginPrivate +class AxivionPluginPrivate : public QObject { public: + void fetchProjectInfo(const QString &projectName); + void handleProjectInfo(const ProjectInfo &info); + AxivionSettings axivionSettings; AxivionSettingsPage axivionSettingsPage{&axivionSettings}; AxivionOutputPane axivionOutputPane; QHash projectSettings; + ProjectInfo currentProjectInfo; + bool runningQuery = false; }; static AxivionPlugin *s_instance = nullptr; @@ -78,9 +88,26 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa return new AxivionProjectSettingsWidget(project); }); ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); + connect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::startupProjectChanged, + this, &AxivionPlugin::onStartupProjectChanged); return true; } +void AxivionPlugin::onStartupProjectChanged() +{ + QTC_ASSERT(dd, return); + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + if (!project) { + dd->currentProjectInfo = ProjectInfo(); + dd->axivionOutputPane.updateDashboard(); + return; + } + + const AxivionProjectSettings *projSettings = projectSettings(project); + dd->fetchProjectInfo(projSettings->dashboardProjectName()); +} + AxivionSettings *AxivionPlugin::settings() { QTC_ASSERT(dd, return nullptr); @@ -116,4 +143,44 @@ bool AxivionPlugin::handleCertificateIssue() return true; } +void AxivionPlugin::fetchProjectInfo(const QString &projectName) +{ + QTC_ASSERT(dd, return); + dd->fetchProjectInfo(projectName); +} + +void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) +{ + if (runningQuery) { // re-schedule + QTimer::singleShot(3000, [this, projectName]{ fetchProjectInfo(projectName); }); + return; + } + if (projectName.isEmpty()) { + currentProjectInfo = ProjectInfo(); + axivionOutputPane.updateDashboard(); + return; + } + runningQuery = true; + + AxivionQuery query(AxivionQuery::ProjectInfo, {projectName}); + AxivionQueryRunner *runner = new AxivionQueryRunner(query, this); + connect(runner, &AxivionQueryRunner::resultRetrieved, this, [this](const QByteArray &result){ + handleProjectInfo(ResultParser::parseProjectInfo(result)); + }); + connect(runner, &AxivionQueryRunner::finished, [runner]{ runner->deleteLater(); }); + runner->start(); +} + +void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) +{ + runningQuery = false; + if (!info.error.isEmpty()) { + Core::MessageManager::writeFlashing("Axivion: " + info.error); + return; + } + + currentProjectInfo = info; + axivionOutputPane.updateDashboard(); +} + } // Axivion::Internal diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h index 0d71d005b96..fb0da44cbd0 100644 --- a/plugins/axivion/axivionplugin.h +++ b/plugins/axivion/axivionplugin.h @@ -26,6 +26,7 @@ public: static AxivionProjectSettings *projectSettings(ProjectExplorer::Project *project); static bool handleCertificateIssue(); + static void fetchProjectInfo(const QString &projectName); signals: void settingsChanged(); @@ -33,6 +34,7 @@ signals: private: bool initialize(const QStringList &arguments, QString *errorMessage) final; void extensionsInitialized() final {} + void onStartupProjectChanged(); }; } // Axivion::Internal diff --git a/plugins/axivion/axivionprojectsettings.cpp b/plugins/axivion/axivionprojectsettings.cpp index 3d8b11c70dc..00844d10746 100644 --- a/plugins/axivion/axivionprojectsettings.cpp +++ b/plugins/axivion/axivionprojectsettings.cpp @@ -136,8 +136,10 @@ void AxivionProjectSettingsWidget::linkProject() const QList selected = m_dashboardProjects->selectedItems(); QTC_ASSERT(selected.size() == 1, return); - m_projectSettings->setDashboardProjectName(selected.first()->text(0)); + const QString projectName = selected.first()->text(0); + m_projectSettings->setDashboardProjectName(projectName); updateUi(); + AxivionPlugin::fetchProjectInfo(projectName); } void AxivionProjectSettingsWidget::unlinkProject() diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp index 8b8cf48938f..4885b74ff46 100644 --- a/plugins/axivion/axivionquery.cpp +++ b/plugins/axivion/axivionquery.cpp @@ -9,6 +9,8 @@ #include #include +#include + using namespace Utils; namespace Axivion::Internal { @@ -27,6 +29,10 @@ QString AxivionQuery::toString() const return {}; case DashboardInfo: return query; + case ProjectInfo: + QTC_ASSERT(m_parameters.size() == 1, return {}); + query += "/projects/" + QUrl::toPercentEncoding(m_parameters.first()); + return query; } return {}; diff --git a/plugins/axivion/axivionquery.h b/plugins/axivion/axivionquery.h index 85721b07033..721700ab3c2 100644 --- a/plugins/axivion/axivionquery.h +++ b/plugins/axivion/axivionquery.h @@ -12,7 +12,7 @@ namespace Axivion::Internal { class AxivionQuery { public: - enum QueryType {NoQuery, DashboardInfo}; + enum QueryType {NoQuery, DashboardInfo, ProjectInfo}; explicit AxivionQuery(QueryType type, const QStringList ¶meters = {}); QString toString() const; diff --git a/plugins/axivion/axivionresultparser.cpp b/plugins/axivion/axivionresultparser.cpp index 5ef89a1cce1..4d765331623 100644 --- a/plugins/axivion/axivionresultparser.cpp +++ b/plugins/axivion/axivionresultparser.cpp @@ -70,6 +70,124 @@ static std::pair prehandleHeaderAndBody(const QByteAr return {result, doc}; } +static User::UserType userTypeForString(const QString &type) +{ + if (type == "DASHBOARD_USER") + return User::Dashboard; + if (type == "VIRTUAL_USER") + return User::Virtual; + return User::Unknown; +} + +static User userFromJson(const QJsonObject &object) +{ + User result; + if (object.isEmpty()) { + result.error = "Not a user object."; + return result; + } + result.name = object.value("name").toString(); + result.displayName = object.value("displayName").toString(); + result.type = userTypeForString(object.value("type").toString()); + return result; +} + +static QList usersFromJson(const QJsonArray &array) +{ + QList result; + for (const QJsonValue &value : array) { + User user = userFromJson(value.toObject()); + if (!user.error.isEmpty()) // add this error to result.error? + continue; + result.append(user); + } + return result; +} + +static IssueCount issueCountFromJson(const QJsonObject &object) +{ + IssueCount result; + if (object.isEmpty()) { + result.error = "Not an issue count object."; + return result; + } + result.added = object.value("Added").toInt(); + result.removed = object.value("Removed").toInt(); + result.total = object.value("Total").toInt(); + return result; +} + +static QList issueCountsFromJson(const QJsonObject &object) +{ + QList result; + + const QStringList keys = object.keys(); + for (const QString &k : keys) { + IssueCount issue = issueCountFromJson(object.value(k).toObject()); + if (!issue.error.isEmpty()) // add this error to result.error? + continue; + issue.issueKind = k; + result.append(issue); + } + return result; +} + +static ResultVersion versionFromJson(const QJsonObject &object) +{ + ResultVersion result; + if (object.isEmpty()) { + result.error = "Not a version object."; + return result; + } + const QJsonValue issuesValue = object.value("issueCounts"); + if (!issuesValue.isObject()) { + result.error = "Not an object (issueCounts)."; + return result; + } + result.issueCounts = issueCountsFromJson(issuesValue.toObject()); + result.timeStamp = object.value("date").toString(); + result.name = object.value("name").toString(); + result.linesOfCode = object.value("linesOfCode").toInt(); + return result; +} + +static QList versionsFromJson(const QJsonArray &array) +{ + QList result; + for (const QJsonValue &value : array) { + ResultVersion version = versionFromJson(value.toObject()); + if (!version.error.isEmpty()) // add this error to result.error? + continue; + result.append(version); + } + return result; +} + +static IssueKind issueKindFromJson(const QJsonObject &object) +{ + IssueKind result; + if (object.isEmpty()) { + result.error = "Not an issue kind object."; + return result; + } + result.prefix = object.value("prefix").toString(); + result.niceSingular = object.value("niceSingularName").toString(); + result.nicePlural = object.value("nicePluralName").toString(); + return result; +} + +static QList issueKindsFromJson(const QJsonArray &array) +{ + QList result; + for (const QJsonValue &value : array) { + IssueKind kind = issueKindFromJson(value.toObject()); + if (!kind.error.isEmpty()) // add this error to result.error? + continue; + result.append(kind); + } + return result; +} + namespace ResultParser { DashboardInfo parseDashboardInfo(const QByteArray &input) @@ -109,6 +227,43 @@ DashboardInfo parseDashboardInfo(const QByteArray &input) return result; } +ProjectInfo parseProjectInfo(const QByteArray &input) +{ + ProjectInfo result; + + auto [header, body] = splitHeaderAndBody(input); + auto [error, doc] = prehandleHeaderAndBody(header, body); + if (!error.error.isEmpty()) { + result.error = error.error; + return result; + } + + const QJsonObject object = doc.object(); + result.name = object.value("name").toString(); + + const QJsonValue usersValue = object.value("users"); + if (!usersValue.isArray()) { + result.error = "Malformed json response (users)."; + return result; + } + result.users = usersFromJson(usersValue.toArray()); + + const QJsonValue versionsValue = object.value("versions"); + if (!versionsValue.isArray()) { + result.error = "Malformed json response (versions)."; + return result; + } + result.versions = versionsFromJson(versionsValue.toArray()); + + const QJsonValue issueKindsValue = object.value("issueKinds"); + if (!issueKindsValue.isArray()) { + result.error = "Malformed json response (issueKinds)."; + return result; + } + result.issueKinds = issueKindsFromJson(issueKindsValue.toArray()); + return result; +} + } // ResultParser } // Axivion::Internal diff --git a/plugins/axivion/axivionresultparser.h b/plugins/axivion/axivionresultparser.h index 57a0127cc02..9a308f9950e 100644 --- a/plugins/axivion/axivionresultparser.h +++ b/plugins/axivion/axivionresultparser.h @@ -27,9 +27,53 @@ public: QList projects; }; +class User : public BaseResult +{ +public: + QString name; + QString displayName; + enum UserType { Dashboard, Virtual, Unknown } type; +}; + +class IssueKind : public BaseResult +{ +public: + QString prefix; + QString niceSingular; + QString nicePlural; +}; + +class IssueCount : public BaseResult +{ +public: + QString issueKind; + int total = 0; + int added = 0; + int removed = 0; +}; + +class ResultVersion : public BaseResult +{ +public: + QString name; + QString timeStamp; + QList issueCounts; + int linesOfCode = 0; +}; + +class ProjectInfo : public BaseResult +{ +public: + QString name; + QList users; + QList versions; + QList issueKinds; +}; + namespace ResultParser { DashboardInfo parseDashboardInfo(const QByteArray &input); +ProjectInfo parseProjectInfo(const QByteArray &input); } // ResultParser From 5ac1629976a4b7a33fc873fd8c1a03185be00fa2 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 14 Dec 2022 13:53:00 +0100 Subject: [PATCH 13/38] Provide some minimal project dashboard widget Some placeholder which is populated if the current project is linked to a dashboard project to have something to continue work. Ui is likely to change over time. Change-Id: I28e7df95006e5db551fcfe38adf68e5dae7c094d Reviewed-by: David Schulz --- plugins/axivion/axivionoutputpane.cpp | 85 +++++++++++++++++++++- plugins/axivion/axivionplugin.cpp | 6 ++ plugins/axivion/axivionplugin.h | 3 +- plugins/axivion/axivionprojectsettings.cpp | 1 + 4 files changed, 93 insertions(+), 2 deletions(-) diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp index 81df73cbc4f..b1b4ec98a1b 100644 --- a/plugins/axivion/axivionoutputpane.cpp +++ b/plugins/axivion/axivionoutputpane.cpp @@ -3,18 +3,96 @@ #include "axivionoutputpane.h" +#include "axivionplugin.h" +#include "axivionresultparser.h" #include "axiviontr.h" #include +#include +#include #include namespace Axivion::Internal { +class DashboardWidget : public QWidget +{ +public: + explicit DashboardWidget(QWidget *parent = nullptr); + void updateUi(); + bool hasProject() const { return !m_project->text().isEmpty(); } +private: + QLabel *m_project = nullptr; + QLabel *m_loc = nullptr; + QFormLayout *m_formLayout = nullptr; +}; + +DashboardWidget::DashboardWidget(QWidget *parent) + : QWidget(parent) +{ + QVBoxLayout *layout = new QVBoxLayout(this); + QFormLayout *projectLayout = new QFormLayout; + m_project = new QLabel(this); + projectLayout->addRow(Tr::tr("Project:"), m_project); + m_loc = new QLabel(this); + projectLayout->addRow(Tr::tr("Lines of Code:"), m_loc); + layout->addLayout(projectLayout); + m_formLayout = new QFormLayout; + layout->addLayout(m_formLayout); +} + +void DashboardWidget::updateUi() +{ + const ProjectInfo &info = AxivionPlugin::projectInfo(); + m_project->setText(info.name); + m_loc->setText({}); + while (m_formLayout->rowCount()) + m_formLayout->removeRow(0); + + if (info.versions.isEmpty()) + return; + + const ResultVersion &last = info.versions.last(); + m_loc->setText(QString::number(last.linesOfCode)); + + const QString tmpl("%1 %2 +%3 / -%4"); + auto apply = [&tmpl](int t, int a, int r){ + QChar tr = (a == r ? '=' : (a < r ? '^' : 'v')); + return tmpl.arg(t, 10, 10, QLatin1Char(' ')).arg(tr).arg(a, 5, 10, QLatin1Char(' ')) + .arg(r, 5, 10, QLatin1Char(' ')); + }; + const QList &issueKinds = info.issueKinds; + auto toolTip = [issueKinds](const QString &prefix){ + for (const IssueKind &kind : issueKinds) { + if (kind.prefix == prefix) + return kind.nicePlural; + } + return QString(); + }; + int allTotal = 0, allAdded = 0, allRemoved = 0; + for (auto issueCount : std::as_const(last.issueCounts)) { + allTotal += issueCount.total; + allAdded += issueCount.added; + allRemoved += issueCount.removed; + const QString txt = apply(issueCount.total, issueCount.added, issueCount.removed); + const QString currentToolTip = toolTip(issueCount.issueKind); + QLabel *label = new QLabel(issueCount.issueKind, this); + label->setToolTip(currentToolTip); + QLabel *values = new QLabel(txt, this); + values->setToolTip(currentToolTip); + m_formLayout->addRow(label, values); + } + + QLabel *label = new QLabel(apply(allTotal, allAdded, allRemoved), this); + m_formLayout->addRow(Tr::tr("Total:"), label); +} + AxivionOutputPane::AxivionOutputPane(QObject *parent) : Core::IOutputPane(parent) { m_outputWidget = new QStackedWidget; + DashboardWidget *dashboardWidget = new DashboardWidget(m_outputWidget); + m_outputWidget->addWidget(dashboardWidget); } AxivionOutputPane::~AxivionOutputPane() @@ -91,7 +169,12 @@ void AxivionOutputPane::goToPrev() void AxivionOutputPane::updateDashboard() { - + if (auto dashboard = static_cast(m_outputWidget->widget(0))) { + dashboard->updateUi(); + m_outputWidget->setCurrentIndex(0); + if (dashboard->hasProject()) + flash(); + } } } // Axivion::Internal diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index f3e6cd8c184..75186c30390 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -149,6 +149,12 @@ void AxivionPlugin::fetchProjectInfo(const QString &projectName) dd->fetchProjectInfo(projectName); } +ProjectInfo AxivionPlugin::projectInfo() +{ + QTC_ASSERT(dd, return {}); + return dd->currentProjectInfo; +} + void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) { if (runningQuery) { // re-schedule diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h index fb0da44cbd0..86f23ee5923 100644 --- a/plugins/axivion/axivionplugin.h +++ b/plugins/axivion/axivionplugin.h @@ -11,6 +11,7 @@ namespace Axivion::Internal { class AxivionSettings; class AxivionProjectSettings; +class ProjectInfo; class AxivionPlugin final : public ExtensionSystem::IPlugin { @@ -27,7 +28,7 @@ public: static bool handleCertificateIssue(); static void fetchProjectInfo(const QString &projectName); - + static ProjectInfo projectInfo(); signals: void settingsChanged(); diff --git a/plugins/axivion/axivionprojectsettings.cpp b/plugins/axivion/axivionprojectsettings.cpp index 00844d10746..74fa66fcdcf 100644 --- a/plugins/axivion/axivionprojectsettings.cpp +++ b/plugins/axivion/axivionprojectsettings.cpp @@ -148,6 +148,7 @@ void AxivionProjectSettingsWidget::unlinkProject() m_projectSettings->setDashboardProjectName({}); updateUi(); + AxivionPlugin::fetchProjectInfo({}); } void AxivionProjectSettingsWidget::updateUi() From 3503efff551aad7bb0e944bc323df2ce436ae116 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 16 Dec 2022 23:11:46 +0100 Subject: [PATCH 14/38] Perform style violation query on file open Enable style violation queries on files and create some annotations for the results. This is just a first step to have visible results, but will need further tweaking and improvements at several areas. Change-Id: Icead2c5232194e7c3beb027d3f7975c90ecadeb5 Reviewed-by: David Schulz --- plugins/axivion/CMakeLists.txt | 2 +- plugins/axivion/axivion.qbs | 1 + plugins/axivion/axivionplugin.cpp | 74 ++++++++++++++++++++++++ plugins/axivion/axivionquery.cpp | 7 +++ plugins/axivion/axivionquery.h | 2 +- plugins/axivion/axivionresultparser.cpp | 76 +++++++++++++++++++++++-- plugins/axivion/axivionresultparser.h | 19 +++++++ 7 files changed, 175 insertions(+), 6 deletions(-) diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index 61ad3c7857a..f904cf308f9 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -8,7 +8,7 @@ endif() add_qtc_plugin(Axivion PLUGIN_DEPENDS - QtCreator::Core QtCreator::ProjectExplorer + QtCreator::Core QtCreator::ProjectExplorer QtCreator::TextEditor ${LICENSECHECKER_DEPENDS} DEPENDS Qt5::Network Qt5::Widgets QtCreator::ExtensionSystem QtCreator::Utils SOURCES diff --git a/plugins/axivion/axivion.qbs b/plugins/axivion/axivion.qbs index 1e437bb357a..4e20de194ba 100644 --- a/plugins/axivion/axivion.qbs +++ b/plugins/axivion/axivion.qbs @@ -5,6 +5,7 @@ QtcCommercialPlugin { Depends { name: "Core" } Depends { name: "ProjectExplorer" } + Depends { name: "TextEditor" } Depends { name: "ExtensionSystem" } Depends { name: "Utils" } Depends { name: "Qt.widgets" } diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 75186c30390..81accb47c58 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -11,12 +11,16 @@ #include "axivionsettingspage.h" #include "axiviontr.h" +#include #include #include #include #include #include #include +#include +#include +#include #include #ifdef LICENSECHECKER @@ -33,6 +37,9 @@ class AxivionPluginPrivate : public QObject public: void fetchProjectInfo(const QString &projectName); void handleProjectInfo(const ProjectInfo &info); + void onDocumentOpened(Core::IDocument *doc); + void onDocumentClosed(Core::IDocument * doc); + void handleIssuesForFile(const IssuesList &issues); AxivionSettings axivionSettings; AxivionSettingsPage axivionSettingsPage{&axivionSettings}; @@ -91,6 +98,10 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa connect(ProjectExplorer::SessionManager::instance(), &ProjectExplorer::SessionManager::startupProjectChanged, this, &AxivionPlugin::onStartupProjectChanged); + connect(Core::EditorManager::instance(), &Core::EditorManager::documentOpened, + dd, &AxivionPluginPrivate::onDocumentOpened); + connect(Core::EditorManager::instance(), &Core::EditorManager::documentClosed, + dd, &AxivionPluginPrivate::onDocumentClosed); return true; } @@ -187,6 +198,69 @@ void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) currentProjectInfo = info; axivionOutputPane.updateDashboard(); + + if (currentProjectInfo.name.isEmpty()) + return; + // FIXME handle already opened documents +} + +void AxivionPluginPrivate::onDocumentOpened(Core::IDocument *doc) +{ + if (currentProjectInfo.name.isEmpty()) // we do not have a project info (yet) + return; + + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + if (!doc || !project->isKnownFile(doc->filePath())) + return; + + Utils::FilePath relative = doc->filePath().relativeChildPath(project->projectDirectory()); + // for now only style violations + AxivionQuery query(AxivionQuery::IssuesForFileList, {currentProjectInfo.name, "SV", + relative.path() } ); + 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(doc); + if (!document) + return; + + const TextEditor::TextMarks marks = document->marks(); + auto axivionId = Utils::Id("AxivionTextMark"); + for (auto m : marks) { + if (m->category() == axivionId) + delete m; + } +} + +void AxivionPluginPrivate::handleIssuesForFile(const IssuesList &issues) +{ + if (issues.issues.isEmpty()) + return; + + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + if (!project) + return; + + const Utils::FilePath filePath = project->projectDirectory() + .pathAppended(issues.issues.first().filePath); + + auto axivionId = Utils::Id("AxivionTextMark"); + 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 + auto mark = new TextEditor::TextMark(filePath, issue.lineNumber, axivionId); + mark->setToolTip(issue.errorNumber + " " + issue.entity + ": " + issue.message); + mark->setPriority(TextEditor::TextMark::NormalPriority); + mark->setLineAnnotation(issue.errorNumber); + } } } // Axivion::Internal diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp index 4885b74ff46..4fa49bf75a3 100644 --- a/plugins/axivion/axivionquery.cpp +++ b/plugins/axivion/axivionquery.cpp @@ -33,6 +33,13 @@ QString AxivionQuery::toString() const QTC_ASSERT(m_parameters.size() == 1, return {}); query += "/projects/" + QUrl::toPercentEncoding(m_parameters.first()); return query; + case IssuesForFileList: + QTC_ASSERT(m_parameters.size() == 3, return {}); + // FIXME shall we validate the kind? (some kinds do not support path filter) + query += "/projects/" + QUrl::toPercentEncoding(m_parameters.first()) + + "/issues?kind=" + m_parameters.at(1) + "&filter_path=" + + QUrl::toPercentEncoding(m_parameters.at(2)) + "&format=csv"; + return query; } return {}; diff --git a/plugins/axivion/axivionquery.h b/plugins/axivion/axivionquery.h index 721700ab3c2..6cf5ac07ae3 100644 --- a/plugins/axivion/axivionquery.h +++ b/plugins/axivion/axivionquery.h @@ -12,7 +12,7 @@ namespace Axivion::Internal { class AxivionQuery { public: - enum QueryType {NoQuery, DashboardInfo, ProjectInfo}; + enum QueryType {NoQuery, DashboardInfo, ProjectInfo, IssuesForFileList}; explicit AxivionQuery(QueryType type, const QStringList ¶meters = {}); QString toString() const; diff --git a/plugins/axivion/axivionresultparser.cpp b/plugins/axivion/axivionresultparser.cpp index 4d765331623..9c7da845883 100644 --- a/plugins/axivion/axivionresultparser.cpp +++ b/plugins/axivion/axivionresultparser.cpp @@ -3,6 +3,8 @@ #include "axivionresultparser.h" +#include + #include #include #include @@ -37,13 +39,12 @@ static int httpStatus(const QByteArray &header) return match.hasMatch() ? match.captured(1).toInt() : 601; } -static std::pair prehandleHeaderAndBody(const QByteArray &header, - const QByteArray &body) +static BaseResult prehandleHeader(const QByteArray &header, const QByteArray &body) { BaseResult result; if (header.isEmpty()) { result.error = QString::fromUtf8(body); // we likely had a curl problem - return {result, {}}; + return result; } int status = httpStatus(header); if ((status > 399) || (status > 299 && body.isEmpty())) { // FIXME handle some explicitly? @@ -52,8 +53,16 @@ static std::pair prehandleHeaderAndBody(const QByteAr result.error = QLatin1String("(%1)").arg(statusStr); else result.error = QLatin1String("%1 (%2)").arg(QString::fromUtf8(body)).arg(statusStr); - return {result, {}}; } + return result; +} + +static std::pair prehandleHeaderAndBody(const QByteArray &header, + const QByteArray &body) +{ + BaseResult result = prehandleHeader(header, body); + if (!result.error.isEmpty()) + return {result, {}}; QJsonParseError error; const QJsonDocument doc = QJsonDocument::fromJson(body, &error); @@ -264,6 +273,65 @@ ProjectInfo parseProjectInfo(const QByteArray &input) return result; } +static QRegularExpression issueCsvLineRegex(const QByteArray &firstCsvLine) +{ + QString pattern = "^"; + for (const QByteArray &part : firstCsvLine.split(',')) { + const QString cleaned = QString::fromUtf8(part).remove(' ').chopped(1).mid(1); + pattern.append(QString("\"(?<" + cleaned + ">.*)\",")); + } + pattern.chop(1); // remove last comma + pattern.append('$'); + const QRegularExpression regex(pattern); + QTC_ASSERT(regex.isValid(), return {}); + return regex; +} + +static void parseCsvIssue(const QByteArray &csv, QList *issues) +{ + QTC_ASSERT(issues, return); + + bool first = true; + std::optional regex; + for (auto &line : csv.split('\n')) { + if (first) { + regex.emplace(issueCsvLineRegex(line)); + first = false; + if (regex.value().pattern().isEmpty()) + return; + continue; + } + if (line.isEmpty()) + continue; + const QRegularExpressionMatch match = regex->match(QString::fromUtf8(line)); + QTC_ASSERT(match.hasMatch(), continue); + // FIXME: some of these are not present for all issue kinds! Limited to SV for now + ShortIssue issue; + issue.state = match.captured("State"); + issue.errorNumber = match.captured("ErrorNumber"); + issue.message = match.captured("Message"); + issue.entity = match.captured("Entity"); + issue.filePath = match.captured("Path"); + issue.severity = match.captured("Severity"); + issue.lineNumber = match.captured("Line").toInt(); + issues->append(issue); + } +} + +IssuesList parseIssuesList(const QByteArray &input) +{ + IssuesList result; + + auto [header, body] = splitHeaderAndBody(input); + BaseResult headerResult = prehandleHeader(header, body); + if (!headerResult.error.isEmpty()) { + result.error = headerResult.error; + return result; + } + parseCsvIssue(body, &result.issues); + return result; +} + } // ResultParser } // Axivion::Internal diff --git a/plugins/axivion/axivionresultparser.h b/plugins/axivion/axivionresultparser.h index 9a308f9950e..b187a23afaf 100644 --- a/plugins/axivion/axivionresultparser.h +++ b/plugins/axivion/axivionresultparser.h @@ -70,10 +70,29 @@ public: QList issueKinds; }; +class ShortIssue : public BaseResult +{ +public: + QString state; + QString errorNumber; + QString message; + QString entity; + QString filePath; + QString severity; + int lineNumber = 0; +}; + +class IssuesList : public BaseResult +{ +public: + QList issues; +}; + namespace ResultParser { DashboardInfo parseDashboardInfo(const QByteArray &input); ProjectInfo parseProjectInfo(const QByteArray &input); +IssuesList parseIssuesList(const QByteArray &input); } // ResultParser From fff125db97a95116699599d5ca3686fab9116d36 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 16 Dec 2022 15:12:39 +0100 Subject: [PATCH 15/38] Handle opened documents when ProjectInfo is update When we receive a new project info we should update issues for documents that are opened already. As we do this only for files that are known to the current project we may need to postpone this until the project has been parsed for the first time. Change-Id: I4241efa9f8a51c1d79fa91e7265bdf359e3d5826 Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 81accb47c58..cc17006976f 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -11,10 +11,12 @@ #include "axivionsettingspage.h" #include "axiviontr.h" +#include #include #include #include #include +#include #include #include #include @@ -37,6 +39,7 @@ class AxivionPluginPrivate : public QObject public: void fetchProjectInfo(const QString &projectName); void handleProjectInfo(const ProjectInfo &info); + void handleOpenedDocs(ProjectExplorer::Project *project); void onDocumentOpened(Core::IDocument *doc); void onDocumentClosed(Core::IDocument * doc); void handleIssuesForFile(const IssuesList &issues); @@ -188,6 +191,19 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) runner->start(); } +void AxivionPluginPrivate::handleOpenedDocs(ProjectExplorer::Project *project) +{ + if (project && ProjectExplorer::SessionManager::startupProject() != project) + return; + const QList openDocuments = Core::DocumentModel::openedDocuments(); + for (Core::IDocument *doc : openDocuments) + onDocumentOpened(doc); + if (project) + disconnect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::projectFinishedParsing, + this, &AxivionPluginPrivate::handleOpenedDocs); +} + void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) { runningQuery = false; @@ -201,7 +217,15 @@ void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) if (currentProjectInfo.name.isEmpty()) return; - // FIXME handle already opened documents + + // handle already opened documents + if (!ProjectExplorer::SessionManager::startupBuildSystem()->isParsing()) { + handleOpenedDocs(nullptr); + } else { + connect(ProjectExplorer::SessionManager::instance(), + &ProjectExplorer::SessionManager::projectFinishedParsing, + this, &AxivionPluginPrivate::handleOpenedDocs); + } } void AxivionPluginPrivate::onDocumentOpened(Core::IDocument *doc) From 02b094fc97ad01baab9388a01e1613532501dbd0 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 16 Dec 2022 22:34:56 +0100 Subject: [PATCH 16/38] Clear existing marks When unlinking a project or if the current startup project changes remove all existing marks to avoid showing outdated marks. Change-Id: I6578a0a145222191f5ec4228e9aeef924f70edf5 Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index cc17006976f..9d4c3ff648b 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -42,6 +42,7 @@ public: void handleOpenedDocs(ProjectExplorer::Project *project); void onDocumentOpened(Core::IDocument *doc); void onDocumentClosed(Core::IDocument * doc); + void clearAllMarks(); void handleIssuesForFile(const IssuesList &issues); AxivionSettings axivionSettings; @@ -113,6 +114,7 @@ void AxivionPlugin::onStartupProjectChanged() QTC_ASSERT(dd, return); ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); if (!project) { + dd->clearAllMarks(); dd->currentProjectInfo = ProjectInfo(); dd->axivionOutputPane.updateDashboard(); return; @@ -175,6 +177,7 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) QTimer::singleShot(3000, [this, projectName]{ fetchProjectInfo(projectName); }); return; } + clearAllMarks(); if (projectName.isEmpty()) { currentProjectInfo = ProjectInfo(); axivionOutputPane.updateDashboard(); @@ -204,6 +207,13 @@ void AxivionPluginPrivate::handleOpenedDocs(ProjectExplorer::Project *project) this, &AxivionPluginPrivate::handleOpenedDocs); } +void AxivionPluginPrivate::clearAllMarks() +{ + const QList openDocuments = Core::DocumentModel::openedDocuments(); + for (Core::IDocument *doc : openDocuments) + onDocumentClosed(doc); +} + void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) { runningQuery = false; From cef8339785a20f31af96f0973b7d6f4ca62607d4 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 16 Dec 2022 23:01:01 +0100 Subject: [PATCH 17/38] Move function into plugin private Change-Id: Ia69c39cf4dccefc5d712153628aaaeae3a075c5e Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 54 +++++++++++++++++-------------- plugins/axivion/axivionplugin.h | 1 - 2 files changed, 30 insertions(+), 25 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 9d4c3ff648b..0d7496729c3 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -37,6 +37,8 @@ namespace Axivion::Internal { class AxivionPluginPrivate : public QObject { public: + AxivionProjectSettings *projectSettings(ProjectExplorer::Project *project); + void onStartupProjectChanged(); void fetchProjectInfo(const QString &projectName); void handleProjectInfo(const ProjectInfo &info); void handleOpenedDocs(ProjectExplorer::Project *project); @@ -48,7 +50,7 @@ public: AxivionSettings axivionSettings; AxivionSettingsPage axivionSettingsPage{&axivionSettings}; AxivionOutputPane axivionOutputPane; - QHash projectSettings; + QHash axivionProjectSettings; ProjectInfo currentProjectInfo; bool runningQuery = false; }; @@ -63,9 +65,9 @@ AxivionPlugin::AxivionPlugin() AxivionPlugin::~AxivionPlugin() { - if (!dd->projectSettings.isEmpty()) { - qDeleteAll(dd->projectSettings); - dd->projectSettings.clear(); + if (!dd->axivionProjectSettings.isEmpty()) { + qDeleteAll(dd->axivionProjectSettings); + dd->axivionProjectSettings.clear(); } delete dd; dd = nullptr; @@ -101,7 +103,7 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); connect(ProjectExplorer::SessionManager::instance(), &ProjectExplorer::SessionManager::startupProjectChanged, - this, &AxivionPlugin::onStartupProjectChanged); + dd, &AxivionPluginPrivate::onStartupProjectChanged); connect(Core::EditorManager::instance(), &Core::EditorManager::documentOpened, dd, &AxivionPluginPrivate::onDocumentOpened); connect(Core::EditorManager::instance(), &Core::EditorManager::documentClosed, @@ -109,21 +111,6 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa return true; } -void AxivionPlugin::onStartupProjectChanged() -{ - QTC_ASSERT(dd, return); - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); - if (!project) { - dd->clearAllMarks(); - dd->currentProjectInfo = ProjectInfo(); - dd->axivionOutputPane.updateDashboard(); - return; - } - - const AxivionProjectSettings *projSettings = projectSettings(project); - dd->fetchProjectInfo(projSettings->dashboardProjectName()); -} - AxivionSettings *AxivionPlugin::settings() { QTC_ASSERT(dd, return nullptr); @@ -135,10 +122,7 @@ AxivionProjectSettings *AxivionPlugin::projectSettings(ProjectExplorer::Project QTC_ASSERT(project, return nullptr); QTC_ASSERT(dd, return nullptr); - auto &settings = dd->projectSettings[project]; - if (!settings) - settings = new AxivionProjectSettings(project); - return settings; + return dd->projectSettings(project); } bool AxivionPlugin::handleCertificateIssue() @@ -171,6 +155,28 @@ ProjectInfo AxivionPlugin::projectInfo() return dd->currentProjectInfo; } +AxivionProjectSettings *AxivionPluginPrivate::projectSettings(ProjectExplorer::Project *project) +{ + auto &settings = axivionProjectSettings[project]; + if (!settings) + settings = new AxivionProjectSettings(project); + return settings; +} + +void AxivionPluginPrivate::onStartupProjectChanged() +{ + ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + if (!project) { + clearAllMarks(); + currentProjectInfo = ProjectInfo(); + axivionOutputPane.updateDashboard(); + return; + } + + const AxivionProjectSettings *projSettings = projectSettings(project); + fetchProjectInfo(projSettings->dashboardProjectName()); +} + void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) { if (runningQuery) { // re-schedule diff --git a/plugins/axivion/axivionplugin.h b/plugins/axivion/axivionplugin.h index 86f23ee5923..1cd33d0e99b 100644 --- a/plugins/axivion/axivionplugin.h +++ b/plugins/axivion/axivionplugin.h @@ -35,7 +35,6 @@ signals: private: bool initialize(const QStringList &arguments, QString *errorMessage) final; void extensionsInitialized() final {} - void onStartupProjectChanged(); }; } // Axivion::Internal From ac532cb324aa8649b667dc140a6f1e5308f01d36 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Thu, 5 Jan 2023 10:08:15 +0100 Subject: [PATCH 18/38] Server config dialog button "Modify" -> "Ok" Change-Id: Ia0cd0e54de573ac408309caa9721ffbc33b0816f Reviewed-by: David Schulz Reviewed-by: Christian Stenger --- plugins/axivion/axivionsettingspage.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index bd0ddee04c9..bcbced865c9 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -173,13 +173,13 @@ void AxivionSettingsWidget::showEditServerDialog() DashboardWidget *dashboardWidget = new DashboardWidget(DashboardWidget::Edit, this); dashboardWidget->setDashboardServer(old); layout->addWidget(dashboardWidget); - auto buttons = new QDialogButtonBox(QDialogButtonBox::Cancel, this); - auto modify = buttons->addButton(Tr::tr("Modify"), QDialogButtonBox::AcceptRole); - modify->setEnabled(m_dashboardDisplay->isValid()); + auto buttons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok, this); + auto ok = buttons->button(QDialogButtonBox::Ok); + ok->setEnabled(m_dashboardDisplay->isValid()); connect(buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, &d, &QDialog::reject); - connect(modify, &QPushButton::clicked, &d, &QDialog::accept); + connect(ok, &QPushButton::clicked, &d, &QDialog::accept); connect(dashboardWidget, &DashboardWidget::validChanged, - modify, &QPushButton::setEnabled); + ok, &QPushButton::setEnabled); layout->addWidget(buttons); d.setLayout(layout); d.resize(500, 200); From 76212ed1321fdd4b73b75f54e2a5405c7f5aea5c Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Fri, 23 Dec 2022 14:26:26 +0100 Subject: [PATCH 19/38] Build: Use version-less Qt targets Since we do not support Qt < 5.15 anymore. Change-Id: I2585427f4095ffc8507f5de63b6866e1a308b3dd Reviewed-by: Christian Stenger --- plugins/axivion/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index f904cf308f9..594740d8fc3 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -10,7 +10,7 @@ add_qtc_plugin(Axivion PLUGIN_DEPENDS QtCreator::Core QtCreator::ProjectExplorer QtCreator::TextEditor ${LICENSECHECKER_DEPENDS} - DEPENDS Qt5::Network Qt5::Widgets QtCreator::ExtensionSystem QtCreator::Utils + DEPENDS Qt::Network Qt::Widgets QtCreator::ExtensionSystem QtCreator::Utils SOURCES axivion.qrc axivionoutputpane.cpp axivionoutputpane.h From 633e1bb73100fd6dc532222409987772112cdcca Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 6 Jan 2023 15:51:59 +0100 Subject: [PATCH 20/38] Make line annotations more descriptive Change-Id: I7c8936cebbf944640af90c1b19f7b9294c0edbed Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 0d7496729c3..c06bf1d40c3 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -297,9 +297,11 @@ void AxivionPluginPrivate::handleIssuesForFile(const IssuesList &issues) // 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 auto mark = new TextEditor::TextMark(filePath, issue.lineNumber, axivionId); - mark->setToolTip(issue.errorNumber + " " + issue.entity + ": " + issue.message); + const QString markText = issue.entity.isEmpty() ? issue.message + : issue.entity + ": " + issue.message; + mark->setToolTip(issue.errorNumber + " " + markText); mark->setPriority(TextEditor::TextMark::NormalPriority); - mark->setLineAnnotation(issue.errorNumber); + mark->setLineAnnotation(markText); } } From 22df847631158ccc01d9a98ba0d45f33bd005843 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 9 Jan 2023 07:31:50 +0100 Subject: [PATCH 21/38] Use static variable for text mark id Change-Id: I4a928f14d8e1efc34b70d92a4f71d354c02c7fb7 Reviewed-by: Christian Stenger --- plugins/axivion/axivionplugin.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index c06bf1d40c3..bb2284e1532 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -32,6 +32,8 @@ #include #include +constexpr char AxivionTextMarkId[] = "AxivionTextMark"; + namespace Axivion::Internal { class AxivionPluginPrivate : public QObject @@ -272,9 +274,8 @@ void AxivionPluginPrivate::onDocumentClosed(Core::IDocument *doc) return; const TextEditor::TextMarks marks = document->marks(); - auto axivionId = Utils::Id("AxivionTextMark"); for (auto m : marks) { - if (m->category() == axivionId) + if (m->category() == AxivionTextMarkId) delete m; } } @@ -291,7 +292,7 @@ void AxivionPluginPrivate::handleIssuesForFile(const IssuesList &issues) const Utils::FilePath filePath = project->projectDirectory() .pathAppended(issues.issues.first().filePath); - auto axivionId = Utils::Id("AxivionTextMark"); + const Utils::Id axivionId(AxivionTextMarkId); 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 From 96bbd32edfba97999f64523f741c85c95910e2c1 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 9 Jan 2023 07:41:22 +0100 Subject: [PATCH 22/38] Use common member style Change-Id: I9a71c4906a56ae65f21bc271220c783d8056e748 Reviewed-by: Christian Stenger --- plugins/axivion/axivionplugin.cpp | 54 +++++++++++++++---------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index bb2284e1532..a12f4a010cf 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -49,12 +49,12 @@ public: void clearAllMarks(); void handleIssuesForFile(const IssuesList &issues); - AxivionSettings axivionSettings; - AxivionSettingsPage axivionSettingsPage{&axivionSettings}; - AxivionOutputPane axivionOutputPane; - QHash axivionProjectSettings; - ProjectInfo currentProjectInfo; - bool runningQuery = false; + AxivionSettings m_axivionSettings; + AxivionSettingsPage m_axivionSettingsPage{&m_axivionSettings}; + AxivionOutputPane m_axivionOutputPane; + QHash m_axivionProjectSettings; + ProjectInfo m_currentProjectInfo; + bool m_runningQuery = false; }; static AxivionPlugin *s_instance = nullptr; @@ -67,9 +67,9 @@ AxivionPlugin::AxivionPlugin() AxivionPlugin::~AxivionPlugin() { - if (!dd->axivionProjectSettings.isEmpty()) { - qDeleteAll(dd->axivionProjectSettings); - dd->axivionProjectSettings.clear(); + if (!dd->m_axivionProjectSettings.isEmpty()) { + qDeleteAll(dd->m_axivionProjectSettings); + dd->m_axivionProjectSettings.clear(); } delete dd; dd = nullptr; @@ -94,7 +94,7 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa #endif // LICENSECHECKER dd = new AxivionPluginPrivate; - dd->axivionSettings.fromSettings(Core::ICore::settings()); + dd->m_axivionSettings.fromSettings(Core::ICore::settings()); auto panelFactory = new ProjectExplorer::ProjectPanelFactory; panelFactory->setPriority(250); @@ -116,7 +116,7 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa AxivionSettings *AxivionPlugin::settings() { QTC_ASSERT(dd, return nullptr); - return &dd->axivionSettings; + return &dd->m_axivionSettings; } AxivionProjectSettings *AxivionPlugin::projectSettings(ProjectExplorer::Project *project) @@ -131,7 +131,7 @@ bool AxivionPlugin::handleCertificateIssue() { QTC_ASSERT(dd, return false); - const QString serverHost = QUrl(dd->axivionSettings.server.dashboard).host(); + const QString serverHost = QUrl(dd->m_axivionSettings.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" @@ -140,7 +140,7 @@ bool AxivionPlugin::handleCertificateIssue() != QMessageBox::Yes) { return false; } - dd->axivionSettings.server.validateCert = false; + dd->m_axivionSettings.server.validateCert = false; emit s_instance->settingsChanged(); return true; } @@ -154,12 +154,12 @@ void AxivionPlugin::fetchProjectInfo(const QString &projectName) ProjectInfo AxivionPlugin::projectInfo() { QTC_ASSERT(dd, return {}); - return dd->currentProjectInfo; + return dd->m_currentProjectInfo; } AxivionProjectSettings *AxivionPluginPrivate::projectSettings(ProjectExplorer::Project *project) { - auto &settings = axivionProjectSettings[project]; + auto &settings = m_axivionProjectSettings[project]; if (!settings) settings = new AxivionProjectSettings(project); return settings; @@ -170,8 +170,8 @@ void AxivionPluginPrivate::onStartupProjectChanged() ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); if (!project) { clearAllMarks(); - currentProjectInfo = ProjectInfo(); - axivionOutputPane.updateDashboard(); + m_currentProjectInfo = ProjectInfo(); + m_axivionOutputPane.updateDashboard(); return; } @@ -181,17 +181,17 @@ void AxivionPluginPrivate::onStartupProjectChanged() void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) { - if (runningQuery) { // re-schedule + if (m_runningQuery) { // re-schedule QTimer::singleShot(3000, [this, projectName]{ fetchProjectInfo(projectName); }); return; } clearAllMarks(); if (projectName.isEmpty()) { - currentProjectInfo = ProjectInfo(); - axivionOutputPane.updateDashboard(); + m_currentProjectInfo = ProjectInfo(); + m_axivionOutputPane.updateDashboard(); return; } - runningQuery = true; + m_runningQuery = true; AxivionQuery query(AxivionQuery::ProjectInfo, {projectName}); AxivionQueryRunner *runner = new AxivionQueryRunner(query, this); @@ -224,16 +224,16 @@ void AxivionPluginPrivate::clearAllMarks() void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) { - runningQuery = false; + m_runningQuery = false; if (!info.error.isEmpty()) { Core::MessageManager::writeFlashing("Axivion: " + info.error); return; } - currentProjectInfo = info; - axivionOutputPane.updateDashboard(); + m_currentProjectInfo = info; + m_axivionOutputPane.updateDashboard(); - if (currentProjectInfo.name.isEmpty()) + if (m_currentProjectInfo.name.isEmpty()) return; // handle already opened documents @@ -248,7 +248,7 @@ void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) void AxivionPluginPrivate::onDocumentOpened(Core::IDocument *doc) { - if (currentProjectInfo.name.isEmpty()) // we do not have a project info (yet) + if (m_currentProjectInfo.name.isEmpty()) // we do not have a project info (yet) return; ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); @@ -257,7 +257,7 @@ void AxivionPluginPrivate::onDocumentOpened(Core::IDocument *doc) Utils::FilePath relative = doc->filePath().relativeChildPath(project->projectDirectory()); // for now only style violations - AxivionQuery query(AxivionQuery::IssuesForFileList, {currentProjectInfo.name, "SV", + AxivionQuery query(AxivionQuery::IssuesForFileList, {m_currentProjectInfo.name, "SV", relative.path() } ); AxivionQueryRunner *runner = new AxivionQueryRunner(query, this); connect(runner, &AxivionQueryRunner::resultRetrieved, this, [this](const QByteArray &result){ From f994d27bf5efd33ffdc89e707d75aa9e331a7b64 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 11 Jan 2023 10:04:24 +0100 Subject: [PATCH 23/38] Adapt to upstream change Change-Id: Ib86208aa4209580854b98971e436a521020211f6 Reviewed-by: hjk --- plugins/axivion/axivionquery.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp index 4fa49bf75a3..090b5c7194a 100644 --- a/plugins/axivion/axivionquery.cpp +++ b/plugins/axivion/axivionquery.cpp @@ -75,9 +75,9 @@ AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *paren start(); return; } - emit resultRetrieved(m_process.readAllStandardError()); + emit resultRetrieved(m_process.readAllRawStandardError()); } else { - emit resultRetrieved(m_process.readAllStandardOutput()); + emit resultRetrieved(m_process.readAllRawStandardOutput()); } emit finished(); }); From 6221871b2f0feb7bb66aa6a229d1bbe81b95946c Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 12 Jan 2023 09:45:41 +0100 Subject: [PATCH 24/38] Rename one of the DashboardWidgets This is confusing on and even led to crashes on macOS. Change-Id: I4227a091f2b2ac90405494a1a8b206c4ea672030 Reviewed-by: David Schulz --- plugins/axivion/axivionsettingspage.cpp | 16 ++++++++-------- plugins/axivion/axivionsettingspage.h | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index bcbced865c9..57c258c7e08 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -46,7 +46,7 @@ static bool isUrlValid(const QString &in) return hostValid(url.host()) && url.scheme() == "https" || url.scheme() == "http"; } -DashboardWidget::DashboardWidget(Mode mode, QWidget *parent) +DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent) : QWidget(parent) , m_mode(mode) { @@ -91,7 +91,7 @@ DashboardWidget::DashboardWidget(Mode mode, QWidget *parent) } } -AxivionServer DashboardWidget::dashboardServer() const +AxivionServer DashboardSettingsWidget::dashboardServer() const { AxivionServer result; if (m_id.isValid()) @@ -104,7 +104,7 @@ AxivionServer DashboardWidget::dashboardServer() const return result; } -void DashboardWidget::setDashboardServer(const AxivionServer &server) +void DashboardSettingsWidget::setDashboardServer(const AxivionServer &server) { m_id = server.id; m_dashboardUrl.setValue(server.dashboard); @@ -112,7 +112,7 @@ void DashboardWidget::setDashboardServer(const AxivionServer &server) m_token.setValue(server.token); } -bool DashboardWidget::isValid() const +bool DashboardSettingsWidget::isValid() const { return !m_token.value().isEmpty() && !m_description.value().isEmpty() && isUrlValid(m_dashboardUrl.value()); @@ -130,7 +130,7 @@ private: AxivionSettings *m_settings; Utils::StringAspect m_curlPC; - DashboardWidget *m_dashboardDisplay = nullptr; + DashboardSettingsWidget *m_dashboardDisplay = nullptr; QPushButton *m_edit = nullptr; }; @@ -139,7 +139,7 @@ AxivionSettingsWidget::AxivionSettingsWidget(AxivionSettings *settings) { using namespace Layouting; - m_dashboardDisplay = new DashboardWidget(DashboardWidget::Display, this); + m_dashboardDisplay = new DashboardSettingsWidget(DashboardSettingsWidget::Display, this); m_dashboardDisplay->setDashboardServer(m_settings->server); m_edit = new QPushButton(Tr::tr("Edit..."), this); m_curlPC.setLabelText(Tr::tr("curl:")); @@ -170,7 +170,7 @@ void AxivionSettingsWidget::showEditServerDialog() QDialog d; d.setWindowTitle(Tr::tr("Edit Dashboard Configuration")); QVBoxLayout *layout = new QVBoxLayout; - DashboardWidget *dashboardWidget = new DashboardWidget(DashboardWidget::Edit, this); + DashboardSettingsWidget *dashboardWidget = new DashboardSettingsWidget(DashboardSettingsWidget::Edit, this); dashboardWidget->setDashboardServer(old); layout->addWidget(dashboardWidget); auto buttons = new QDialogButtonBox(QDialogButtonBox::Cancel | QDialogButtonBox::Ok, this); @@ -178,7 +178,7 @@ void AxivionSettingsWidget::showEditServerDialog() ok->setEnabled(m_dashboardDisplay->isValid()); connect(buttons->button(QDialogButtonBox::Cancel), &QPushButton::clicked, &d, &QDialog::reject); connect(ok, &QPushButton::clicked, &d, &QDialog::accept); - connect(dashboardWidget, &DashboardWidget::validChanged, + connect(dashboardWidget, &DashboardSettingsWidget::validChanged, ok, &QPushButton::setEnabled); layout->addWidget(buttons); d.setLayout(layout); diff --git a/plugins/axivion/axivionsettingspage.h b/plugins/axivion/axivionsettingspage.h index 02cfb81ffa9..5d1fc9c8b8d 100644 --- a/plugins/axivion/axivionsettingspage.h +++ b/plugins/axivion/axivionsettingspage.h @@ -16,12 +16,12 @@ class AxivionServer; class AxivionSettings; class AxivionSettingsWidget; -class DashboardWidget : public QWidget +class DashboardSettingsWidget : public QWidget { Q_OBJECT public: enum Mode { Display, Edit }; - explicit DashboardWidget(Mode m = Display, QWidget *parent = nullptr); + explicit DashboardSettingsWidget(Mode m = Display, QWidget *parent = nullptr); AxivionServer dashboardServer() const; void setDashboardServer(const AxivionServer &server); From 0056df7584ab272b53ddc872f19e47054ba27aad Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 12 Jan 2023 09:52:24 +0100 Subject: [PATCH 25/38] Fix possible nullptr access Change-Id: I89555a9ac6cd06f7c902893f40e1e3757b14f971 Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index a12f4a010cf..bc2f6bed1a7 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -237,7 +237,8 @@ void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) return; // handle already opened documents - if (!ProjectExplorer::SessionManager::startupBuildSystem()->isParsing()) { + if (auto buildSystem = ProjectExplorer::SessionManager::startupBuildSystem(); + !buildSystem || !buildSystem->isParsing()) { handleOpenedDocs(nullptr); } else { connect(ProjectExplorer::SessionManager::instance(), From 2dc03f41d0adb9ee7277130c1df7625291b7e5d7 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Wed, 11 Jan 2023 14:44:27 +0100 Subject: [PATCH 26/38] Make dashboard widget scrollable Change-Id: I81a58f52edeaec150d7210b3154d055e4751784e Reviewed-by: David Schulz --- plugins/axivion/axivionoutputpane.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp index b1b4ec98a1b..c48326863f4 100644 --- a/plugins/axivion/axivionoutputpane.cpp +++ b/plugins/axivion/axivionoutputpane.cpp @@ -11,11 +11,12 @@ #include #include +#include #include namespace Axivion::Internal { -class DashboardWidget : public QWidget +class DashboardWidget : public QScrollArea { public: explicit DashboardWidget(QWidget *parent = nullptr); @@ -28,9 +29,10 @@ private: }; DashboardWidget::DashboardWidget(QWidget *parent) - : QWidget(parent) + : QScrollArea(parent) { - QVBoxLayout *layout = new QVBoxLayout(this); + QWidget *widget = new QWidget(this); + QVBoxLayout *layout = new QVBoxLayout(widget); QFormLayout *projectLayout = new QFormLayout; m_project = new QLabel(this); projectLayout->addRow(Tr::tr("Project:"), m_project); @@ -39,6 +41,9 @@ DashboardWidget::DashboardWidget(QWidget *parent) layout->addLayout(projectLayout); m_formLayout = new QFormLayout; layout->addLayout(m_formLayout); + setWidget(widget); + setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); + setWidgetResizable(true); } void DashboardWidget::updateUi() From becd66a4fc6030cc7c21050fa3e26a54aad6cf03 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Thu, 12 Jan 2023 12:01:51 +0100 Subject: [PATCH 27/38] Adapt to upstream change Change-Id: Ibfa287e1df09d3984b572569bd3fdfa9f2fd9497 Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index bc2f6bed1a7..ced5d37597c 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -276,7 +276,7 @@ void AxivionPluginPrivate::onDocumentClosed(Core::IDocument *doc) const TextEditor::TextMarks marks = document->marks(); for (auto m : marks) { - if (m->category() == AxivionTextMarkId) + if (m->category().id == AxivionTextMarkId) delete m; } } @@ -298,7 +298,8 @@ void AxivionPluginPrivate::handleIssuesForFile(const IssuesList &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 - auto mark = new TextEditor::TextMark(filePath, issue.lineNumber, axivionId); + auto mark = new TextEditor::TextMark(filePath, issue.lineNumber, + {Tr::tr("Axivion"), axivionId}); const QString markText = issue.entity.isEmpty() ? issue.message : issue.entity + ": " + issue.message; mark->setToolTip(issue.errorNumber + " " + markText); From 4b3f5a04e2a9b96a71ba6f24a88e998804e0ff45 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Fri, 13 Jan 2023 13:43:07 +0100 Subject: [PATCH 28/38] Fix operator precedence problem Change-Id: Id3af6e4a88cba97072053b28d8b7a7f65f76f91c Reviewed-by: Christian Stenger --- plugins/axivion/axivionsettingspage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index 57c258c7e08..cb144371d9e 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -43,7 +43,7 @@ static bool hostValid(const QString &host) static bool isUrlValid(const QString &in) { const QUrl url(in); - return hostValid(url.host()) && url.scheme() == "https" || url.scheme() == "http"; + return hostValid(url.host()) && (url.scheme() == "https" || url.scheme() == "http"); } DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent) From 134b71a45a14dfb4e3c1d9bd47ac59bf836b5f4d Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 13 Jan 2023 13:49:40 +0100 Subject: [PATCH 29/38] Extract text mark functionality into own class Enhance issue information by id of the issue to be able to retrieve further details later. Change-Id: Ia6ff5c8a0064c45b50f9c712a05f6271f356e59a Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 28 ++++++++++++++++++------- plugins/axivion/axivionresultparser.cpp | 1 + plugins/axivion/axivionresultparser.h | 1 + 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index ced5d37597c..c431af66e7a 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -60,6 +60,26 @@ public: static AxivionPlugin *s_instance = nullptr; static AxivionPluginPrivate *dd = nullptr; +class AxivionTextMark : public TextEditor::TextMark +{ +public: + AxivionTextMark(const Utils::FilePath &filePath, const ShortIssue &issue); + +private: + QString m_id; +}; + +AxivionTextMark::AxivionTextMark(const Utils::FilePath &filePath, const ShortIssue &issue) + : 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); +} + AxivionPlugin::AxivionPlugin() { s_instance = this; @@ -298,13 +318,7 @@ void AxivionPluginPrivate::handleIssuesForFile(const IssuesList &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 - auto mark = new TextEditor::TextMark(filePath, issue.lineNumber, - {Tr::tr("Axivion"), axivionId}); - const QString markText = issue.entity.isEmpty() ? issue.message - : issue.entity + ": " + issue.message; - mark->setToolTip(issue.errorNumber + " " + markText); - mark->setPriority(TextEditor::TextMark::NormalPriority); - mark->setLineAnnotation(markText); + new AxivionTextMark(filePath, issue); } } diff --git a/plugins/axivion/axivionresultparser.cpp b/plugins/axivion/axivionresultparser.cpp index 9c7da845883..e2b9713f576 100644 --- a/plugins/axivion/axivionresultparser.cpp +++ b/plugins/axivion/axivionresultparser.cpp @@ -307,6 +307,7 @@ static void parseCsvIssue(const QByteArray &csv, QList *issues) QTC_ASSERT(match.hasMatch(), continue); // FIXME: some of these are not present for all issue kinds! Limited to SV for now ShortIssue issue; + issue.id = match.captured("Id"); issue.state = match.captured("State"); issue.errorNumber = match.captured("ErrorNumber"); issue.message = match.captured("Message"); diff --git a/plugins/axivion/axivionresultparser.h b/plugins/axivion/axivionresultparser.h index b187a23afaf..c4b0c376f75 100644 --- a/plugins/axivion/axivionresultparser.h +++ b/plugins/axivion/axivionresultparser.h @@ -73,6 +73,7 @@ public: class ShortIssue : public BaseResult { public: + QString id; QString state; QString errorNumber; QString message; From 5fb06bdeb9f883b95be66e86561611616411fcb7 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 13 Jan 2023 14:38:39 +0100 Subject: [PATCH 30/38] Add possibility to fetch rule details for issues Allows to fetch further information of an issue and display it inside the output pane. Change-Id: I94ec27b9c060dca9f9523d763b8628a2fce7ca59 Reviewed-by: David Schulz --- plugins/axivion/axivionoutputpane.cpp | 14 +++++++++++ plugins/axivion/axivionoutputpane.h | 1 + plugins/axivion/axivionplugin.cpp | 31 +++++++++++++++++++++++++ plugins/axivion/axivionquery.cpp | 7 +++++- plugins/axivion/axivionquery.h | 2 +- plugins/axivion/axivionresultparser.cpp | 9 +++++++ plugins/axivion/axivionresultparser.h | 1 + 7 files changed, 63 insertions(+), 2 deletions(-) diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp index c48326863f4..0021f03dc40 100644 --- a/plugins/axivion/axivionoutputpane.cpp +++ b/plugins/axivion/axivionoutputpane.cpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace Axivion::Internal { @@ -98,6 +99,8 @@ AxivionOutputPane::AxivionOutputPane(QObject *parent) m_outputWidget = new QStackedWidget; DashboardWidget *dashboardWidget = new DashboardWidget(m_outputWidget); m_outputWidget->addWidget(dashboardWidget); + QTextBrowser *browser = new QTextBrowser(m_outputWidget); + m_outputWidget->addWidget(browser); } AxivionOutputPane::~AxivionOutputPane() @@ -182,4 +185,15 @@ void AxivionOutputPane::updateDashboard() } } +void AxivionOutputPane::updateAndShowRule(const QString &ruleHtml) +{ + if (auto browser = static_cast(m_outputWidget->widget(1))) { + browser->setText(ruleHtml); + if (!ruleHtml.isEmpty()) { + m_outputWidget->setCurrentIndex(1); + popup(Core::IOutputPane::NoModeSwitch); + } + } +} + } // Axivion::Internal diff --git a/plugins/axivion/axivionoutputpane.h b/plugins/axivion/axivionoutputpane.h index 81b1647154c..aea4354e02e 100644 --- a/plugins/axivion/axivionoutputpane.h +++ b/plugins/axivion/axivionoutputpane.h @@ -34,6 +34,7 @@ public: void goToPrev() override; void updateDashboard(); + void updateAndShowRule(const QString &ruleHtml); private: QStackedWidget *m_outputWidget = nullptr; }; diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index c431af66e7a..9f626656437 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -24,11 +24,13 @@ #include #include #include +#include #ifdef LICENSECHECKER # include #endif +#include #include #include @@ -48,6 +50,7 @@ public: void onDocumentClosed(Core::IDocument * doc); void clearAllMarks(); void handleIssuesForFile(const IssuesList &issues); + void fetchRuleInfo(const QString &id); AxivionSettings m_axivionSettings; AxivionSettingsPage m_axivionSettingsPage{&m_axivionSettings}; @@ -78,6 +81,14 @@ AxivionTextMark::AxivionTextMark(const Utils::FilePath &filePath, const ShortIss setToolTip(issue.errorNumber + " " + markText); setPriority(TextEditor::TextMark::NormalPriority); setLineAnnotation(markText); + 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}; + }); } AxivionPlugin::AxivionPlugin() @@ -222,6 +233,26 @@ void AxivionPluginPrivate::fetchProjectInfo(const QString &projectName) runner->start(); } +void AxivionPluginPrivate::fetchRuleInfo(const QString &id) +{ + if (m_runningQuery) { + QTimer::singleShot(3000, [this, id]{ fetchRuleInfo(id); }); + 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(); +} + void AxivionPluginPrivate::handleOpenedDocs(ProjectExplorer::Project *project) { if (project && ProjectExplorer::SessionManager::startupProject() != project) diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp index 090b5c7194a..fbf0ec61936 100644 --- a/plugins/axivion/axivionquery.cpp +++ b/plugins/axivion/axivionquery.cpp @@ -23,7 +23,7 @@ AxivionQuery::AxivionQuery(QueryType type, const QStringList ¶meters) QString AxivionQuery::toString() const { - QString query = "/api"; // common for all + QString query = "/api"; // common for all except RuleInfo switch (m_type) { case NoQuery: return {}; @@ -40,6 +40,11 @@ QString AxivionQuery::toString() const + "/issues?kind=" + m_parameters.at(1) + "&filter_path=" + QUrl::toPercentEncoding(m_parameters.at(2)) + "&format=csv"; return query; + case RuleInfo: + QTC_ASSERT(m_parameters.size() == 2, return {}); + query = "/projects/" + QUrl::toPercentEncoding(m_parameters.first()) + + "/issues/" + m_parameters.at(1) + "/rule"; + return query; } return {}; diff --git a/plugins/axivion/axivionquery.h b/plugins/axivion/axivionquery.h index 6cf5ac07ae3..63b64a52f9b 100644 --- a/plugins/axivion/axivionquery.h +++ b/plugins/axivion/axivionquery.h @@ -12,7 +12,7 @@ namespace Axivion::Internal { class AxivionQuery { public: - enum QueryType {NoQuery, DashboardInfo, ProjectInfo, IssuesForFileList}; + enum QueryType {NoQuery, DashboardInfo, ProjectInfo, IssuesForFileList, RuleInfo}; explicit AxivionQuery(QueryType type, const QStringList ¶meters = {}); QString toString() const; diff --git a/plugins/axivion/axivionresultparser.cpp b/plugins/axivion/axivionresultparser.cpp index e2b9713f576..ba483e8f72e 100644 --- a/plugins/axivion/axivionresultparser.cpp +++ b/plugins/axivion/axivionresultparser.cpp @@ -333,6 +333,15 @@ IssuesList parseIssuesList(const QByteArray &input) return result; } +QString parseRuleInfo(const QByteArray &input) // html result! +{ + auto [header, body] = splitHeaderAndBody(input); + BaseResult headerResult = prehandleHeader(header, body); + if (!headerResult.error.isEmpty()) + return QString(); + return QString::fromLocal8Bit(body); +} + } // ResultParser } // Axivion::Internal diff --git a/plugins/axivion/axivionresultparser.h b/plugins/axivion/axivionresultparser.h index c4b0c376f75..090b05d10af 100644 --- a/plugins/axivion/axivionresultparser.h +++ b/plugins/axivion/axivionresultparser.h @@ -94,6 +94,7 @@ namespace ResultParser { DashboardInfo parseDashboardInfo(const QByteArray &input); ProjectInfo parseProjectInfo(const QByteArray &input); IssuesList parseIssuesList(const QByteArray &input); +QString parseRuleInfo(const QByteArray &input); } // ResultParser From 935d04e9ac173f4c95e7087252a477dab42961e9 Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Fri, 13 Jan 2023 15:43:01 +0100 Subject: [PATCH 31/38] Allow to switch to the main view Change-Id: Idd75b9c161d701898690681bf8141d3a8508ce7a Reviewed-by: David Schulz --- plugins/axivion/axivionoutputpane.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/plugins/axivion/axivionoutputpane.cpp b/plugins/axivion/axivionoutputpane.cpp index 0021f03dc40..5f3f8c16161 100644 --- a/plugins/axivion/axivionoutputpane.cpp +++ b/plugins/axivion/axivionoutputpane.cpp @@ -8,12 +8,14 @@ #include "axiviontr.h" #include +#include #include #include #include #include #include +#include namespace Axivion::Internal { @@ -121,6 +123,14 @@ QWidget *AxivionOutputPane::outputWidget(QWidget *parent) QList AxivionOutputPane::toolBarWidgets() const { QList buttons; + auto showDashboard = new QToolButton(m_outputWidget); + showDashboard->setIcon(Utils::Icons::ONLINE_TOOLBAR.icon()); + showDashboard->setToolTip(Tr::tr("Show dashboard")); + connect(showDashboard, &QToolButton::clicked, this, [this]{ + QTC_ASSERT(m_outputWidget, return); + m_outputWidget->setCurrentIndex(0); + }); + buttons.append(showDashboard); return buttons; } From d208ef3e9ad89a6ce0cc8433aa631a76535ab3da Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 23 Jan 2023 14:10:52 +0100 Subject: [PATCH 32/38] Build: Don't rely on FindQt5.cmake We only support Qt 6 nowadays. Change-Id: Id797467f03afeaaf36f33100461a7163ad27c0fa Reviewed-by: Christian Stenger --- plugins/axivion/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/axivion/CMakeLists.txt b/plugins/axivion/CMakeLists.txt index 594740d8fc3..8f311a885b8 100644 --- a/plugins/axivion/CMakeLists.txt +++ b/plugins/axivion/CMakeLists.txt @@ -1,5 +1,5 @@ find_package(QtCreator COMPONENTS Core REQUIRED) -find_package(Qt5 COMPONENTS Network Widgets REQUIRED) +find_package(Qt6 COMPONENTS Network Widgets REQUIRED) find_package(QtCreatorLicenseChecker QUIET) if (TARGET QtCreator::LicenseChecker) From 9e223c6bde9148edb83198adbddaa92f88cfbec7 Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 1 Mar 2023 17:54:39 +0100 Subject: [PATCH 33/38] Adapt to upstream Session/ProjectManager split Change-Id: Ia41a0985f95d2274219ea24c518341ac4accc3e8 Reviewed-by: Christian Kandeler --- plugins/axivion/axivionplugin.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 9f626656437..253ca34ad2f 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -15,14 +15,18 @@ #include #include #include + #include + #include #include +#include #include -#include + #include #include #include + #include #include @@ -134,8 +138,8 @@ bool AxivionPlugin::initialize(const QStringList &arguments, QString *errorMessa return new AxivionProjectSettingsWidget(project); }); ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); - connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::startupProjectChanged, + connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, dd, &AxivionPluginPrivate::onStartupProjectChanged); connect(Core::EditorManager::instance(), &Core::EditorManager::documentOpened, dd, &AxivionPluginPrivate::onDocumentOpened); @@ -198,7 +202,7 @@ AxivionProjectSettings *AxivionPluginPrivate::projectSettings(ProjectExplorer::P void AxivionPluginPrivate::onStartupProjectChanged() { - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project) { clearAllMarks(); m_currentProjectInfo = ProjectInfo(); @@ -255,14 +259,14 @@ void AxivionPluginPrivate::fetchRuleInfo(const QString &id) void AxivionPluginPrivate::handleOpenedDocs(ProjectExplorer::Project *project) { - if (project && ProjectExplorer::SessionManager::startupProject() != project) + if (project && ProjectExplorer::ProjectManager::startupProject() != project) return; const QList openDocuments = Core::DocumentModel::openedDocuments(); for (Core::IDocument *doc : openDocuments) onDocumentOpened(doc); if (project) - disconnect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::projectFinishedParsing, + disconnect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::projectFinishedParsing, this, &AxivionPluginPrivate::handleOpenedDocs); } @@ -288,12 +292,12 @@ void AxivionPluginPrivate::handleProjectInfo(const ProjectInfo &info) return; // handle already opened documents - if (auto buildSystem = ProjectExplorer::SessionManager::startupBuildSystem(); + if (auto buildSystem = ProjectExplorer::ProjectManager::startupBuildSystem(); !buildSystem || !buildSystem->isParsing()) { handleOpenedDocs(nullptr); } else { - connect(ProjectExplorer::SessionManager::instance(), - &ProjectExplorer::SessionManager::projectFinishedParsing, + connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::projectFinishedParsing, this, &AxivionPluginPrivate::handleOpenedDocs); } } @@ -303,7 +307,7 @@ void AxivionPluginPrivate::onDocumentOpened(Core::IDocument *doc) if (m_currentProjectInfo.name.isEmpty()) // we do not have a project info (yet) return; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!doc || !project->isKnownFile(doc->filePath())) return; @@ -337,7 +341,7 @@ void AxivionPluginPrivate::handleIssuesForFile(const IssuesList &issues) if (issues.issues.isEmpty()) return; - ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject(); + ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); if (!project) return; From 0bffc2bc464a87b7f3a58ef8d249c91d9f5f73b5 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 17:34:01 +0200 Subject: [PATCH 34/38] Adapt to upstream changes Follows 50084f6b0ed78bfee6f5e1d2e56ade9b52b3f2f6 Change-Id: I83a7a9bf491e1b587d26b9058952f23fc0c82f09 Reviewed-by: hjk --- plugins/axivion/axivionsettingspage.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/axivion/axivionsettingspage.cpp b/plugins/axivion/axivionsettingspage.cpp index cb144371d9e..2c55192a995 100644 --- a/plugins/axivion/axivionsettingspage.cpp +++ b/plugins/axivion/axivionsettingspage.cpp @@ -71,11 +71,12 @@ DashboardSettingsWidget::DashboardSettingsWidget(Mode mode, QWidget *parent) Form { m_dashboardUrl, m_description, - m_token + m_token, + mode == Edit ? normalMargin : noMargin } - }.attachTo(this, mode == Edit ? WithMargins : WithoutMargins); + }.attachTo(this); - auto checkValidity = [this](){ + auto checkValidity = [this] { bool old = m_valid; m_valid = isValid(); if (old != m_valid) From 2dbdbaf202b0f0b7f3d7eea2cac48aea44e8e552 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 3 May 2023 17:54:47 +0200 Subject: [PATCH 35/38] Adapt to upstream changes Change-Id: I99ded030d0382ea9c465e1e951d1457d87570389 Reviewed-by: hjk --- plugins/axivion/axivionquery.cpp | 2 +- plugins/axivion/axivionquery.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/axivion/axivionquery.cpp b/plugins/axivion/axivionquery.cpp index fbf0ec61936..8fcb131c87f 100644 --- a/plugins/axivion/axivionquery.cpp +++ b/plugins/axivion/axivionquery.cpp @@ -66,7 +66,7 @@ AxivionQueryRunner::AxivionQueryRunner(const AxivionQuery &query, QObject *paren args << url; m_process.setCommand({settings->curl, args}); - connect(&m_process, &QtcProcess::done, this, [this]{ + connect(&m_process, &Process::done, this, [this]{ if (m_process.result() != ProcessResult::FinishedWithSuccess) { const int exitCode = m_process.exitCode(); if (m_process.exitStatus() == QProcess::NormalExit diff --git a/plugins/axivion/axivionquery.h b/plugins/axivion/axivionquery.h index 63b64a52f9b..d9873a6db44 100644 --- a/plugins/axivion/axivionquery.h +++ b/plugins/axivion/axivionquery.h @@ -3,7 +3,7 @@ #pragma once -#include +#include #include @@ -34,7 +34,7 @@ signals: void resultRetrieved(const QByteArray &json); private: - Utils::QtcProcess m_process; + Utils::Process m_process; }; } // Axivion::Internal From 63522999ee454466449f138a5ddee9ff22abb6fe Mon Sep 17 00:00:00 2001 From: Christian Stenger Date: Mon, 8 May 2023 12:42:40 +0200 Subject: [PATCH 36/38] Avoid crash on close Private may not have been initialized in case QC gets stopped before it could be. Change-Id: I4b6cf6755dd6803834f956e2e125bc1c5f1d929f Reviewed-by: hjk Reviewed-by: David Schulz --- plugins/axivion/axivionplugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/axivion/axivionplugin.cpp b/plugins/axivion/axivionplugin.cpp index 253ca34ad2f..923c0cabb09 100644 --- a/plugins/axivion/axivionplugin.cpp +++ b/plugins/axivion/axivionplugin.cpp @@ -102,7 +102,7 @@ AxivionPlugin::AxivionPlugin() AxivionPlugin::~AxivionPlugin() { - if (!dd->m_axivionProjectSettings.isEmpty()) { + if (dd && !dd->m_axivionProjectSettings.isEmpty()) { qDeleteAll(dd->m_axivionProjectSettings); dd->m_axivionProjectSettings.clear(); } From 76d1973514561d8e0d93e98cfcbc19b266fa4eab Mon Sep 17 00:00:00 2001 From: hjk Date: Wed, 10 May 2023 12:52:09 +0200 Subject: [PATCH 37/38] Adapt to upstream removal of IOptionPage's QObject base Change-Id: Id001ec22478ecb42c0506b4223c497d258c51e18 Reviewed-by: Christian Stenger --- plugins/axivion/axivionsettingspage.h | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/axivion/axivionsettingspage.h b/plugins/axivion/axivionsettingspage.h index 5d1fc9c8b8d..5dd52564800 100644 --- a/plugins/axivion/axivionsettingspage.h +++ b/plugins/axivion/axivionsettingspage.h @@ -42,7 +42,6 @@ private: class AxivionSettingsPage : public Core::IOptionsPage { - Q_OBJECT public: explicit AxivionSettingsPage(AxivionSettings *settings); From af5bb5e599af9ce475d82bbc4e8b91791b5f5f0a Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Tue, 23 May 2023 16:43:48 +0200 Subject: [PATCH 38/38] Adapt for easier merge into main repository Remove conflicting files and already move to the right place Change-Id: I2b20f4aa85e61ff121acb68aaab5d5e1fdd87956 Reviewed-by: Christian Stenger Reviewed-by: hjk --- CMakeLists.txt | 11 ----------- README.md | 7 ------- {plugins => src/plugins}/axivion/Axivion.json.in | 0 {plugins => src/plugins}/axivion/CMakeLists.txt | 0 {plugins => src/plugins}/axivion/axivion.qbs | 0 {plugins => src/plugins}/axivion/axivion.qrc | 0 .../plugins}/axivion/axivionoutputpane.cpp | 0 .../plugins}/axivion/axivionoutputpane.h | 0 {plugins => src/plugins}/axivion/axivionplugin.cpp | 0 {plugins => src/plugins}/axivion/axivionplugin.h | 0 .../plugins}/axivion/axivionprojectsettings.cpp | 0 .../plugins}/axivion/axivionprojectsettings.h | 0 {plugins => src/plugins}/axivion/axivionquery.cpp | 0 {plugins => src/plugins}/axivion/axivionquery.h | 0 .../plugins}/axivion/axivionresultparser.cpp | 0 .../plugins}/axivion/axivionresultparser.h | 0 .../plugins}/axivion/axivionsettings.cpp | 0 {plugins => src/plugins}/axivion/axivionsettings.h | 0 .../plugins}/axivion/axivionsettingspage.cpp | 0 .../plugins}/axivion/axivionsettingspage.h | 0 {plugins => src/plugins}/axivion/axiviontr.h | 0 {plugins => src/plugins}/axivion/images/axivion.png | Bin .../plugins}/axivion/images/axivion@2x.png | Bin 23 files changed, 18 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 README.md rename {plugins => src/plugins}/axivion/Axivion.json.in (100%) rename {plugins => src/plugins}/axivion/CMakeLists.txt (100%) rename {plugins => src/plugins}/axivion/axivion.qbs (100%) rename {plugins => src/plugins}/axivion/axivion.qrc (100%) rename {plugins => src/plugins}/axivion/axivionoutputpane.cpp (100%) rename {plugins => src/plugins}/axivion/axivionoutputpane.h (100%) rename {plugins => src/plugins}/axivion/axivionplugin.cpp (100%) rename {plugins => src/plugins}/axivion/axivionplugin.h (100%) rename {plugins => src/plugins}/axivion/axivionprojectsettings.cpp (100%) rename {plugins => src/plugins}/axivion/axivionprojectsettings.h (100%) rename {plugins => src/plugins}/axivion/axivionquery.cpp (100%) rename {plugins => src/plugins}/axivion/axivionquery.h (100%) rename {plugins => src/plugins}/axivion/axivionresultparser.cpp (100%) rename {plugins => src/plugins}/axivion/axivionresultparser.h (100%) rename {plugins => src/plugins}/axivion/axivionsettings.cpp (100%) rename {plugins => src/plugins}/axivion/axivionsettings.h (100%) rename {plugins => src/plugins}/axivion/axivionsettingspage.cpp (100%) rename {plugins => src/plugins}/axivion/axivionsettingspage.h (100%) rename {plugins => src/plugins}/axivion/axiviontr.h (100%) rename {plugins => src/plugins}/axivion/images/axivion.png (100%) rename {plugins => src/plugins}/axivion/images/axivion@2x.png (100%) diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 7a3dd57ae3c..00000000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -cmake_minimum_required(VERSION 3.16) - -project(Axivion) - -set(CMAKE_AUTOMOC ON) -set(CMAKE_AUTORCC ON) -set(CMAKE_AUTOUIC ON) -set(CMAKE_CXX_STANDARD 17) - -add_subdirectory(plugins/axivion) - diff --git a/README.md b/README.md deleted file mode 100644 index df44f43aeb3..00000000000 --- a/README.md +++ /dev/null @@ -1,7 +0,0 @@ - -# QtCreator/Axivion Integration Plug-in - -This plug-in integrates Axivion Tools handling into Qt Creator. - -This plug-in is only available as part of the commercial Qt offering. - diff --git a/plugins/axivion/Axivion.json.in b/src/plugins/axivion/Axivion.json.in similarity index 100% rename from plugins/axivion/Axivion.json.in rename to src/plugins/axivion/Axivion.json.in diff --git a/plugins/axivion/CMakeLists.txt b/src/plugins/axivion/CMakeLists.txt similarity index 100% rename from plugins/axivion/CMakeLists.txt rename to src/plugins/axivion/CMakeLists.txt diff --git a/plugins/axivion/axivion.qbs b/src/plugins/axivion/axivion.qbs similarity index 100% rename from plugins/axivion/axivion.qbs rename to src/plugins/axivion/axivion.qbs diff --git a/plugins/axivion/axivion.qrc b/src/plugins/axivion/axivion.qrc similarity index 100% rename from plugins/axivion/axivion.qrc rename to src/plugins/axivion/axivion.qrc diff --git a/plugins/axivion/axivionoutputpane.cpp b/src/plugins/axivion/axivionoutputpane.cpp similarity index 100% rename from plugins/axivion/axivionoutputpane.cpp rename to src/plugins/axivion/axivionoutputpane.cpp diff --git a/plugins/axivion/axivionoutputpane.h b/src/plugins/axivion/axivionoutputpane.h similarity index 100% rename from plugins/axivion/axivionoutputpane.h rename to src/plugins/axivion/axivionoutputpane.h diff --git a/plugins/axivion/axivionplugin.cpp b/src/plugins/axivion/axivionplugin.cpp similarity index 100% rename from plugins/axivion/axivionplugin.cpp rename to src/plugins/axivion/axivionplugin.cpp diff --git a/plugins/axivion/axivionplugin.h b/src/plugins/axivion/axivionplugin.h similarity index 100% rename from plugins/axivion/axivionplugin.h rename to src/plugins/axivion/axivionplugin.h diff --git a/plugins/axivion/axivionprojectsettings.cpp b/src/plugins/axivion/axivionprojectsettings.cpp similarity index 100% rename from plugins/axivion/axivionprojectsettings.cpp rename to src/plugins/axivion/axivionprojectsettings.cpp diff --git a/plugins/axivion/axivionprojectsettings.h b/src/plugins/axivion/axivionprojectsettings.h similarity index 100% rename from plugins/axivion/axivionprojectsettings.h rename to src/plugins/axivion/axivionprojectsettings.h diff --git a/plugins/axivion/axivionquery.cpp b/src/plugins/axivion/axivionquery.cpp similarity index 100% rename from plugins/axivion/axivionquery.cpp rename to src/plugins/axivion/axivionquery.cpp diff --git a/plugins/axivion/axivionquery.h b/src/plugins/axivion/axivionquery.h similarity index 100% rename from plugins/axivion/axivionquery.h rename to src/plugins/axivion/axivionquery.h diff --git a/plugins/axivion/axivionresultparser.cpp b/src/plugins/axivion/axivionresultparser.cpp similarity index 100% rename from plugins/axivion/axivionresultparser.cpp rename to src/plugins/axivion/axivionresultparser.cpp diff --git a/plugins/axivion/axivionresultparser.h b/src/plugins/axivion/axivionresultparser.h similarity index 100% rename from plugins/axivion/axivionresultparser.h rename to src/plugins/axivion/axivionresultparser.h diff --git a/plugins/axivion/axivionsettings.cpp b/src/plugins/axivion/axivionsettings.cpp similarity index 100% rename from plugins/axivion/axivionsettings.cpp rename to src/plugins/axivion/axivionsettings.cpp diff --git a/plugins/axivion/axivionsettings.h b/src/plugins/axivion/axivionsettings.h similarity index 100% rename from plugins/axivion/axivionsettings.h rename to src/plugins/axivion/axivionsettings.h diff --git a/plugins/axivion/axivionsettingspage.cpp b/src/plugins/axivion/axivionsettingspage.cpp similarity index 100% rename from plugins/axivion/axivionsettingspage.cpp rename to src/plugins/axivion/axivionsettingspage.cpp diff --git a/plugins/axivion/axivionsettingspage.h b/src/plugins/axivion/axivionsettingspage.h similarity index 100% rename from plugins/axivion/axivionsettingspage.h rename to src/plugins/axivion/axivionsettingspage.h diff --git a/plugins/axivion/axiviontr.h b/src/plugins/axivion/axiviontr.h similarity index 100% rename from plugins/axivion/axiviontr.h rename to src/plugins/axivion/axiviontr.h diff --git a/plugins/axivion/images/axivion.png b/src/plugins/axivion/images/axivion.png similarity index 100% rename from plugins/axivion/images/axivion.png rename to src/plugins/axivion/images/axivion.png diff --git a/plugins/axivion/images/axivion@2x.png b/src/plugins/axivion/images/axivion@2x.png similarity index 100% rename from plugins/axivion/images/axivion@2x.png rename to src/plugins/axivion/images/axivion@2x.png