aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@qt.io>2020-01-08 13:38:08 +0100
committerEike Ziller <eike.ziller@qt.io>2020-01-09 15:04:18 +0000
commitce69a9af83f4fb9e3074175f382c3b1da382d67f (patch)
treeaf550938d144967c8b431a16904e42d383c2f441 /src
parente5a9e981ad268cc8deb42f9c819e0a435ba4929f (diff)
Provide option to "link" Qt Creator to a Qt installation
Allows making e.g. a Qt Creator-only offline installation aware of a Qt installation, with auto-registration of Qt versions and kits. Change-Id: Ia92dd9d4dbf34acb3a01713207699ff3f14cea12 Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: hjk <hjk@qt.io> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/qtsupport/qtoptionspage.cpp197
-rw-r--r--src/plugins/qtsupport/qtoptionspage.h3
-rw-r--r--src/plugins/qtsupport/qtsupportplugin.cpp27
-rw-r--r--src/plugins/qtsupport/qtversionmanager.ui7
4 files changed, 224 insertions, 10 deletions
diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp
index d059b02dee..c48126247f 100644
--- a/src/plugins/qtsupport/qtoptionspage.cpp
+++ b/src/plugins/qtsupport/qtoptionspage.cpp
@@ -32,34 +32,40 @@
#include "qtversionmanager.h"
#include "qtversionfactory.h"
-#include <coreplugin/progressmanager/progressmanager.h>
+#include <app/app_version.h>
#include <coreplugin/coreconstants.h>
+#include <coreplugin/dialogs/restartdialog.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/progressmanager/progressmanager.h>
#include <coreplugin/variablechooser.h>
-#include <projectexplorer/toolchain.h>
-#include <projectexplorer/toolchainmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectexplorericons.h>
+#include <projectexplorer/toolchain.h>
+#include <projectexplorer/toolchainmanager.h>
+#include <utils/algorithm.h>
#include <utils/buildablehelperlibrary.h>
#include <utils/hostosinfo.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
#include <utils/runextensions.h>
-#include <utils/algorithm.h>
#include <utils/treemodel.h>
#include <utils/utilsicons.h>
+#include <QDesktopServices>
#include <QDir>
-#include <QMessageBox>
#include <QFileDialog>
-#include <QTextBrowser>
-#include <QDesktopServices>
+#include <QMessageBox>
#include <QSortFilterProxyModel>
+#include <QTextBrowser>
+#include <QTimer>
#include <utility>
using namespace ProjectExplorer;
using namespace Utils;
+const char kInstallSettingsKey[] = "Settings/InstallSettings";
+
namespace QtSupport {
namespace Internal {
@@ -191,7 +197,6 @@ void QtOptionsPage::finish()
//-----------------------------------------------------
-
QtOptionsPageWidget::QtOptionsPageWidget(QWidget *parent)
: QWidget(parent)
, m_specifyNameString(tr("<specify a name>"))
@@ -208,6 +213,8 @@ QtOptionsPageWidget::QtOptionsPageWidget(QWidget *parent)
m_ui->setupUi(this);
+ setupLinkWithQtButton();
+
m_infoBrowser->setOpenLinks(false);
m_infoBrowser->setTextInteractionFlags(Qt::TextBrowserInteraction);
connect(m_infoBrowser, &QTextBrowser::anchorClicked,
@@ -751,6 +758,58 @@ void QtOptionsPageWidget::updateWidgets()
m_versionUi->editPathPushButton->setEnabled(enabled && !isAutodetected);
}
+static QString settingsFile(const QString &baseDir)
+{
+ return baseDir + (baseDir.isEmpty() ? "" : "/") + Core::Constants::IDE_SETTINGSVARIANT_STR + '/'
+ + Core::Constants::IDE_CASED_ID + ".ini";
+}
+
+static Utils::optional<QString> currentlyLinkedQtDir(bool *hasInstallSettings)
+{
+ const QString installSettingsFilePath = settingsFile(Core::ICore::resourcePath());
+ const bool installSettingsExist = QFile::exists(installSettingsFilePath);
+ if (hasInstallSettings)
+ *hasInstallSettings = installSettingsExist;
+ if (installSettingsExist) {
+ const QVariant value = QSettings(installSettingsFilePath, QSettings::IniFormat)
+ .value(kInstallSettingsKey);
+ if (value.isValid())
+ return value.toString();
+ }
+ return {};
+}
+
+static QString linkingPurposeText()
+{
+ return QtOptionsPageWidget::tr(
+ "Linking with a Qt installation automatically registers Qt versions and kits.");
+}
+
+void QtOptionsPageWidget::setupLinkWithQtButton()
+{
+ bool installSettingsExist;
+ const Utils::optional<QString> installSettingsValue = currentlyLinkedQtDir(
+ &installSettingsExist);
+ QStringList tip;
+ tip << linkingPurposeText();
+ if (!FilePath::fromString(Core::ICore::resourcePath()).isWritablePath()) {
+ m_ui->linkWithQtButton->setEnabled(false);
+ tip << tr("%1's resource directory is not writable.").arg(Core::Constants::IDE_DISPLAY_NAME);
+ }
+ // guard against redirecting Qt Creator that is part of a Qt installations
+ // TODO this fails for pre-releases in the online installer
+ // TODO this will fail when make Qt Creator non-required in the Qt installers
+ if (installSettingsExist && !installSettingsValue) {
+ m_ui->linkWithQtButton->setEnabled(false);
+ tip << tr("%1 is part of a Qt installation.").arg(Core::Constants::IDE_DISPLAY_NAME);
+ }
+ const QString link = installSettingsValue ? *installSettingsValue : QString();
+ if (!link.isEmpty())
+ tip << tr("%1 is currently linked to \"%2\".").arg(Core::Constants::IDE_DISPLAY_NAME, link);
+ m_ui->linkWithQtButton->setToolTip(tip.join("\n\n"));
+ connect(m_ui->linkWithQtButton, &QPushButton::clicked, this, &QtOptionsPageWidget::linkWithQt);
+}
+
void QtOptionsPageWidget::updateCurrentQtName()
{
QtVersionItem *item = currentItem();
@@ -781,8 +840,126 @@ void QtOptionsPageWidget::apply()
});
QtVersionManager::setNewQtVersions(versions);
- connect(QtVersionManager::instance(), &QtVersionManager::qtVersionsChanged,
- this, &QtOptionsPageWidget::updateQtVersions);
+ connect(QtVersionManager::instance(),
+ &QtVersionManager::qtVersionsChanged,
+ this,
+ &QtOptionsPageWidget::updateQtVersions);
+}
+
+// TODO whenever we move the output of sdktool to a different location in the installer,
+// this needs to be adapted accordingly
+const QStringList kSubdirsToCheck = {"",
+ "Qt Creator.app/Contents/Resources",
+ "Contents/Resources",
+ "Tools/QtCreator/share/qtcreator"};
+
+static Utils::optional<QString> settingsDirForQtDir(const QString &qtDir)
+{
+ const QStringList dirsToCheck = Utils::transform(kSubdirsToCheck, [qtDir](const QString &dir) {
+ return QString(qtDir + '/' + dir);
+ });
+ const QString validDir = Utils::findOrDefault(dirsToCheck, [](const QString &dir) {
+ return QFile::exists(settingsFile(dir));
+ });
+ if (!validDir.isEmpty())
+ return validDir;
+ return {};
+}
+
+static bool validateQtInstallDir(FancyLineEdit *input, QString *errorString)
+{
+ const QString qtDir = input->text();
+ if (!settingsDirForQtDir(qtDir)) {
+ if (errorString) {
+ const QStringList filesToCheck = Utils::transform(kSubdirsToCheck,
+ [](const QString &dir) {
+ return settingsFile(dir);
+ });
+ *errorString = QtOptionsPageWidget::tr(
+ "<html><body>Qt installation information was not found in \"%1\". "
+ "Choose a directory that contains one of the files <pre>%2</pre>")
+ .arg(qtDir, filesToCheck.join('\n'));
+ }
+ return false;
+ }
+ return true;
+}
+
+static QString defaultQtInstallationPath()
+{
+ if (HostOsInfo::isWindowsHost())
+ return "C:/Qt";
+ return QDir::homePath() + "/Qt";
+}
+
+void QtOptionsPageWidget::linkWithQt()
+{
+ const QString title = tr("Choose Qt Installation");
+ const QString restartText = tr("The change will take effect after restart.");
+ bool askForRestart = false;
+ QDialog dialog(Core::ICore::dialogParent());
+ dialog.setWindowTitle(title);
+ auto layout = new QVBoxLayout;
+ dialog.setLayout(layout);
+ layout->addWidget(new QLabel(linkingPurposeText()));
+ auto pathLayout = new QHBoxLayout;
+ layout->addLayout(pathLayout);
+ auto pathLabel = new QLabel(tr("Qt installation path:"));
+ pathLabel->setToolTip(
+ tr("Choose the Qt installation directory, or a directory that contains \"%1\".")
+ .arg(settingsFile("")));
+ pathLayout->addWidget(pathLabel);
+ auto pathInput = new PathChooser;
+ pathLayout->addWidget(pathInput);
+ pathInput->setExpectedKind(PathChooser::ExistingDirectory);
+ pathInput->setPromptDialogTitle(title);
+ pathInput->setMacroExpander(nullptr);
+ pathInput->setValidationFunction([pathInput](FancyLineEdit *input, QString *errorString) {
+ if (pathInput->defaultValidationFunction()
+ && !pathInput->defaultValidationFunction()(input, errorString))
+ return false;
+ return validateQtInstallDir(input, errorString);
+ });
+ const Utils::optional<QString> currentLink = currentlyLinkedQtDir(nullptr);
+ pathInput->setPath(currentLink ? *currentLink : defaultQtInstallationPath());
+ auto buttons = new QDialogButtonBox;
+ layout->addWidget(buttons);
+ auto linkButton = buttons->addButton(tr("Link with Qt"), QDialogButtonBox::AcceptRole);
+ connect(linkButton, &QPushButton::clicked, &dialog, &QDialog::accept);
+ auto cancelButton = buttons->addButton(tr("Cancel"), QDialogButtonBox::RejectRole);
+ connect(cancelButton, &QPushButton::clicked, &dialog, &QDialog::reject);
+ auto unlinkButton = buttons->addButton(tr("Remove Link"), QDialogButtonBox::DestructiveRole);
+ unlinkButton->setEnabled(currentLink.has_value());
+ connect(unlinkButton, &QPushButton::clicked, &dialog, [&dialog, &askForRestart] {
+ bool removeSettingsFile = false;
+ const QString filePath = settingsFile(Core::ICore::resourcePath());
+ {
+ QSettings installSettings(filePath, QSettings::IniFormat);
+ installSettings.remove(kInstallSettingsKey);
+ if (installSettings.allKeys().isEmpty())
+ removeSettingsFile = true;
+ }
+ if (removeSettingsFile)
+ QFile::remove(filePath);
+ askForRestart = true;
+ dialog.reject();
+ });
+ connect(pathInput, &PathChooser::validChanged, linkButton, &QPushButton::setEnabled);
+ linkButton->setEnabled(pathInput->isValid());
+
+ dialog.exec();
+ if (dialog.result() == QDialog::Accepted) {
+ const Utils::optional<QString> settingsDir = settingsDirForQtDir(pathInput->rawPath());
+ if (QTC_GUARD(settingsDir)) {
+ QSettings(settingsFile(Core::ICore::resourcePath()), QSettings::IniFormat)
+ .setValue(kInstallSettingsKey, *settingsDir);
+ askForRestart = true;
+ }
+ }
+ if (askForRestart) {
+ Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
+ restartDialog.exec();
+ }
}
} // namespace Internal
diff --git a/src/plugins/qtsupport/qtoptionspage.h b/src/plugins/qtsupport/qtoptionspage.h
index ece24c4b51..c094218b38 100644
--- a/src/plugins/qtsupport/qtoptionspage.h
+++ b/src/plugins/qtsupport/qtoptionspage.h
@@ -64,10 +64,13 @@ public:
~QtOptionsPageWidget();
void apply();
+ static void linkWithQt();
+
private:
void updateDescriptionLabel();
void userChangedCurrentVersion();
void updateWidgets();
+ void setupLinkWithQtButton();
BaseQtVersion *currentVersion() const;
QtVersionItem *currentItem() const;
void showDebuggingBuildLog(const QtVersionItem *item);
diff --git a/src/plugins/qtsupport/qtsupportplugin.cpp b/src/plugins/qtsupport/qtsupportplugin.cpp
index 9193a3071b..9059207f8c 100644
--- a/src/plugins/qtsupport/qtsupportplugin.cpp
+++ b/src/plugins/qtsupport/qtsupportplugin.cpp
@@ -40,6 +40,7 @@
#include "uicgenerator.h"
#include <coreplugin/icore.h>
+#include <coreplugin/infobar.h>
#include <coreplugin/jsexpander.h>
#include <projectexplorer/jsonwizard/jsonwizardfactory.h>
@@ -115,6 +116,30 @@ static BaseQtVersion *qtVersion()
return QtKitAspect::qtVersion(project->activeTarget()->kit());
}
+const char kLinkWithQtInstallationSetting[] = "LinkWithQtInstallation";
+
+static void askAboutQtInstallation()
+{
+ // if the install settings exist, the Qt Creator installation is (probably) already linked to
+ // a Qt installation, so don't ask
+ if (QFile::exists(ICore::settings(QSettings::SystemScope)->fileName())
+ || !ICore::infoBar()->canInfoBeAdded(kLinkWithQtInstallationSetting))
+ return;
+
+ InfoBarEntry info(
+ kLinkWithQtInstallationSetting,
+ QtSupportPlugin::tr(
+ "Link with a Qt installation to automatically register Qt versions and kits? To do "
+ "this later, select Options > Kits > Qt Versions > Link with Qt."),
+ InfoBarEntry::GlobalSuppression::Enabled);
+ info.setCustomButtonInfo(QtSupportPlugin::tr("Link with Qt"), [] {
+ ICore::infoBar()->removeInfo(kLinkWithQtInstallationSetting);
+ ICore::infoBar()->globallySuppressInfo(kLinkWithQtInstallationSetting);
+ QTimer::singleShot(0, ICore::mainWindow(), &QtOptionsPageWidget::linkWithQt);
+ });
+ ICore::infoBar()->addInfo(info);
+}
+
void QtSupportPlugin::extensionsInitialized()
{
Utils::MacroExpander *expander = Utils::globalMacroExpander();
@@ -136,6 +161,8 @@ void QtSupportPlugin::extensionsInitialized()
BaseQtVersion *qt = qtVersion();
return qt ? qt->binPath().toUserOutput() : QString();
});
+
+ askAboutQtInstallation();
}
} // Internal
diff --git a/src/plugins/qtsupport/qtversionmanager.ui b/src/plugins/qtsupport/qtversionmanager.ui
index 6f303b06be..42bac27091 100644
--- a/src/plugins/qtsupport/qtversionmanager.ui
+++ b/src/plugins/qtsupport/qtversionmanager.ui
@@ -100,6 +100,13 @@
</spacer>
</item>
<item>
+ <widget class="QPushButton" name="linkWithQtButton">
+ <property name="text">
+ <string>Link with Qt...</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<widget class="QPushButton" name="cleanUpButton">
<property name="text">
<string>Clean Up</string>