forked from qt-creator/qt-creator
ExtensionSystem: Add Terms & Conditions
Initial implementation of asking the user to accept Terms & Conditions on a per-plugin basis. Change-Id: Idb252efbdc5a2318bf059e35420fa7333b66880a Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
@@ -57,6 +57,8 @@ Q_LOGGING_CATEGORY(pluginLog, "qtc.extensionsystem", QtWarningMsg)
|
|||||||
|
|
||||||
const char C_IGNORED_PLUGINS[] = "Plugins/Ignored";
|
const char C_IGNORED_PLUGINS[] = "Plugins/Ignored";
|
||||||
const char C_FORCEENABLED_PLUGINS[] = "Plugins/ForceEnabled";
|
const char C_FORCEENABLED_PLUGINS[] = "Plugins/ForceEnabled";
|
||||||
|
const char C_TANDCACCEPTED_PLUGINS[] = "Plugins/TermsAndConditionsAccepted";
|
||||||
|
|
||||||
const std::chrono::milliseconds DELAYED_INITIALIZE_INTERVAL{20};
|
const std::chrono::milliseconds DELAYED_INITIALIZE_INTERVAL{20};
|
||||||
|
|
||||||
enum { debugLeaks = 0 };
|
enum { debugLeaks = 0 };
|
||||||
@@ -1051,6 +1053,8 @@ void PluginManagerPrivate::readSettings()
|
|||||||
if (settings) {
|
if (settings) {
|
||||||
disabledPlugins = toLower(settings->value(C_IGNORED_PLUGINS).toStringList());
|
disabledPlugins = toLower(settings->value(C_IGNORED_PLUGINS).toStringList());
|
||||||
forceEnabledPlugins = toLower(settings->value(C_FORCEENABLED_PLUGINS).toStringList());
|
forceEnabledPlugins = toLower(settings->value(C_FORCEENABLED_PLUGINS).toStringList());
|
||||||
|
pluginsWithAcceptedTermsAndConditions
|
||||||
|
= settings->value(C_TANDCACCEPTED_PLUGINS).toStringList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1688,6 +1692,34 @@ PluginSpec *PluginManager::specForPlugin(IPlugin *plugin)
|
|||||||
return findOrDefault(d->pluginSpecs, equal(&PluginSpec::plugin, plugin));
|
return findOrDefault(d->pluginSpecs, equal(&PluginSpec::plugin, plugin));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PluginManagerPrivate::acceptTermsAndConditions(PluginSpec *spec)
|
||||||
|
{
|
||||||
|
if (pluginsWithAcceptedTermsAndConditions.contains(spec->id()))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!acceptTermsAndConditionsCallback) {
|
||||||
|
spec->setError(Tr::tr("No callback set to accept terms and conditions"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!acceptTermsAndConditionsCallback(spec)) {
|
||||||
|
spec->setError(Tr::tr("You did not accept the terms and conditions"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pluginsWithAcceptedTermsAndConditions.append(spec->id());
|
||||||
|
if (settings)
|
||||||
|
settings->setValue(C_TANDCACCEPTED_PLUGINS, pluginsWithAcceptedTermsAndConditions);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PluginManagerPrivate::setAcceptTermsAndConditionsCallback(
|
||||||
|
const std::function<bool(PluginSpec *)> &callback)
|
||||||
|
{
|
||||||
|
acceptTermsAndConditionsCallback = callback;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\internal
|
\internal
|
||||||
*/
|
*/
|
||||||
@@ -1700,6 +1732,13 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
|
|||||||
if (!spec->isEffectivelyEnabled() && destState == PluginSpec::Loaded)
|
if (!spec->isEffectivelyEnabled() && destState == PluginSpec::Loaded)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (spec->termsAndConditions()) {
|
||||||
|
if (!acceptTermsAndConditions(spec)) {
|
||||||
|
spec->setError(Tr::tr("You did not accept the terms and conditions"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<LockFile> lockFile;
|
std::unique_ptr<LockFile> lockFile;
|
||||||
if (enableCrashCheck && destState < PluginSpec::Stopped)
|
if (enableCrashCheck && destState < PluginSpec::Stopped)
|
||||||
lockFile.reset(new LockFile(this, spec));
|
lockFile.reset(new LockFile(this, spec));
|
||||||
@@ -2026,4 +2065,10 @@ void PluginManager::startProfiling()
|
|||||||
d->m_profileElapsedMS = 0;
|
d->m_profileElapsedMS = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PluginManager::setAcceptTermsAndConditionsCallback(
|
||||||
|
const std::function<bool(PluginSpec *)> &callback)
|
||||||
|
{
|
||||||
|
d->setAcceptTermsAndConditionsCallback(callback);
|
||||||
|
}
|
||||||
|
|
||||||
} // ExtensionSystem
|
} // ExtensionSystem
|
||||||
|
@@ -137,6 +137,8 @@ public:
|
|||||||
|
|
||||||
static QString systemInformation();
|
static QString systemInformation();
|
||||||
|
|
||||||
|
void setAcceptTermsAndConditionsCallback(const std::function<bool(PluginSpec *)> &callback);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void objectAdded(QObject *obj);
|
void objectAdded(QObject *obj);
|
||||||
void aboutToRemoveObject(QObject *obj);
|
void aboutToRemoveObject(QObject *obj);
|
||||||
|
@@ -68,6 +68,9 @@ public:
|
|||||||
void readSettings();
|
void readSettings();
|
||||||
void writeSettings();
|
void writeSettings();
|
||||||
|
|
||||||
|
bool acceptTermsAndConditions(PluginSpec *spec);
|
||||||
|
void setAcceptTermsAndConditionsCallback(const std::function<bool(PluginSpec *)> &callback);
|
||||||
|
|
||||||
class TestSpec {
|
class TestSpec {
|
||||||
public:
|
public:
|
||||||
TestSpec(PluginSpec *pluginSpec, const QStringList &testFunctionsOrObjects = QStringList())
|
TestSpec(PluginSpec *pluginSpec, const QStringList &testFunctionsOrObjects = QStringList())
|
||||||
@@ -98,6 +101,7 @@ public:
|
|||||||
QStringList defaultEnabledPlugins; // Plugins/ForceEnabled from install settings
|
QStringList defaultEnabledPlugins; // Plugins/ForceEnabled from install settings
|
||||||
QStringList disabledPlugins;
|
QStringList disabledPlugins;
|
||||||
QStringList forceEnabledPlugins;
|
QStringList forceEnabledPlugins;
|
||||||
|
QStringList pluginsWithAcceptedTermsAndConditions;
|
||||||
// delayed initialization
|
// delayed initialization
|
||||||
QTimer delayedInitializeTimer;
|
QTimer delayedInitializeTimer;
|
||||||
std::queue<PluginSpec *> delayedInitializeQueue;
|
std::queue<PluginSpec *> delayedInitializeQueue;
|
||||||
@@ -115,6 +119,8 @@ public:
|
|||||||
Utils::QtcSettings *settings = nullptr;
|
Utils::QtcSettings *settings = nullptr;
|
||||||
Utils::QtcSettings *globalSettings = nullptr;
|
Utils::QtcSettings *globalSettings = nullptr;
|
||||||
|
|
||||||
|
std::function<bool(PluginSpec *)> acceptTermsAndConditionsCallback;
|
||||||
|
|
||||||
// Look in argument descriptions of the specs for the option.
|
// Look in argument descriptions of the specs for the option.
|
||||||
PluginSpec *pluginForOption(const QString &option, bool *requiresArgument) const;
|
PluginSpec *pluginForOption(const QString &option, bool *requiresArgument) const;
|
||||||
PluginSpec *pluginById(const QString &id) const;
|
PluginSpec *pluginById(const QString &id) const;
|
||||||
|
@@ -202,6 +202,7 @@ public:
|
|||||||
QString copyright;
|
QString copyright;
|
||||||
QStringList arguments;
|
QStringList arguments;
|
||||||
QRegularExpression platformSpecification;
|
QRegularExpression platformSpecification;
|
||||||
|
std::optional<TermsAndConditions> termsAndConditions;
|
||||||
QVector<ExtensionSystem::PluginDependency> dependencies;
|
QVector<ExtensionSystem::PluginDependency> dependencies;
|
||||||
|
|
||||||
PluginSpec::PluginArgumentDescriptions argumentDescriptions;
|
PluginSpec::PluginArgumentDescriptions argumentDescriptions;
|
||||||
@@ -392,6 +393,11 @@ QRegularExpression PluginSpec::platformSpecification() const
|
|||||||
return d->platformSpecification;
|
return d->platformSpecification;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<TermsAndConditions> PluginSpec::termsAndConditions() const
|
||||||
|
{
|
||||||
|
return d->termsAndConditions;
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Returns whether the plugin works on the host platform.
|
Returns whether the plugin works on the host platform.
|
||||||
*/
|
*/
|
||||||
@@ -734,6 +740,7 @@ namespace {
|
|||||||
const char ARGUMENT_NAME[] = "Name";
|
const char ARGUMENT_NAME[] = "Name";
|
||||||
const char ARGUMENT_PARAMETER[] = "Parameter";
|
const char ARGUMENT_PARAMETER[] = "Parameter";
|
||||||
const char ARGUMENT_DESCRIPTION[] = "Description";
|
const char ARGUMENT_DESCRIPTION[] = "Description";
|
||||||
|
const char TERMSANDCONDITIONS[] = "TermsAndConditions";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -978,6 +985,23 @@ Utils::expected_str<void> PluginSpecPrivate::readMetaData(const QJsonObject &dat
|
|||||||
if (auto r = assignOr(revision, "Revision", QString{}); !r.has_value())
|
if (auto r = assignOr(revision, "Revision", QString{}); !r.has_value())
|
||||||
return reportError(r.error());
|
return reportError(r.error());
|
||||||
|
|
||||||
|
QJsonObject tAndC = metaData.value(QLatin1String(TERMSANDCONDITIONS)).toObject();
|
||||||
|
if (!tAndC.isEmpty()) {
|
||||||
|
QJsonValue version = tAndC.value(QLatin1String("version"));
|
||||||
|
QJsonValue text = tAndC.value(QLatin1String("text"));
|
||||||
|
|
||||||
|
if (!version.isDouble()) {
|
||||||
|
return reportError(::ExtensionSystem::Tr::tr("Terms and conditions: %1")
|
||||||
|
.arg(msgValueMissing("version")));
|
||||||
|
}
|
||||||
|
if (!text.isString() || text.toString().isEmpty()) {
|
||||||
|
return reportError(
|
||||||
|
::ExtensionSystem::Tr::tr("Terms and conditions: %1").arg(msgValueMissing("text")));
|
||||||
|
}
|
||||||
|
|
||||||
|
termsAndConditions.emplace(TermsAndConditions{version.toInt(), text.toString()});
|
||||||
|
}
|
||||||
|
|
||||||
QJsonValue value = metaData.value(QLatin1String(PLATFORM));
|
QJsonValue value = metaData.value(QLatin1String(PLATFORM));
|
||||||
if (!value.isUndefined() && !value.isString())
|
if (!value.isUndefined() && !value.isString())
|
||||||
return reportError(msgValueIsNotAString(PLATFORM));
|
return reportError(msgValueIsNotAString(PLATFORM));
|
||||||
|
@@ -34,6 +34,12 @@ class PluginSpecPrivate;
|
|||||||
|
|
||||||
class PluginView;
|
class PluginView;
|
||||||
|
|
||||||
|
struct EXTENSIONSYSTEM_EXPORT TermsAndConditions
|
||||||
|
{
|
||||||
|
int version;
|
||||||
|
QString text;
|
||||||
|
};
|
||||||
|
|
||||||
struct EXTENSIONSYSTEM_EXPORT PluginDependency
|
struct EXTENSIONSYSTEM_EXPORT PluginDependency
|
||||||
{
|
{
|
||||||
enum Type { Required, Optional, Test };
|
enum Type { Required, Optional, Test };
|
||||||
@@ -110,6 +116,7 @@ public:
|
|||||||
virtual QString category() const;
|
virtual QString category() const;
|
||||||
virtual QString revision() const;
|
virtual QString revision() const;
|
||||||
virtual QRegularExpression platformSpecification() const;
|
virtual QRegularExpression platformSpecification() const;
|
||||||
|
virtual std::optional<TermsAndConditions> termsAndConditions() const;
|
||||||
|
|
||||||
virtual QString displayName() const;
|
virtual QString displayName() const;
|
||||||
|
|
||||||
|
@@ -31,6 +31,7 @@
|
|||||||
#include <utils/checkablemessagebox.h>
|
#include <utils/checkablemessagebox.h>
|
||||||
#include <utils/commandline.h>
|
#include <utils/commandline.h>
|
||||||
#include <utils/infobar.h>
|
#include <utils/infobar.h>
|
||||||
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/macroexpander.h>
|
#include <utils/macroexpander.h>
|
||||||
#include <utils/mimeutils.h>
|
#include <utils/mimeutils.h>
|
||||||
#include <utils/networkaccessmanager.h>
|
#include <utils/networkaccessmanager.h>
|
||||||
@@ -163,6 +164,37 @@ static void initProxyAuthDialog()
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void initTAndCAcceptDialog()
|
||||||
|
{
|
||||||
|
ExtensionSystem::PluginManager::instance()->setAcceptTermsAndConditionsCallback(
|
||||||
|
[](ExtensionSystem::PluginSpec *spec) {
|
||||||
|
using namespace Layouting;
|
||||||
|
|
||||||
|
QDialog dialog(ICore::dialogParent());
|
||||||
|
dialog.setWindowTitle(Tr::tr("Terms and Conditions"));
|
||||||
|
|
||||||
|
QDialogButtonBox buttonBox(
|
||||||
|
QDialogButtonBox::StandardButton::Yes | QDialogButtonBox::StandardButton::No);
|
||||||
|
QObject::connect(&buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
||||||
|
QObject::connect(&buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
Column {
|
||||||
|
Tr::tr("The plugin %1 requires you to accept the following terms and conditions:").arg(spec->name()), br,
|
||||||
|
TextEdit {
|
||||||
|
markdown(spec->termsAndConditions()->text),
|
||||||
|
readOnly(true),
|
||||||
|
}, br,
|
||||||
|
Row {
|
||||||
|
Tr::tr("Do you wish to accept?"), &buttonBox,
|
||||||
|
}
|
||||||
|
}.attachTo(&dialog);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
return dialog.exec() == QDialog::Accepted;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
|
bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
|
||||||
{
|
{
|
||||||
// register all mime types from all plugins
|
// register all mime types from all plugins
|
||||||
@@ -171,7 +203,7 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
|
|||||||
continue;
|
continue;
|
||||||
loadMimeFromPlugin(plugin);
|
loadMimeFromPlugin(plugin);
|
||||||
}
|
}
|
||||||
|
initTAndCAcceptDialog();
|
||||||
initProxyAuthDialog();
|
initProxyAuthDialog();
|
||||||
|
|
||||||
if (ThemeEntry::availableThemes().isEmpty()) {
|
if (ThemeEntry::availableThemes().isEmpty()) {
|
||||||
|
Reference in New Issue
Block a user