From be54b3db2f4356d477b372bd4528415f2fa57e85 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 15 Aug 2023 15:37:51 +0200 Subject: [PATCH] Python: check for pyside in qt installation Fixes: PYSIDE-2153 Change-Id: I91ec24eb6a71d4f29edaf7a707b3c49a4deb725a Reviewed-by: Christian Stenger --- src/libs/utils/filepath.cpp | 7 +++ src/libs/utils/filepath.h | 1 + src/plugins/python/CMakeLists.txt | 2 +- src/plugins/python/pyside.cpp | 54 ++++++++++++++++++- src/plugins/python/python.qbs | 5 +- .../tests/qmlpreviewplugin_test.cpp | 3 +- src/plugins/qtsupport/qtoptionspage.cpp | 24 ++++++--- src/plugins/qtsupport/qtoptionspage.h | 19 +++++-- src/plugins/qtsupport/qtsupportplugin.cpp | 4 +- 9 files changed, 97 insertions(+), 22 deletions(-) diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index 42c1a19957f..abafc7748e8 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -1788,6 +1788,13 @@ FilePath FilePath::stringAppended(const QString &str) const return FilePath::fromString(toString() + str); } +std::optional FilePath::tailRemoved(const QString &str) const +{ + if (pathView().endsWith(str)) + return withNewPath(pathView().chopped(str.size()).toString()); + return {}; +} + QDateTime FilePath::lastModified() const { return fileAccess()->lastModified(*this); diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index ae71d3f2e31..a5605769866 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -97,6 +97,7 @@ public: [[nodiscard]] FilePath pathAppended(const QString &str) const; [[nodiscard]] FilePath stringAppended(const QString &str) const; + [[nodiscard]] std::optional tailRemoved(const QString &str) const; bool startsWith(const QString &s) const; bool endsWith(const QString &s) const; bool contains(const QString &s) const; diff --git a/src/plugins/python/CMakeLists.txt b/src/plugins/python/CMakeLists.txt index 0e4ca944194..25275cebdfc 100644 --- a/src/plugins/python/CMakeLists.txt +++ b/src/plugins/python/CMakeLists.txt @@ -1,6 +1,6 @@ add_qtc_plugin(Python DEPENDS QmlJS - PLUGIN_DEPENDS Core LanguageClient ProjectExplorer TextEditor + PLUGIN_DEPENDS Core LanguageClient ProjectExplorer TextEditor QtSupport SOURCES pipsupport.cpp pipsupport.h pyside.cpp pyside.h diff --git a/src/plugins/python/pyside.cpp b/src/plugins/python/pyside.cpp index 4b9df185a37..a2f1cac2fc1 100644 --- a/src/plugins/python/pyside.cpp +++ b/src/plugins/python/pyside.cpp @@ -13,6 +13,8 @@ #include #include +#include + #include #include @@ -21,6 +23,9 @@ #include #include +#include +#include +#include #include #include @@ -79,7 +84,19 @@ void PySideInstaller::installPyside(const FilePath &python, const QString &pySide, TextEditor::TextDocument *document) { - document->infoBar()->removeInfo(installPySideInfoBarId); + QMap availablePySides; + + const std::optional qtInstallDir + = QtSupport::LinkWithQtSupport::linkedQt().tailRemoved("Tools/sdktool/share/qtcreator"); + if (qtInstallDir) { + const FilePath qtForPythonDir = qtInstallDir->pathAppended("QtForPython"); + for (const FilePath &versionDir : qtForPythonDir.dirEntries(QDir::Dirs | QDir::NoDotAndDotDot)) { + FilePath requirements = versionDir.pathAppended("requirements.txt"); + if (requirements.exists()) + availablePySides[QVersionNumber::fromString(versionDir.fileName())] = requirements; + } + } + auto install = new PipInstallTask(python); connect(install, &PipInstallTask::finished, install, &QObject::deleteLater); @@ -87,7 +104,40 @@ void PySideInstaller::installPyside(const FilePath &python, if (success) emit pySideInstalled(python, pySide); }); - install->setPackages({PipPackage(pySide)}); + if (qtInstallDir->isEmpty()) { + install->setPackages({PipPackage(pySide)}); + } else { + QDialog dialog; + dialog.setWindowTitle(Tr::tr("Select PySide version")); + dialog.setLayout(new QVBoxLayout()); + dialog.layout()->addWidget(new QLabel(Tr::tr("Select which PySide version to install:"))); + QComboBox *pySideSelector = new QComboBox(); + pySideSelector->addItem(Tr::tr("Latest PySide from the Python Package Index")); + for (const Utils::FilePath &version : availablePySides) { + const FilePath dir = version.parentDir(); + const QString text + = Tr::tr("PySide %1 wheel (%2)").arg(dir.fileName(), dir.toUserOutput()); + pySideSelector->addItem(text, version.toVariant()); + } + dialog.layout()->addWidget(pySideSelector); + QDialogButtonBox box; + box.setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + dialog.layout()->addWidget(&box); + connect(&box, &QDialogButtonBox::accepted, &dialog, &QDialog::accept); + connect(&box, &QDialogButtonBox::rejected, &dialog, &QDialog::reject); + + if (dialog.exec() == QDialog::Rejected) + return; + + const FilePath requirementsFile = FilePath::fromVariant(pySideSelector->currentData()); + if (requirementsFile.isEmpty()) { + install->setPackages({PipPackage(pySide)}); + } else { + install->setWorkingDirectory(requirementsFile.parentDir()); + install->setRequirements(requirementsFile); + } + } + document->infoBar()->removeInfo(installPySideInfoBarId); install->run(); } diff --git a/src/plugins/python/python.qbs b/src/plugins/python/python.qbs index 5186dafcdcd..dd7aba1b697 100644 --- a/src/plugins/python/python.qbs +++ b/src/plugins/python/python.qbs @@ -9,10 +9,11 @@ QtcPlugin { Depends { name: "Utils" } Depends { name: "Core" } - Depends { name: "TextEditor" } - Depends { name: "ProjectExplorer" } Depends { name: "LanguageClient" } Depends { name: "LanguageServerProtocol" } + Depends { name: "ProjectExplorer" } + Depends { name: "QtSupport" } + Depends { name: "TextEditor" } Group { name: "General" diff --git a/src/plugins/qmlpreview/tests/qmlpreviewplugin_test.cpp b/src/plugins/qmlpreview/tests/qmlpreviewplugin_test.cpp index 21e1dd18466..2b06bd12e0d 100644 --- a/src/plugins/qmlpreview/tests/qmlpreviewplugin_test.cpp +++ b/src/plugins/qmlpreview/tests/qmlpreviewplugin_test.cpp @@ -15,8 +15,7 @@ Q_DECLARE_METATYPE(QmlPreview::TestFpsHandler) namespace QmlPreview { QmlPreviewPluginTest::QmlPreviewPluginTest(QObject *parent) : QObject(parent) -{ -} +{ } static ExtensionSystem::IPlugin *getPlugin() { diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp index 322de3ba480..bd41cfd068d 100644 --- a/src/plugins/qtsupport/qtoptionspage.cpp +++ b/src/plugins/qtsupport/qtoptionspage.cpp @@ -52,7 +52,8 @@ using namespace Utils; const char kInstallSettingsKey[] = "Settings/InstallSettings"; -namespace QtSupport::Internal { +namespace QtSupport { +namespace Internal { class QtVersionItem : public TreeItem { @@ -869,7 +870,7 @@ void QtOptionsPageWidget::setupLinkWithQtButton() const bool canLink = canLinkWithQt(&tip); m_linkWithQtButton->setEnabled(canLink); m_linkWithQtButton->setToolTip(tip); - connect(m_linkWithQtButton, &QPushButton::clicked, this, &QtOptionsPage::linkWithQt); + connect(m_linkWithQtButton, &QPushButton::clicked, this, &LinkWithQtSupport::linkWithQt); } void QtOptionsPageWidget::updateCurrentQtName() @@ -1080,19 +1081,26 @@ QStringList QtOptionsPage::keywords() const }; } -bool QtOptionsPage::canLinkWithQt() +} // Internal + +bool LinkWithQtSupport::canLinkWithQt() { return Internal::canLinkWithQt(nullptr); } -bool QtOptionsPage::isLinkedWithQt() +bool LinkWithQtSupport::isLinkedWithQt() { - return currentlyLinkedQtDir(nullptr).has_value(); + return Internal::currentlyLinkedQtDir(nullptr).has_value(); } -void QtOptionsPage::linkWithQt() +Utils::FilePath LinkWithQtSupport::linkedQt() { - QtOptionsPageWidget::linkWithQt(); + return Internal::currentlyLinkedQtDir(nullptr).value_or(Utils::FilePath()); } -} // QtSupport::Internal +void LinkWithQtSupport::linkWithQt() +{ + Internal::QtOptionsPageWidget::linkWithQt(); +} + +} // QtSupport diff --git a/src/plugins/qtsupport/qtoptionspage.h b/src/plugins/qtsupport/qtoptionspage.h index 8aa88ad5f3a..1ee0e28df8b 100644 --- a/src/plugins/qtsupport/qtoptionspage.h +++ b/src/plugins/qtsupport/qtoptionspage.h @@ -3,9 +3,12 @@ #pragma once +#include "qtsupport_global.h" + #include -namespace QtSupport::Internal { +namespace QtSupport { +namespace Internal { class QtOptionsPage final : public Core::IOptionsPage { @@ -14,9 +17,15 @@ public: QStringList keywords() const final; - static bool canLinkWithQt(); - static bool isLinkedWithQt(); - static void linkWithQt(); }; -} // QtSupport::Internal +} // QtSupport + +namespace LinkWithQtSupport { +QTSUPPORT_EXPORT bool canLinkWithQt(); +QTSUPPORT_EXPORT bool isLinkedWithQt(); +QTSUPPORT_EXPORT Utils::FilePath linkedQt(); +QTSUPPORT_EXPORT void linkWithQt(); +} + +} // Internal diff --git a/src/plugins/qtsupport/qtsupportplugin.cpp b/src/plugins/qtsupport/qtsupportplugin.cpp index 9a6875f3864..93a62f0deb4 100644 --- a/src/plugins/qtsupport/qtsupportplugin.cpp +++ b/src/plugins/qtsupport/qtsupportplugin.cpp @@ -143,7 +143,7 @@ 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 (!QtOptionsPage::canLinkWithQt() || QtOptionsPage::isLinkedWithQt() + if (!LinkWithQtSupport::canLinkWithQt() || LinkWithQtSupport::isLinkedWithQt() || !ICore::infoBar()->canInfoBeAdded(kLinkWithQtInstallationSetting)) return; @@ -155,7 +155,7 @@ static void askAboutQtInstallation() Utils::InfoBarEntry::GlobalSuppression::Enabled); info.addCustomButton(Tr::tr("Link with Qt"), [] { ICore::infoBar()->removeInfo(kLinkWithQtInstallationSetting); - QTimer::singleShot(0, ICore::dialogParent(), &QtOptionsPage::linkWithQt); + QTimer::singleShot(0, ICore::dialogParent(), &LinkWithQtSupport::linkWithQt); }); ICore::infoBar()->addInfo(info); }