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