diff --git a/src/plugins/bazaar/Bazaar.json.in b/src/plugins/bazaar/Bazaar.json.in index e725b785734..8311877c71c 100644 --- a/src/plugins/bazaar/Bazaar.json.in +++ b/src/plugins/bazaar/Bazaar.json.in @@ -4,6 +4,7 @@ "Name" : "Bazaar", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", + "DisabledByDefault" : true, "VendorId" : "huguesdelorme", "Vendor" : "Hugues Delorme", "Copyright" : "(C) 2016 Hugues Delorme, ${IDE_COPYRIGHT}", @@ -23,5 +24,8 @@ ], "Url" : "https://www.qt.io", "DocumentationUrl" : "https://doc.qt.io/qtcreator/creator-vcs-bazaar.html", + "VcsDetectionFiles" : [ + ".bzr/branch-format" + ], ${IDE_PLUGIN_DEPENDENCIES} } diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 6168acfd6c6..55e99c92e1d 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -1126,6 +1126,35 @@ void ICore::restart() exit(); } +/*! + Asks the user if they want to enable the \a plugins and their dependencies. + If the user agrees, the plugins are enabled. + If all plugins are soft loadable without restart, they get loaded directly. + Otherwise the "Restart Required" dialog is shown. + + Returns whether the user agreed to enabling the plugins. +*/ +bool ICore::enablePlugins(const QSet &plugins) +{ + std::optional> additionalPlugins + = PluginManager::askForEnablingPlugins(dialogParent(), plugins, /*enable=*/true); + if (!additionalPlugins) // canceled + return false; + const QSet affectedPlugins = plugins + *additionalPlugins; + bool softloadable = true; + for (PluginSpec *spec : affectedPlugins) { + spec->setEnabledBySettings(true); + softloadable = softloadable && spec->isSoftLoadable(); + } + ExtensionSystem::PluginManager::writeSettings(); + if (softloadable) { + PluginManager::loadPluginsAtRuntime(affectedPlugins); + } else { + ICore::askForRestart(Tr::tr("Plugin changes will take effect after restart.")); + } + return true; +} + /*! \internal */ diff --git a/src/plugins/coreplugin/icore.h b/src/plugins/coreplugin/icore.h index 9aa1e93c393..10a90f66464 100644 --- a/src/plugins/coreplugin/icore.h +++ b/src/plugins/coreplugin/icore.h @@ -6,6 +6,7 @@ #include "core_global.h" #include "icontext.h" +#include #include #include #include @@ -116,6 +117,8 @@ public: static void restart(); + static bool enablePlugins(const QSet &plugins); + enum SaveSettingsReason { SettingsDialogDone, ModeChanged, diff --git a/src/plugins/coreplugin/vcsmanager.cpp b/src/plugins/coreplugin/vcsmanager.cpp index de146a5656b..14271eab44f 100644 --- a/src/plugins/coreplugin/vcsmanager.cpp +++ b/src/plugins/coreplugin/vcsmanager.cpp @@ -12,12 +12,15 @@ #include "iversioncontrol.h" #include +#include #include #include #include #include +#include +#include #include #include #include @@ -177,6 +180,74 @@ static FilePath fixedDir(const FilePath &directory) return directory; } +static void askForDisabledVcsPlugins(const FilePath &inputDirectory) +{ + using namespace ExtensionSystem; + FilePath toplevel; + + PluginSpec *spec = Utils::findOrDefault( + PluginManager::plugins(), [&toplevel, inputDirectory](PluginSpec *plugin) { + if (plugin->isEffectivelyEnabled()) + return false; + const QJsonObject metaData = plugin->metaData(); + const QJsonArray filesArray = metaData.value("VcsDetectionFiles").toArray(); + if (filesArray.isEmpty()) + return false; + QStringList files; + for (const QJsonValue &v : filesArray) { + const QString str = v.toString(); + if (!str.isEmpty()) + files.append(str); + } + if (files.isEmpty()) + return false; + qCDebug(findRepoLog) << "Checking if plugin" << plugin->displayName() << "can handle" + << inputDirectory.toUserOutput(); + qCDebug(findRepoLog) << "by checking for" << files; + const FilePath dir = VcsManager::findRepositoryForFiles(inputDirectory, files); + if (dir.isEmpty()) + return false; + qCDebug(findRepoLog) << "The plugin" << plugin->displayName() << "can handle" + << inputDirectory.toUserOutput(); + toplevel = dir; + return true; + }); + + if (!spec) + return; + + const Id vcsSuggestion = Id("VcsManager.Suggestion.").withSuffix(spec->id()); + InfoBar *infoBar = ICore::infoBar(); + if (!infoBar->canInfoBeAdded(vcsSuggestion)) + return; + + const QString pluginDisplayName = spec->displayName(); + Utils::InfoBarEntry info( + vcsSuggestion, + Tr::tr("A directory under version control was detected that is supported by the %1 plugin.") + .arg(pluginDisplayName), + Utils::InfoBarEntry::GlobalSuppression::Enabled); + info.addCustomButton(Tr::tr("Enable %1").arg(pluginDisplayName), [vcsSuggestion, spec] { + // TODO In case the plugin is actually loaded during runtime (softloadable), + // we'd need to restructure findVersionControlForDirectory below to take the new plugin + // into account. + // At the moment softloadable VCS plugins are not supported though. + if (ICore::enablePlugins({spec})) + ICore::infoBar()->removeInfo(vcsSuggestion); + }); + + info.setDetailsWidgetCreator([toplevel, pluginDisplayName]() -> QWidget * { + auto label = new QLabel; + label->setWordWrap(true); + label->setOpenExternalLinks(true); + label->setText(Tr::tr("The directory \"%1\" seems to be under version control that can be " + "handled by the disabled %2 plugin.") + .arg(toplevel.toUserOutput(), pluginDisplayName)); + label->setContentsMargins(0, 0, 0, 8); + return label; + }); + ICore::infoBar()->addInfo(info); +}; IVersionControl* VcsManager::findVersionControlForDirectory(const FilePath &inputDirectory, FilePath *topLevelDirectory) @@ -221,6 +292,8 @@ IVersionControl* VcsManager::findVersionControlForDirectory(const FilePath &inpu // report result; if (topLevelDirectory) topLevelDirectory->clear(); + + askForDisabledVcsPlugins(directory); return nullptr; } diff --git a/src/plugins/fossil/Fossil.json.in b/src/plugins/fossil/Fossil.json.in index ccc9856d2bc..6018e41ed4e 100644 --- a/src/plugins/fossil/Fossil.json.in +++ b/src/plugins/fossil/Fossil.json.in @@ -24,6 +24,9 @@ ], "Url" : "https://www.qt.io", "DocumentationUrl" : "https://doc.qt.io/qtcreator/creator-vcs-fossil.html", + "VcsDetectionFiles" : [ + ".fslckout" + ], ${IDE_PLUGIN_DEPENDENCIES}, "JsonWizardPaths" : [":/fossil/wizard"] diff --git a/src/plugins/git/Git.json.in b/src/plugins/git/Git.json.in index 6c6b476b880..d87f9341643 100644 --- a/src/plugins/git/Git.json.in +++ b/src/plugins/git/Git.json.in @@ -30,6 +30,10 @@ "Description" : "Show given commit hash" } ], + "VcsDetectionFiles" : [ + ".git", + ".git/config" + ], ${IDE_PLUGIN_DEPENDENCIES}, "Mimetypes" : [ diff --git a/src/plugins/mercurial/Mercurial.json.in b/src/plugins/mercurial/Mercurial.json.in index d8125d77ba2..835005771ca 100644 --- a/src/plugins/mercurial/Mercurial.json.in +++ b/src/plugins/mercurial/Mercurial.json.in @@ -4,6 +4,7 @@ "Name" : "Mercurial", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", + "DisabledByDefault" : true, "VendorId" : "brianmcgillion", "Vendor" : "Brian McGillion", "Copyright" : "(C) 2016 Brian McGillion, ${IDE_COPYRIGHT}", @@ -23,5 +24,8 @@ ], "Url" : "https://www.qt.io", "DocumentationUrl" : "https://doc.qt.io/qtcreator/creator-vcs-mercurial.html", + "VcsDetectionFiles" : [ + ".hg/requires" + ], ${IDE_PLUGIN_DEPENDENCIES} } diff --git a/src/plugins/subversion/Subversion.json.in b/src/plugins/subversion/Subversion.json.in index 1941eb222c4..81420a0e3ac 100644 --- a/src/plugins/subversion/Subversion.json.in +++ b/src/plugins/subversion/Subversion.json.in @@ -4,6 +4,7 @@ "Name" : "Subversion", "Version" : "${IDE_VERSION}", "CompatVersion" : "${IDE_VERSION_COMPAT}", + "DisabledByDefault" : true, "VendorId" : "theqtcompany", "Vendor" : "The Qt Company Ltd", "Copyright" : "${IDE_COPYRIGHT}", @@ -23,6 +24,10 @@ ], "Url" : "https://www.qt.io", "DocumentationUrl" : "https://doc.qt.io/qtcreator/creator-vcs-subversion.html", + "VcsDetectionFiles" : [ + ".svn/wc.db", + "_svn/wc.db" + ], ${IDE_PLUGIN_DEPENDENCIES}, "Mimetypes" : [