diff --git a/src/plugins/projectexplorer/runconfigurationaspects.cpp b/src/plugins/projectexplorer/runconfigurationaspects.cpp index 09499c8d060..1810bb03b51 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.cpp +++ b/src/plugins/projectexplorer/runconfigurationaspects.cpp @@ -807,6 +807,13 @@ void InterpreterAspect::updateInterpreters(const QList &interpreter updateComboBox(); } +void InterpreterAspect::setDefaultInterpreter(const Interpreter &interpreter) +{ + m_defaultId = interpreter.id; + if (m_currentId.isEmpty()) + m_currentId = m_defaultId; +} + void InterpreterAspect::setCurrentInterpreter(const Interpreter &interpreter) { m_currentId = interpreter.id; @@ -820,7 +827,8 @@ void InterpreterAspect::fromMap(const QVariantMap &map) void InterpreterAspect::toMap(QVariantMap &map) const { - saveToMap(map, m_currentId, QString(), settingsKey()); + if (m_currentId != m_defaultId) + saveToMap(map, m_currentId, QString(), settingsKey()); } void InterpreterAspect::addToLayout(LayoutBuilder &builder) diff --git a/src/plugins/projectexplorer/runconfigurationaspects.h b/src/plugins/projectexplorer/runconfigurationaspects.h index cb3a86c79d9..4d1e84b59bf 100644 --- a/src/plugins/projectexplorer/runconfigurationaspects.h +++ b/src/plugins/projectexplorer/runconfigurationaspects.h @@ -244,7 +244,7 @@ public: Interpreter currentInterpreter() const; void updateInterpreters(const QList &interpreters); - void setDefaultInterpreter(const Interpreter &interpreter) { m_defaultId = interpreter.id; } + void setDefaultInterpreter(const Interpreter &interpreter); void setCurrentInterpreter(const Interpreter &interpreter); void setSettingsDialogId(Utils::Id id) { m_settingsDialogId = id; } diff --git a/src/plugins/python/CMakeLists.txt b/src/plugins/python/CMakeLists.txt index dad146f3217..bd71f4fbb23 100644 --- a/src/plugins/python/CMakeLists.txt +++ b/src/plugins/python/CMakeLists.txt @@ -4,6 +4,7 @@ add_qtc_plugin(Python SOURCES pipsupport.cpp pipsupport.h pyside.cpp pyside.h + pysidebuildconfiguration.cpp pysidebuildconfiguration.h python.qrc pythonconstants.h pythoneditor.cpp pythoneditor.h diff --git a/src/plugins/python/pysidebuildconfiguration.cpp b/src/plugins/python/pysidebuildconfiguration.cpp new file mode 100644 index 00000000000..c344d0d1708 --- /dev/null +++ b/src/plugins/python/pysidebuildconfiguration.cpp @@ -0,0 +1,134 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "pysidebuildconfiguration.h" + +#include "pipsupport.h" +#include "pythonconstants.h" +#include "pythonproject.h" +#include "pythonrunconfiguration.h" +#include "pythonsettings.h" + +#include +#include +#include +#include +#include +#include +#include + +using namespace ProjectExplorer; +using namespace Utils; + +namespace Python { +namespace Internal { + +constexpr char pySideBuildStep[] = "Python.PysideBuildStep"; + +PySideBuildConfigurationFactory::PySideBuildConfigurationFactory() +{ + registerBuildConfiguration("Python.PySideBuildConfiguration"); + setSupportedProjectType(PythonProjectId); + setSupportedProjectMimeTypeName(Constants::C_PY_MIMETYPE); + setBuildGenerator([](const Kit *, const FilePath &projectPath, bool) { + BuildInfo info; + info.displayName = "build"; + info.typeName = "build"; + info.buildDirectory = projectPath.parentDir(); + return QList{info}; + }); +} + +PySideBuildStepFactory::PySideBuildStepFactory() +{ + registerStep(pySideBuildStep); + setSupportedProjectType(PythonProjectId); + setDisplayName(tr("Run PySide6 project tool")); + setFlags(BuildStepInfo::UniqueStep); +} + +PySideBuildStep::PySideBuildStep(BuildStepList *bsl, Id id) + : AbstractProcessStep(bsl, id) +{ + m_pysideProject = addAspect(); + m_pysideProject->setSettingsKey("Python.PySideProjectTool"); + m_pysideProject->setLabelText(tr("PySide project tool:")); + m_pysideProject->setToolTip(tr("Enter location of PySide project tool.")); + m_pysideProject->setDisplayStyle(StringAspect::PathChooserDisplay); + m_pysideProject->setExpectedKind(PathChooser::Command); + m_pysideProject->setHistoryCompleter("Python.PySideProjectTool.History"); + + const FilePath pySideProjectPath = Environment::systemEnvironment().searchInPath( + "pyside6-project"); + if (pySideProjectPath.isExecutableFile()) + m_pysideProject->setFilePath(pySideProjectPath); + + setCommandLineProvider([this] { return CommandLine(m_pysideProject->filePath(), {"build"}); }); + setWorkingDirectoryProvider([this] { return target()->project()->projectDirectory(); }); +} + +void PySideBuildStep::updateInterpreter(const Utils::FilePath &python) +{ + Utils::FilePath pySideProjectPath; + const PipPackage pySide6Package("PySide6"); + const PipPackageInfo info = pySide6Package.info(python); + for (const FilePath &file : qAsConst(info.files)) { + if (file.fileName() == HostOsInfo::withExecutableSuffix("pyside6-project")) { + pySideProjectPath = info.location.resolvePath(file); + pySideProjectPath = pySideProjectPath.cleanPath(); + break; + } + } + + if (!pySideProjectPath.isExecutableFile()) + pySideProjectPath = Environment::systemEnvironment().searchInPath("pyside6-project"); + + if (pySideProjectPath.isExecutableFile()) + m_pysideProject->setFilePath(pySideProjectPath); +} + +void PySideBuildStep::doRun() +{ + if (processParameters()->effectiveCommand().isExecutableFile()) + AbstractProcessStep::doRun(); + else + emit finished(true); +} + +PySideBuildConfiguration::PySideBuildConfiguration(Target *target, Id id) + : BuildConfiguration(target, id) +{ + setConfigWidgetDisplayName(tr("General")); + + setInitializer([this](const BuildInfo &) { + buildSteps()->appendStep(pySideBuildStep); + updateCacheAndEmitEnvironmentChanged(); + }); + + updateCacheAndEmitEnvironmentChanged(); +} + +} // namespace Internal +} // namespace Python diff --git a/src/plugins/python/pysidebuildconfiguration.h b/src/plugins/python/pysidebuildconfiguration.h new file mode 100644 index 00000000000..943c995f472 --- /dev/null +++ b/src/plugins/python/pysidebuildconfiguration.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2022 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include +#include +#include + +namespace Python { +namespace Internal { + +class PySideBuildConfiguration : public ProjectExplorer::BuildConfiguration +{ +public: + PySideBuildConfiguration(ProjectExplorer::Target *target, Utils::Id id); +}; + +class PySideBuildConfigurationFactory : public ProjectExplorer::BuildConfigurationFactory +{ + Q_DECLARE_TR_FUNCTIONS(Python::Internal::PySideBuildConfigurationFactory) +public: + PySideBuildConfigurationFactory(); +}; + +class PySideBuildStep : public ProjectExplorer::AbstractProcessStep +{ + Q_OBJECT +public: + PySideBuildStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id); + void updateInterpreter(const Utils::FilePath &python); + +private: + Utils::StringAspect *m_pysideProject; + +private: + void doRun() override; +}; + +class PySideBuildStepFactory : public ProjectExplorer::BuildStepFactory +{ + Q_DECLARE_TR_FUNCTIONS(Python::Internal::PySideBuildStepFactory) +public: + PySideBuildStepFactory(); +}; + +} // namespace Internal +} // namespace Python diff --git a/src/plugins/python/python.qbs b/src/plugins/python/python.qbs index 3f14f992baf..a19e9939e37 100644 --- a/src/plugins/python/python.qbs +++ b/src/plugins/python/python.qbs @@ -21,6 +21,8 @@ QtcPlugin { "pipsupport.h", "pyside.cpp", "pyside.h", + "pysidebuildconfiguration.cpp", + "pysidebuildconfiguration.h", "python.qrc", "pythonconstants.h", "pythoneditor.cpp", diff --git a/src/plugins/python/pythonplugin.cpp b/src/plugins/python/pythonplugin.cpp index e0029b64a2d..5f839ea5918 100644 --- a/src/plugins/python/pythonplugin.cpp +++ b/src/plugins/python/pythonplugin.cpp @@ -25,6 +25,7 @@ #include "pythonplugin.h" +#include "pysidebuildconfiguration.h" #include "pythonconstants.h" #include "pythoneditor.h" #include "pythonlanguageclient.h" @@ -61,6 +62,8 @@ public: PythonEditorFactory editorFactory; PythonOutputFormatterFactory outputFormatterFactory; PythonRunConfigurationFactory runConfigFactory; + PySideBuildStepFactory buildStepFactory; + PySideBuildConfigurationFactory buildConfigFactory; RunWorkerFactory runWorkerFactory{ RunWorkerFactory::make(), diff --git a/src/plugins/python/pythonproject.cpp b/src/plugins/python/pythonproject.cpp index 69f3b52a0af..cafaf401ff9 100644 --- a/src/plugins/python/pythonproject.cpp +++ b/src/plugins/python/pythonproject.cpp @@ -220,7 +220,6 @@ PythonProject::PythonProject(const FilePath &fileName) setProjectLanguages(Context(ProjectExplorer::Constants::PYTHON_LANGUAGE_ID)); setDisplayName(fileName.completeBaseName()); - setNeedsBuildConfigurations(false); setBuildSystemCreator([](Target *t) { return new PythonBuildSystem(t); }); } diff --git a/src/plugins/python/pythonrunconfiguration.cpp b/src/plugins/python/pythonrunconfiguration.cpp index e3a100486d6..1bd7fd90b22 100644 --- a/src/plugins/python/pythonrunconfiguration.cpp +++ b/src/plugins/python/pythonrunconfiguration.cpp @@ -26,6 +26,7 @@ #include "pythonrunconfiguration.h" #include "pyside.h" +#include "pysidebuildconfiguration.h" #include "pythonconstants.h" #include "pythonlanguageclient.h" #include "pythonproject.h" @@ -36,6 +37,7 @@ #include +#include #include #include #include @@ -145,27 +147,21 @@ public: interpreterAspect->setSettingsKey("PythonEditor.RunConfiguation.Interpreter"); interpreterAspect->setSettingsDialogId(Constants::C_PYTHONOPTIONS_PAGE_ID); - connect(interpreterAspect, &InterpreterAspect::changed, this, [this, interpreterAspect] { - using namespace LanguageClient; - const FilePath python = interpreterAspect->currentInterpreter().command; - - for (FilePath &file : project()->files(Project::AllFiles)) { - if (auto document = TextEditor::TextDocument::textDocumentForFilePath(file)) { - if (document->mimeType() == Constants::C_PY_MIMETYPE) { - PyLSConfigureAssistant::openDocumentWithPython(python, document); - PySideInstaller::checkPySideInstallation(python, document); - } - } - } - }); + connect(interpreterAspect, &InterpreterAspect::changed, + this, &PythonRunConfiguration::currentInterpreterChanged); connect(PythonSettings::instance(), &PythonSettings::interpretersChanged, interpreterAspect, &InterpreterAspect::updateInterpreters); - QList interpreters = PythonSettings::detectPythonVenvs(project()->projectDirectory()); + QList interpreters = PythonSettings::detectPythonVenvs( + project()->projectDirectory()); interpreterAspect->updateInterpreters(PythonSettings::interpreters()); - interpreterAspect->setDefaultInterpreter( - interpreters.isEmpty() ? PythonSettings::defaultInterpreter() : interpreters.first()); + Interpreter defaultInterpreter = interpreters.isEmpty() + ? PythonSettings::defaultInterpreter() + : interpreters.first(); + if (!defaultInterpreter.command.isExecutableFile()) + defaultInterpreter = PythonSettings::interpreters().value(0); + interpreterAspect->setDefaultInterpreter(defaultInterpreter); auto bufferedAspect = addAspect(); bufferedAspect->setSettingsKey("PythonEditor.RunConfiguation.Buffered"); @@ -204,6 +200,24 @@ public: connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update); } + + void currentInterpreterChanged() + { + const FilePath python = aspect()->currentInterpreter().command; + + BuildStepList *buildSteps = target()->activeBuildConfiguration()->buildSteps(); + if (auto pySideBuildStep = buildSteps->firstOfType()) + pySideBuildStep->updateInterpreter(python); + + for (FilePath &file : project()->files(Project::AllFiles)) { + if (auto document = TextEditor::TextDocument::textDocumentForFilePath(file)) { + if (document->mimeType() == Constants::C_PY_MIMETYPE) { + PyLSConfigureAssistant::openDocumentWithPython(python, document); + PySideInstaller::checkPySideInstallation(python, document); + } + } + } + } }; PythonRunConfigurationFactory::PythonRunConfigurationFactory()