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_FORCEENABLED_PLUGINS[] = "Plugins/ForceEnabled";
|
||||
const char C_TANDCACCEPTED_PLUGINS[] = "Plugins/TermsAndConditionsAccepted";
|
||||
|
||||
const std::chrono::milliseconds DELAYED_INITIALIZE_INTERVAL{20};
|
||||
|
||||
enum { debugLeaks = 0 };
|
||||
@@ -1051,6 +1053,8 @@ void PluginManagerPrivate::readSettings()
|
||||
if (settings) {
|
||||
disabledPlugins = toLower(settings->value(C_IGNORED_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));
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
@@ -1700,6 +1732,13 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
|
||||
if (!spec->isEffectivelyEnabled() && destState == PluginSpec::Loaded)
|
||||
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;
|
||||
if (enableCrashCheck && destState < PluginSpec::Stopped)
|
||||
lockFile.reset(new LockFile(this, spec));
|
||||
@@ -2026,4 +2065,10 @@ void PluginManager::startProfiling()
|
||||
d->m_profileElapsedMS = 0;
|
||||
}
|
||||
|
||||
void PluginManager::setAcceptTermsAndConditionsCallback(
|
||||
const std::function<bool(PluginSpec *)> &callback)
|
||||
{
|
||||
d->setAcceptTermsAndConditionsCallback(callback);
|
||||
}
|
||||
|
||||
} // ExtensionSystem
|
||||
|
@@ -137,6 +137,8 @@ public:
|
||||
|
||||
static QString systemInformation();
|
||||
|
||||
void setAcceptTermsAndConditionsCallback(const std::function<bool(PluginSpec *)> &callback);
|
||||
|
||||
signals:
|
||||
void objectAdded(QObject *obj);
|
||||
void aboutToRemoveObject(QObject *obj);
|
||||
|
@@ -68,6 +68,9 @@ public:
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
|
||||
bool acceptTermsAndConditions(PluginSpec *spec);
|
||||
void setAcceptTermsAndConditionsCallback(const std::function<bool(PluginSpec *)> &callback);
|
||||
|
||||
class TestSpec {
|
||||
public:
|
||||
TestSpec(PluginSpec *pluginSpec, const QStringList &testFunctionsOrObjects = QStringList())
|
||||
@@ -98,6 +101,7 @@ public:
|
||||
QStringList defaultEnabledPlugins; // Plugins/ForceEnabled from install settings
|
||||
QStringList disabledPlugins;
|
||||
QStringList forceEnabledPlugins;
|
||||
QStringList pluginsWithAcceptedTermsAndConditions;
|
||||
// delayed initialization
|
||||
QTimer delayedInitializeTimer;
|
||||
std::queue<PluginSpec *> delayedInitializeQueue;
|
||||
@@ -115,6 +119,8 @@ public:
|
||||
Utils::QtcSettings *settings = nullptr;
|
||||
Utils::QtcSettings *globalSettings = nullptr;
|
||||
|
||||
std::function<bool(PluginSpec *)> acceptTermsAndConditionsCallback;
|
||||
|
||||
// Look in argument descriptions of the specs for the option.
|
||||
PluginSpec *pluginForOption(const QString &option, bool *requiresArgument) const;
|
||||
PluginSpec *pluginById(const QString &id) const;
|
||||
|
@@ -202,6 +202,7 @@ public:
|
||||
QString copyright;
|
||||
QStringList arguments;
|
||||
QRegularExpression platformSpecification;
|
||||
std::optional<TermsAndConditions> termsAndConditions;
|
||||
QVector<ExtensionSystem::PluginDependency> dependencies;
|
||||
|
||||
PluginSpec::PluginArgumentDescriptions argumentDescriptions;
|
||||
@@ -392,6 +393,11 @@ QRegularExpression PluginSpec::platformSpecification() const
|
||||
return d->platformSpecification;
|
||||
}
|
||||
|
||||
std::optional<TermsAndConditions> PluginSpec::termsAndConditions() const
|
||||
{
|
||||
return d->termsAndConditions;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns whether the plugin works on the host platform.
|
||||
*/
|
||||
@@ -734,6 +740,7 @@ namespace {
|
||||
const char ARGUMENT_NAME[] = "Name";
|
||||
const char ARGUMENT_PARAMETER[] = "Parameter";
|
||||
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())
|
||||
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));
|
||||
if (!value.isUndefined() && !value.isString())
|
||||
return reportError(msgValueIsNotAString(PLATFORM));
|
||||
|
@@ -34,6 +34,12 @@ class PluginSpecPrivate;
|
||||
|
||||
class PluginView;
|
||||
|
||||
struct EXTENSIONSYSTEM_EXPORT TermsAndConditions
|
||||
{
|
||||
int version;
|
||||
QString text;
|
||||
};
|
||||
|
||||
struct EXTENSIONSYSTEM_EXPORT PluginDependency
|
||||
{
|
||||
enum Type { Required, Optional, Test };
|
||||
@@ -110,6 +116,7 @@ public:
|
||||
virtual QString category() const;
|
||||
virtual QString revision() const;
|
||||
virtual QRegularExpression platformSpecification() const;
|
||||
virtual std::optional<TermsAndConditions> termsAndConditions() const;
|
||||
|
||||
virtual QString displayName() const;
|
||||
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include <utils/checkablemessagebox.h>
|
||||
#include <utils/commandline.h>
|
||||
#include <utils/infobar.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
#include <utils/macroexpander.h>
|
||||
#include <utils/mimeutils.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)
|
||||
{
|
||||
// register all mime types from all plugins
|
||||
@@ -171,7 +203,7 @@ bool CorePlugin::initialize(const QStringList &arguments, QString *errorMessage)
|
||||
continue;
|
||||
loadMimeFromPlugin(plugin);
|
||||
}
|
||||
|
||||
initTAndCAcceptDialog();
|
||||
initProxyAuthDialog();
|
||||
|
||||
if (ThemeEntry::availableThemes().isEmpty()) {
|
||||
|
Reference in New Issue
Block a user