forked from qt-creator/qt-creator
Python: use kits page in python wizards
Change-Id: I1f7aaf145443481546abb868c8c167186600b848 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -13,7 +13,8 @@
|
||||
"options":
|
||||
[
|
||||
{ "key": "SrcFileName", "value": "main.py" },
|
||||
{ "key": "PyProjectFile", "value": "%{JS: Util.fileName('%{ProjectName}', 'pyproject')}" }
|
||||
{ "key": "PyProjectFile", "value": "%{JS: Util.fileName('%{ProjectName}', 'pyproject')}" },
|
||||
{ "key": "ProjectFilePath", "value": "%{ProjectDirectory}/%{PyProjectFile}" }
|
||||
],
|
||||
|
||||
"pages":
|
||||
@@ -49,6 +50,15 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"trDisplayName": "Kit Selection",
|
||||
"trShortTitle": "Kits",
|
||||
"typeId": "Kits",
|
||||
"data": {
|
||||
"projectFilePath": "%{ProjectFilePath}",
|
||||
"requiredFeatures": [ "Python.Interpreter" ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"trDisplayName": "Project Management",
|
||||
"trShortTitle": "Summary",
|
||||
|
@@ -13,7 +13,8 @@
|
||||
"options":
|
||||
[
|
||||
{ "key": "MainPyFileName", "value": "%{ProjectDirectory}/%{SrcFileName}" },
|
||||
{ "key": "PyProjectFile", "value": "%{ProjectDirectory}/%{ProjectFileName}" }
|
||||
{ "key": "PyProjectFile", "value": "%{ProjectFileName}" },
|
||||
{ "key": "ProjectFilePath", "value": "%{ProjectDirectory}/%{PyProjectFile}" }
|
||||
],
|
||||
|
||||
"pages":
|
||||
@@ -93,6 +94,15 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"trDisplayName": "Kit Selection",
|
||||
"trShortTitle": "Kits",
|
||||
"typeId": "Kits",
|
||||
"data": {
|
||||
"projectFilePath": "%{ProjectFilePath}",
|
||||
"requiredFeatures": [ "Python.Interpreter" ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"trDisplayName": "Project Management",
|
||||
"trShortTitle": "Summary",
|
||||
|
@@ -17,7 +17,8 @@
|
||||
{ "key": "PyProjectFile", "value": "%{JS: Util.fileName('%{ProjectName}', 'pyproject')}" },
|
||||
{ "key": "QtQuickVersion", "value": "%{JS: value('QtVersion').QtQuickVersion}" },
|
||||
{ "key": "QtQuickWindowVersion", "value": "%{JS: value('QtVersion').QtQuickWindowVersion}" },
|
||||
{ "key": "PySideVersion", "value": "%{JS: value('QtVersion').PySideVersion}" }
|
||||
{ "key": "PySideVersion", "value": "%{JS: value('QtVersion').PySideVersion}" },
|
||||
{ "key": "ProjectFilePath", "value": "%{ProjectDirectory}/%{PyProjectFile}" }
|
||||
],
|
||||
|
||||
"pages":
|
||||
@@ -84,6 +85,15 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"trDisplayName": "Kit Selection",
|
||||
"trShortTitle": "Kits",
|
||||
"typeId": "Kits",
|
||||
"data": {
|
||||
"projectFilePath": "%{ProjectFilePath}",
|
||||
"requiredFeatures": [ "Python.Interpreter" ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"trDisplayName": "Project Management",
|
||||
"trShortTitle": "Summary",
|
||||
|
@@ -13,7 +13,8 @@
|
||||
"options":
|
||||
[
|
||||
{ "key": "SrcFileName", "value": "%{MainFileName}" },
|
||||
{ "key": "PyProjectFile", "value": "%{ProjectFileName}" }
|
||||
{ "key": "PyProjectFile", "value": "%{ProjectFileName}" },
|
||||
{ "key": "ProjectFilePath", "value": "%{ProjectDirectory}/%{PyProjectFile}" }
|
||||
],
|
||||
|
||||
"pages":
|
||||
@@ -93,6 +94,15 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"trDisplayName": "Kit Selection",
|
||||
"trShortTitle": "Kits",
|
||||
"typeId": "Kits",
|
||||
"data": {
|
||||
"projectFilePath": "%{ProjectFilePath}",
|
||||
"requiredFeatures": [ "Python.Interpreter" ]
|
||||
}
|
||||
},
|
||||
{
|
||||
"trDisplayName": "Project Management",
|
||||
"trShortTitle": "Summary",
|
||||
|
@@ -908,10 +908,10 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm
|
||||
m_runParameters.nativeMixedEnabled = bool(nativeMixedOverride);
|
||||
|
||||
|
||||
if (auto interpreterAspect = runControl->aspect<InterpreterAspect>()) {
|
||||
if (auto interpreterAspect = runControl->aspect<FilePathAspect>()) {
|
||||
if (auto mainScriptAspect = runControl->aspect<MainScriptAspect>()) {
|
||||
const FilePath mainScript = mainScriptAspect->filePath;
|
||||
const FilePath interpreter = interpreterAspect->interpreter.command;
|
||||
const FilePath interpreter = interpreterAspect->filePath;
|
||||
if (!interpreter.isEmpty() && mainScript.endsWith(".py")) {
|
||||
m_runParameters.mainScript = mainScript;
|
||||
m_runParameters.interpreter = interpreter;
|
||||
|
@@ -4,7 +4,7 @@ add_qtc_plugin(Python
|
||||
SOURCES
|
||||
pipsupport.cpp pipsupport.h
|
||||
pyside.cpp pyside.h
|
||||
pysidebuildconfiguration.cpp pysidebuildconfiguration.h
|
||||
pythonbuildconfiguration.cpp pythonbuildconfiguration.h
|
||||
pysideuicextracompiler.cpp pysideuicextracompiler.h
|
||||
python.qrc
|
||||
pythonbuildsystem.cpp pythonbuildsystem.h
|
||||
|
@@ -46,6 +46,10 @@ void PySideInstaller::checkPySideInstallation(const FilePath &python,
|
||||
TextEditor::TextDocument *document)
|
||||
{
|
||||
document->infoBar()->removeInfo(installPySideInfoBarId);
|
||||
if (QPointer<QFutureWatcher<bool>> watcher = instance()->m_futureWatchers.value(document))
|
||||
watcher->cancel();
|
||||
if (!python.exists())
|
||||
return;
|
||||
const QString pySide = importedPySide(document->plainText());
|
||||
if (pySide == "PySide2" || pySide == "PySide6")
|
||||
instance()->runPySideChecker(python, pySide, document);
|
||||
@@ -186,10 +190,8 @@ void PySideInstaller::runPySideChecker(const FilePath &python,
|
||||
|
||||
// cancel and delete watcher after a 10 second timeout
|
||||
QTimer::singleShot(10000, this, [watcher]() {
|
||||
if (watcher) {
|
||||
if (watcher)
|
||||
watcher->cancel();
|
||||
watcher->deleteLater();
|
||||
}
|
||||
});
|
||||
connect(watcher,
|
||||
&CheckPySideWatcher::resultReadyAt,
|
||||
@@ -197,9 +199,13 @@ void PySideInstaller::runPySideChecker(const FilePath &python,
|
||||
[=, document = QPointer<TextEditor::TextDocument>(document)]() {
|
||||
if (watcher->result())
|
||||
handlePySideMissing(python, pySide, document);
|
||||
watcher->deleteLater();
|
||||
});
|
||||
connect(watcher, &CheckPySideWatcher::finished, watcher, &CheckPySideWatcher::deleteLater);
|
||||
connect(watcher, &CheckPySideWatcher::finished, this, [this, document]{
|
||||
m_futureWatchers.remove(document);
|
||||
});
|
||||
watcher->setFuture(Utils::asyncRun(&missingPySideInstallation, python, pySide));
|
||||
m_futureWatchers[document] = watcher;
|
||||
}
|
||||
|
||||
} // Python::Internal
|
||||
|
@@ -6,6 +6,8 @@
|
||||
#include <utils/filepath.h>
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QFutureWatcher>
|
||||
#include <QPointer>
|
||||
#include <QTextDocument>
|
||||
|
||||
namespace TextEditor { class TextDocument; }
|
||||
@@ -13,6 +15,13 @@ namespace ProjectExplorer { class RunConfiguration; }
|
||||
|
||||
namespace Python::Internal {
|
||||
|
||||
class PySideTools
|
||||
{
|
||||
public:
|
||||
Utils::FilePath pySideProjectPath;
|
||||
Utils::FilePath pySideUicPath;
|
||||
};
|
||||
|
||||
class PySideInstaller : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -41,6 +50,7 @@ private:
|
||||
static QString importedPySide(const QString &text);
|
||||
|
||||
QHash<Utils::FilePath, QList<TextEditor::TextDocument *>> m_infoBarEntries;
|
||||
QHash<TextEditor::TextDocument *, QPointer<QFutureWatcher<bool>>> m_futureWatchers;
|
||||
};
|
||||
|
||||
} // Python::Internal
|
||||
|
@@ -1,108 +0,0 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "pysidebuildconfiguration.h"
|
||||
|
||||
#include "pythonconstants.h"
|
||||
#include "pythonproject.h"
|
||||
#include "pythontr.h"
|
||||
|
||||
#include <projectexplorer/buildinfo.h>
|
||||
#include <projectexplorer/buildsteplist.h>
|
||||
#include <projectexplorer/environmentaspect.h>
|
||||
#include <projectexplorer/processparameters.h>
|
||||
#include <projectexplorer/runconfiguration.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <utils/commandline.h>
|
||||
#include <utils/process.h>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
namespace Python::Internal {
|
||||
|
||||
const char pySideBuildStep[] = "Python.PysideBuildStep";
|
||||
|
||||
PySideBuildStepFactory::PySideBuildStepFactory()
|
||||
{
|
||||
registerStep<PySideBuildStep>(pySideBuildStep);
|
||||
setSupportedProjectType(PythonProjectId);
|
||||
setDisplayName(Tr::tr("Run PySide6 project tool"));
|
||||
setFlags(BuildStep::UniqueStep);
|
||||
}
|
||||
|
||||
PySideBuildStep::PySideBuildStep(BuildStepList *bsl, Id id)
|
||||
: AbstractProcessStep(bsl, id)
|
||||
{
|
||||
m_pysideProject.setSettingsKey("Python.PySideProjectTool");
|
||||
m_pysideProject.setLabelText(Tr::tr("PySide project tool:"));
|
||||
m_pysideProject.setToolTip(Tr::tr("Enter location of PySide project tool."));
|
||||
m_pysideProject.setExpectedKind(PathChooser::Command);
|
||||
m_pysideProject.setHistoryCompleter("Python.PySideProjectTool.History");
|
||||
|
||||
const FilePath pySideProjectPath = FilePath("pyside6-project").searchInPath();
|
||||
if (pySideProjectPath.isExecutableFile())
|
||||
m_pysideProject.setValue(pySideProjectPath);
|
||||
|
||||
setCommandLineProvider([this] { return CommandLine(m_pysideProject(), {"build"}); });
|
||||
setWorkingDirectoryProvider([this] {
|
||||
return m_pysideProject().withNewMappedPath(project()->projectDirectory()); // FIXME: new path needed?
|
||||
});
|
||||
setEnvironmentModifier([this](Environment &env) {
|
||||
env.prependOrSetPath(m_pysideProject().parentDir());
|
||||
});
|
||||
}
|
||||
|
||||
void PySideBuildStep::updatePySideProjectPath(const FilePath &pySideProjectPath)
|
||||
{
|
||||
m_pysideProject.setValue(pySideProjectPath);
|
||||
}
|
||||
|
||||
Tasking::GroupItem PySideBuildStep::runRecipe()
|
||||
{
|
||||
using namespace Tasking;
|
||||
|
||||
const auto onSetup = [this] {
|
||||
if (!processParameters()->effectiveCommand().isExecutableFile())
|
||||
return SetupResult::StopWithSuccess;
|
||||
return SetupResult::Continue;
|
||||
};
|
||||
|
||||
return Group { onGroupSetup(onSetup), defaultProcessTask() };
|
||||
}
|
||||
|
||||
// PySideBuildConfiguration
|
||||
|
||||
class PySideBuildConfiguration : public BuildConfiguration
|
||||
{
|
||||
public:
|
||||
PySideBuildConfiguration(Target *target, Id id)
|
||||
: BuildConfiguration(target, id)
|
||||
{
|
||||
setConfigWidgetDisplayName(Tr::tr("General"));
|
||||
|
||||
setInitializer([this](const BuildInfo &) {
|
||||
buildSteps()->appendStep(pySideBuildStep);
|
||||
updateCacheAndEmitEnvironmentChanged();
|
||||
});
|
||||
|
||||
updateCacheAndEmitEnvironmentChanged();
|
||||
}
|
||||
};
|
||||
|
||||
PySideBuildConfigurationFactory::PySideBuildConfigurationFactory()
|
||||
{
|
||||
registerBuildConfiguration<PySideBuildConfiguration>("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<BuildInfo>{info};
|
||||
});
|
||||
}
|
||||
|
||||
} // Python::Internal
|
@@ -1,37 +0,0 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <projectexplorer/abstractprocessstep.h>
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
#include <projectexplorer/buildstep.h>
|
||||
|
||||
namespace Python::Internal {
|
||||
|
||||
class PySideBuildStep : public ProjectExplorer::AbstractProcessStep
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PySideBuildStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id);
|
||||
void updatePySideProjectPath(const Utils::FilePath &pySideProjectPath);
|
||||
|
||||
private:
|
||||
Tasking::GroupItem runRecipe() final;
|
||||
|
||||
Utils::FilePathAspect m_pysideProject{this};
|
||||
};
|
||||
|
||||
class PySideBuildStepFactory : public ProjectExplorer::BuildStepFactory
|
||||
{
|
||||
public:
|
||||
PySideBuildStepFactory();
|
||||
};
|
||||
|
||||
class PySideBuildConfigurationFactory : public ProjectExplorer::BuildConfigurationFactory
|
||||
{
|
||||
public:
|
||||
PySideBuildConfigurationFactory();
|
||||
};
|
||||
|
||||
} // Python::Internal
|
@@ -22,8 +22,8 @@ QtcPlugin {
|
||||
"pipsupport.h",
|
||||
"pyside.cpp",
|
||||
"pyside.h",
|
||||
"pysidebuildconfiguration.cpp",
|
||||
"pysidebuildconfiguration.h",
|
||||
"pythonbuildconfiguration.cpp",
|
||||
"pythonbuildconfiguration.h",
|
||||
"pysideuicextracompiler.cpp",
|
||||
"pysideuicextracompiler.h",
|
||||
"python.qrc",
|
||||
|
415
src/plugins/python/pythonbuildconfiguration.cpp
Normal file
415
src/plugins/python/pythonbuildconfiguration.cpp
Normal file
@@ -0,0 +1,415 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "pythonbuildconfiguration.h"
|
||||
|
||||
#include "pipsupport.h"
|
||||
#include "pyside.h"
|
||||
#include "pysideuicextracompiler.h"
|
||||
#include "pythonconstants.h"
|
||||
#include "pythoneditor.h"
|
||||
#include "pythonkitaspect.h"
|
||||
#include "pythonlanguageclient.h"
|
||||
#include "pythonproject.h"
|
||||
#include "pythonsettings.h"
|
||||
#include "pythontr.h"
|
||||
#include "pythonutils.h"
|
||||
|
||||
#include <coreplugin/editormanager/documentmodel.h>
|
||||
|
||||
#include <languageclient/languageclientmanager.h>
|
||||
|
||||
#include <projectexplorer/buildinfo.h>
|
||||
#include <projectexplorer/buildsteplist.h>
|
||||
#include <projectexplorer/buildsystem.h>
|
||||
#include <projectexplorer/environmentaspect.h>
|
||||
#include <projectexplorer/namedwidget.h>
|
||||
#include <projectexplorer/processparameters.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/projectnodes.h>
|
||||
#include <projectexplorer/runconfiguration.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/commandline.h>
|
||||
#include <utils/detailswidget.h>
|
||||
#include <utils/futuresynchronizer.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
#include <utils/process.h>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
namespace Python::Internal {
|
||||
|
||||
PySideBuildStepFactory::PySideBuildStepFactory()
|
||||
{
|
||||
registerStep<PySideBuildStep>(PySideBuildStep::id());
|
||||
setSupportedProjectType(PythonProjectId);
|
||||
setDisplayName(Tr::tr("Run PySide6 project tool"));
|
||||
setFlags(BuildStep::UniqueStep);
|
||||
}
|
||||
|
||||
PySideBuildStep::PySideBuildStep(BuildStepList *bsl, Id id)
|
||||
: AbstractProcessStep(bsl, id)
|
||||
{
|
||||
m_pysideProject.setSettingsKey("Python.PySideProjectTool");
|
||||
m_pysideProject.setLabelText(Tr::tr("PySide project tool:"));
|
||||
m_pysideProject.setToolTip(Tr::tr("Enter location of PySide project tool."));
|
||||
m_pysideProject.setExpectedKind(PathChooser::Command);
|
||||
m_pysideProject.setHistoryCompleter("Python.PySideProjectTool.History");
|
||||
m_pysideProject.setReadOnly(true);
|
||||
|
||||
m_pysideUic.setSettingsKey("Python.PySideUic");
|
||||
m_pysideUic.setLabelText(Tr::tr("PySide uic tool:"));
|
||||
m_pysideUic.setToolTip(Tr::tr("Enter location of PySide uic tool."));
|
||||
m_pysideUic.setExpectedKind(PathChooser::Command);
|
||||
m_pysideUic.setHistoryCompleter("Python.PySideUic.History");
|
||||
m_pysideUic.setReadOnly(true);
|
||||
|
||||
setCommandLineProvider([this] { return CommandLine(m_pysideProject(), {"build"}); });
|
||||
setWorkingDirectoryProvider([this] {
|
||||
return m_pysideProject().withNewMappedPath(project()->projectDirectory()); // FIXME: new path needed?
|
||||
});
|
||||
setEnvironmentModifier([this](Environment &env) {
|
||||
env.prependOrSetPath(m_pysideProject().parentDir());
|
||||
});
|
||||
|
||||
connect(target(), &Target::buildSystemUpdated, this, &PySideBuildStep::updateExtraCompilers);
|
||||
connect(&m_pysideUic, &BaseAspect::changed, this, &PySideBuildStep::updateExtraCompilers);
|
||||
}
|
||||
|
||||
PySideBuildStep::~PySideBuildStep()
|
||||
{
|
||||
qDeleteAll(m_extraCompilers);
|
||||
}
|
||||
|
||||
void PySideBuildStep::checkForPySide(const FilePath &python)
|
||||
{
|
||||
PySideTools tools;
|
||||
if (python.isEmpty() || !python.isExecutableFile()) {
|
||||
m_pysideProject.setValue(FilePath());
|
||||
m_pysideUic.setValue(FilePath());
|
||||
return;
|
||||
}
|
||||
const FilePath dir = python.parentDir();
|
||||
tools.pySideProjectPath = dir.pathAppended("pyside6-project").withExecutableSuffix();
|
||||
tools.pySideUicPath = dir.pathAppended("pyside6-uic").withExecutableSuffix();
|
||||
|
||||
if (tools.pySideProjectPath.isExecutableFile() && tools.pySideUicPath.isExecutableFile()) {
|
||||
m_pysideProject.setValue(tools.pySideProjectPath.toUserOutput());
|
||||
m_pysideUic.setValue(tools.pySideUicPath.toUserOutput());
|
||||
} else {
|
||||
checkForPySide(python, "PySide6-Essentials");
|
||||
}
|
||||
}
|
||||
|
||||
void PySideBuildStep::checkForPySide(const FilePath &python, const QString &pySidePackageName)
|
||||
{
|
||||
const PipPackage package(pySidePackageName);
|
||||
QObject::disconnect(m_watcherConnection);
|
||||
m_watcher.reset(new QFutureWatcher<PipPackageInfo>());
|
||||
m_watcherConnection = QObject::connect(m_watcher.get(), &QFutureWatcherBase::finished, this, [=] {
|
||||
handlePySidePackageInfo(m_watcher->result(), python, pySidePackageName);
|
||||
});
|
||||
const auto future = Pip::instance(python)->info(package);
|
||||
m_watcher->setFuture(future);
|
||||
ExtensionSystem::PluginManager::futureSynchronizer()->addFuture(future);
|
||||
}
|
||||
|
||||
void PySideBuildStep::handlePySidePackageInfo(const PipPackageInfo &pySideInfo,
|
||||
const FilePath &python,
|
||||
const QString &requestedPackageName)
|
||||
{
|
||||
const auto findPythonTools = [](const FilePaths &files,
|
||||
const FilePath &location,
|
||||
const FilePath &python) -> PySideTools {
|
||||
PySideTools result;
|
||||
const QString pySide6ProjectName
|
||||
= OsSpecificAspects::withExecutableSuffix(python.osType(), "pyside6-project");
|
||||
const QString pySide6UicName
|
||||
= OsSpecificAspects::withExecutableSuffix(python.osType(), "pyside6-uic");
|
||||
for (const FilePath &file : files) {
|
||||
if (file.fileName() == pySide6ProjectName) {
|
||||
result.pySideProjectPath = python.withNewMappedPath(location.resolvePath(file));
|
||||
result.pySideProjectPath = result.pySideProjectPath.cleanPath();
|
||||
if (!result.pySideUicPath.isEmpty())
|
||||
return result;
|
||||
} else if (file.fileName() == pySide6UicName) {
|
||||
result.pySideUicPath = python.withNewMappedPath(location.resolvePath(file));
|
||||
result.pySideUicPath = result.pySideUicPath.cleanPath();
|
||||
if (!result.pySideProjectPath.isEmpty())
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
PySideTools tools = findPythonTools(pySideInfo.files, pySideInfo.location, python);
|
||||
if (!tools.pySideProjectPath.isExecutableFile() && requestedPackageName != "PySide6") {
|
||||
checkForPySide(python, "PySide6");
|
||||
return;
|
||||
}
|
||||
|
||||
m_pysideProject.setValue(tools.pySideProjectPath.toUserOutput());
|
||||
m_pysideUic.setValue(tools.pySideUicPath.toUserOutput());
|
||||
}
|
||||
|
||||
Tasking::GroupItem PySideBuildStep::runRecipe()
|
||||
{
|
||||
using namespace Tasking;
|
||||
|
||||
const auto onSetup = [this] {
|
||||
if (!processParameters()->effectiveCommand().isExecutableFile())
|
||||
return SetupResult::StopWithSuccess;
|
||||
return SetupResult::Continue;
|
||||
};
|
||||
|
||||
return Group { onGroupSetup(onSetup), defaultProcessTask() };
|
||||
}
|
||||
|
||||
void PySideBuildStep::updateExtraCompilers()
|
||||
{
|
||||
QList<PySideUicExtraCompiler *> oldCompilers = m_extraCompilers;
|
||||
m_extraCompilers.clear();
|
||||
|
||||
if (m_pysideUic().isExecutableFile()) {
|
||||
auto uiMatcher = [](const Node *node) {
|
||||
if (const FileNode *fileNode = node->asFileNode())
|
||||
return fileNode->fileType() == FileType::Form;
|
||||
return false;
|
||||
};
|
||||
const FilePaths uiFiles = project()->files(uiMatcher);
|
||||
for (const FilePath &uiFile : uiFiles) {
|
||||
FilePath generated = uiFile.parentDir();
|
||||
generated = generated.pathAppended("/ui_" + uiFile.baseName() + ".py");
|
||||
int index = Utils::indexOf(oldCompilers, [&](PySideUicExtraCompiler *oldCompiler) {
|
||||
return oldCompiler->pySideUicPath() == m_pysideUic()
|
||||
&& oldCompiler->project() == project() && oldCompiler->source() == uiFile
|
||||
&& oldCompiler->targets() == FilePaths{generated};
|
||||
});
|
||||
if (index < 0) {
|
||||
m_extraCompilers << new PySideUicExtraCompiler(m_pysideUic(),
|
||||
project(),
|
||||
uiFile,
|
||||
{generated},
|
||||
this);
|
||||
} else {
|
||||
m_extraCompilers << oldCompilers.takeAt(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (LanguageClient::Client *client : LanguageClient::LanguageClientManager::clients()) {
|
||||
if (auto pylsClient = qobject_cast<PyLSClient *>(client))
|
||||
pylsClient->updateExtraCompilers(project(), m_extraCompilers);
|
||||
}
|
||||
qDeleteAll(oldCompilers);
|
||||
}
|
||||
|
||||
QList<PySideUicExtraCompiler *> PySideBuildStep::extraCompilers() const
|
||||
{
|
||||
return m_extraCompilers;
|
||||
}
|
||||
|
||||
Id PySideBuildStep::id()
|
||||
{
|
||||
return Id("Python.PysideBuildStep");
|
||||
}
|
||||
|
||||
class PythonBuildSettingsWidget : public NamedWidget
|
||||
{
|
||||
public:
|
||||
PythonBuildSettingsWidget(PythonBuildConfiguration *bc)
|
||||
: NamedWidget(Tr::tr("Python"))
|
||||
{
|
||||
using namespace Layouting;
|
||||
m_configureDetailsWidget = new DetailsWidget;
|
||||
m_configureDetailsWidget->setSummaryText(bc->python().toUserOutput());
|
||||
|
||||
if (const std::optional<FilePath> venv = bc->venv()) {
|
||||
auto details = new QWidget();
|
||||
Form{Tr::tr("Effective venv:"), venv->toUserOutput(), br}.attachTo(details);
|
||||
m_configureDetailsWidget->setWidget(details);
|
||||
} else {
|
||||
m_configureDetailsWidget->setState(DetailsWidget::OnlySummary);
|
||||
}
|
||||
|
||||
Column{
|
||||
m_configureDetailsWidget,
|
||||
noMargin
|
||||
}.attachTo(this);
|
||||
}
|
||||
private:
|
||||
DetailsWidget *m_configureDetailsWidget;
|
||||
};
|
||||
|
||||
PythonBuildConfiguration::PythonBuildConfiguration(Target *target, const Id &id)
|
||||
: BuildConfiguration(target, id)
|
||||
, m_buildSystem(std::make_unique<PythonBuildSystem>(this))
|
||||
{
|
||||
setInitializer([this](const BuildInfo &info) { initialize(info); });
|
||||
|
||||
updateCacheAndEmitEnvironmentChanged();
|
||||
|
||||
connect(PySideInstaller::instance(),
|
||||
&PySideInstaller::pySideInstalled,
|
||||
this,
|
||||
&PythonBuildConfiguration::handlePythonUpdated);
|
||||
|
||||
auto update = [this]() {
|
||||
if (isActive()) {
|
||||
m_buildSystem->emitBuildSystemUpdated();
|
||||
const FilePaths files = project()->files(Project::AllFiles);
|
||||
for (const FilePath &file : files) {
|
||||
if (auto doc = qobject_cast<PythonDocument *>(
|
||||
Core::DocumentModel::documentForFilePath(file))) {
|
||||
doc->updatePython(m_python);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
connect(target, &Target::activeBuildConfigurationChanged, this, update);
|
||||
connect(project(), &Project::activeTargetChanged, this, update);
|
||||
connect(ProjectExplorerPlugin::instance(),
|
||||
&ProjectExplorerPlugin::fileListChanged,
|
||||
this,
|
||||
update);
|
||||
connect(PythonSettings::instance(),
|
||||
&PythonSettings::virtualEnvironmentCreated,
|
||||
this,
|
||||
&PythonBuildConfiguration::handlePythonUpdated);
|
||||
}
|
||||
|
||||
NamedWidget *PythonBuildConfiguration::createConfigWidget()
|
||||
{
|
||||
return new PythonBuildSettingsWidget(this);
|
||||
}
|
||||
|
||||
static QString venvTypeName()
|
||||
{
|
||||
static QString name = Tr::tr("New Virtual Environment");
|
||||
return name;
|
||||
}
|
||||
|
||||
void PythonBuildConfiguration::initialize(const BuildInfo &info)
|
||||
{
|
||||
buildSteps()->appendStep(PySideBuildStep::id());
|
||||
if (info.typeName == venvTypeName()) {
|
||||
m_venv = info.buildDirectory;
|
||||
const FilePath venvInterpreterPath = info.buildDirectory.resolvePath(
|
||||
HostOsInfo::isWindowsHost() ? FilePath::fromUserInput("Scripts/python.exe")
|
||||
: FilePath::fromUserInput("bin/python"));
|
||||
|
||||
updatePython(venvInterpreterPath);
|
||||
|
||||
if (info.extraInfo.toMap().value("createVenv", false).toBool()
|
||||
&& !info.buildDirectory.exists()) {
|
||||
if (std::optional<Interpreter> python = PythonKitAspect::python(target()->kit()))
|
||||
PythonSettings::createVirtualEnvironment(python->command, info.buildDirectory);
|
||||
}
|
||||
} else {
|
||||
updateInterpreter(PythonKitAspect::python(target()->kit()));
|
||||
}
|
||||
|
||||
updateCacheAndEmitEnvironmentChanged();
|
||||
}
|
||||
|
||||
void PythonBuildConfiguration::updateInterpreter(const std::optional<Interpreter> &python)
|
||||
{
|
||||
updatePython(python ? python->command : FilePath());
|
||||
}
|
||||
|
||||
void PythonBuildConfiguration::updatePython(const FilePath &python)
|
||||
{
|
||||
m_python = python;
|
||||
if (auto buildStep = buildSteps()->firstOfType<PySideBuildStep>())
|
||||
buildStep->checkForPySide(python);
|
||||
if (isActive()) {
|
||||
const FilePaths files = project()->files(Project::AllFiles);
|
||||
for (const FilePath &file : files) {
|
||||
if (auto doc = qobject_cast<PythonDocument *>(
|
||||
Core::DocumentModel::documentForFilePath(file))) {
|
||||
doc->updatePython(m_python);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_buildSystem->requestParse();
|
||||
}
|
||||
|
||||
void PythonBuildConfiguration::handlePythonUpdated(const FilePath &python)
|
||||
{
|
||||
if (!m_python.isEmpty() && python == m_python)
|
||||
updatePython(python); // retrigger pyside check
|
||||
}
|
||||
|
||||
static const char pythonKey[] = "python";
|
||||
static const char venvKey[] = "venv";
|
||||
|
||||
void PythonBuildConfiguration::fromMap(const Store &map)
|
||||
{
|
||||
BuildConfiguration::fromMap(map);
|
||||
if (map.contains(venvKey))
|
||||
m_venv = FilePath::fromSettings(map[venvKey]);
|
||||
updatePython(FilePath::fromSettings(map[pythonKey]));
|
||||
}
|
||||
|
||||
void PythonBuildConfiguration::toMap(Store &map) const
|
||||
{
|
||||
BuildConfiguration::toMap(map);
|
||||
map[pythonKey] = m_python.toSettings();
|
||||
if (m_venv)
|
||||
map[venvKey] = m_venv->toSettings();
|
||||
}
|
||||
|
||||
BuildSystem *PythonBuildConfiguration::buildSystem() const
|
||||
{
|
||||
return m_buildSystem.get();
|
||||
}
|
||||
|
||||
FilePath PythonBuildConfiguration::python() const
|
||||
{
|
||||
return m_python;
|
||||
}
|
||||
|
||||
std::optional<FilePath> PythonBuildConfiguration::venv() const
|
||||
{
|
||||
return m_venv;
|
||||
}
|
||||
|
||||
PythonBuildConfigurationFactory::PythonBuildConfigurationFactory()
|
||||
{
|
||||
registerBuildConfiguration<PythonBuildConfiguration>("Python.PySideBuildConfiguration");
|
||||
setSupportedProjectType(PythonProjectId);
|
||||
setSupportedProjectMimeTypeName(Constants::C_PY_PROJECT_MIME_TYPE);
|
||||
setBuildGenerator([](const Kit *k, const FilePath &projectPath, bool forSetup) {
|
||||
if (std::optional<Interpreter> python = PythonKitAspect::python(k)) {
|
||||
BuildInfo base;
|
||||
base.buildDirectory = projectPath.parentDir();
|
||||
base.displayName = python->name;
|
||||
base.typeName = Tr::tr("Global Python");
|
||||
base.showBuildDirConfigWidget = false;
|
||||
|
||||
if (isVenvPython(python->command))
|
||||
return QList<BuildInfo>{base};
|
||||
|
||||
base.enabledByDefault = false;
|
||||
|
||||
BuildInfo venv;
|
||||
const FilePath venvBase = projectPath.parentDir() / ".qtcreator"
|
||||
/ FileUtils::fileSystemFriendlyName(python->name + "venv");
|
||||
venv.buildDirectory = venvBase;
|
||||
int i = 2;
|
||||
while (venv.buildDirectory.exists())
|
||||
venv.buildDirectory = venvBase.stringAppended('_' + QString::number(i++));
|
||||
venv.displayName = python->name + Tr::tr(" Virtual Environment");
|
||||
venv.typeName = venvTypeName();
|
||||
venv.extraInfo = QVariantMap{{"createVenv", forSetup}};
|
||||
return QList<BuildInfo>{base, venv};
|
||||
}
|
||||
return QList<BuildInfo>{};
|
||||
});
|
||||
}
|
||||
|
||||
} // Python::Internal
|
86
src/plugins/python/pythonbuildconfiguration.h
Normal file
86
src/plugins/python/pythonbuildconfiguration.h
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pythonbuildsystem.h"
|
||||
|
||||
#include <projectexplorer/abstractprocessstep.h>
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
#include <projectexplorer/buildstep.h>
|
||||
|
||||
|
||||
namespace ProjectExplorer { class Interpreter; }
|
||||
namespace Python::Internal {
|
||||
|
||||
class PipPackageInfo;
|
||||
class PySideUicExtraCompiler;
|
||||
|
||||
class PySideBuildStep : public ProjectExplorer::AbstractProcessStep
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PySideBuildStep(ProjectExplorer::BuildStepList *bsl, Utils::Id id);
|
||||
~PySideBuildStep();
|
||||
|
||||
void checkForPySide(const Utils::FilePath &python);
|
||||
|
||||
QList<PySideUicExtraCompiler *> extraCompilers() const;
|
||||
|
||||
static Utils::Id id();
|
||||
|
||||
private:
|
||||
void checkForPySide(const Utils::FilePath &python, const QString &pySidePackageName);
|
||||
void handlePySidePackageInfo(const PipPackageInfo &pySideInfo,
|
||||
const Utils::FilePath &python,
|
||||
const QString &requestedPackageName);
|
||||
|
||||
Tasking::GroupItem runRecipe() final;
|
||||
void updateExtraCompilers();
|
||||
|
||||
std::unique_ptr<QFutureWatcher<PipPackageInfo>> m_watcher;
|
||||
QMetaObject::Connection m_watcherConnection;
|
||||
|
||||
Utils::FilePathAspect m_pysideProject{this};
|
||||
Utils::FilePathAspect m_pysideUic{this};
|
||||
QList<PySideUicExtraCompiler *> m_extraCompilers;
|
||||
};
|
||||
|
||||
class PySideBuildStepFactory : public ProjectExplorer::BuildStepFactory
|
||||
{
|
||||
public:
|
||||
PySideBuildStepFactory();
|
||||
};
|
||||
|
||||
class PythonBuildConfiguration : public ProjectExplorer::BuildConfiguration
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PythonBuildConfiguration(ProjectExplorer::Target *target, const Utils::Id &id);
|
||||
|
||||
ProjectExplorer::NamedWidget *createConfigWidget() override;
|
||||
void fromMap(const Utils::Store &map) override;
|
||||
void toMap(Utils::Store &map) const override;
|
||||
ProjectExplorer::BuildSystem *buildSystem() const override;
|
||||
|
||||
Utils::FilePath python() const;
|
||||
std::optional<Utils::FilePath> venv() const;
|
||||
|
||||
private:
|
||||
void initialize(const ProjectExplorer::BuildInfo &info);
|
||||
void updateInterpreter(const std::optional<ProjectExplorer::Interpreter> &python);
|
||||
void updatePython(const Utils::FilePath &python);
|
||||
void handlePythonUpdated(const Utils::FilePath &python);
|
||||
|
||||
Utils::FilePath m_python;
|
||||
std::optional<Utils::FilePath> m_venv;
|
||||
std::unique_ptr<PythonBuildSystem> m_buildSystem;
|
||||
};
|
||||
|
||||
class PythonBuildConfigurationFactory : public ProjectExplorer::BuildConfigurationFactory
|
||||
{
|
||||
public:
|
||||
PythonBuildConfigurationFactory();
|
||||
};
|
||||
|
||||
} // namespace Python::Internal
|
@@ -3,7 +3,9 @@
|
||||
|
||||
#include "pythonbuildsystem.h"
|
||||
|
||||
#include "pythonbuildconfiguration.h"
|
||||
#include "pythonconstants.h"
|
||||
#include "pythonkitaspect.h"
|
||||
#include "pythonproject.h"
|
||||
#include "pythontr.h"
|
||||
|
||||
@@ -116,11 +118,15 @@ static QStringList readImportPathsJson(const FilePath &projectFile, QString *err
|
||||
return importPaths;
|
||||
}
|
||||
|
||||
PythonBuildSystem::PythonBuildSystem(Target *target)
|
||||
: BuildSystem(target)
|
||||
PythonBuildSystem::PythonBuildSystem(PythonBuildConfiguration *buildConfig)
|
||||
: BuildSystem(buildConfig)
|
||||
{
|
||||
connect(target->project(), &Project::projectFileIsDirty, this, [this] { triggerParsing(); });
|
||||
triggerParsing();
|
||||
connect(project(),
|
||||
&Project::projectFileIsDirty,
|
||||
this,
|
||||
&PythonBuildSystem::requestDelayedParse);
|
||||
m_buildConfig = buildConfig;
|
||||
requestParse();
|
||||
}
|
||||
|
||||
bool PythonBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const
|
||||
@@ -159,6 +165,12 @@ void PythonBuildSystem::triggerParsing()
|
||||
|
||||
auto newRoot = std::make_unique<PythonProjectNode>(projectDirectory());
|
||||
|
||||
FilePath python;
|
||||
if (m_buildConfig)
|
||||
python = m_buildConfig->python();
|
||||
else if (auto kitPython = PythonKitAspect::python(kit()))
|
||||
python = kitPython->command;
|
||||
|
||||
const FilePath projectFile = projectFilePath();
|
||||
const QString displayName = projectFile.relativePathFrom(projectDirectory()).toUserOutput();
|
||||
newRoot->addNestedNode(
|
||||
@@ -178,6 +190,7 @@ void PythonBuildSystem::triggerParsing()
|
||||
bti.targetFilePath = entry.filePath;
|
||||
bti.projectFilePath = projectFile;
|
||||
bti.isQtcRunnable = entry.filePath.fileName() == "main.py";
|
||||
bti.additionalData = QVariantMap{{"python", python.toSettings()}};
|
||||
appTargets.append(bti);
|
||||
}
|
||||
}
|
||||
|
@@ -7,10 +7,12 @@
|
||||
|
||||
namespace Python::Internal {
|
||||
|
||||
class PythonBuildConfiguration;
|
||||
|
||||
class PythonBuildSystem : public ProjectExplorer::BuildSystem
|
||||
{
|
||||
public:
|
||||
explicit PythonBuildSystem(ProjectExplorer::Target *target);
|
||||
explicit PythonBuildSystem(PythonBuildConfiguration *buildConfig);
|
||||
|
||||
bool supportsAction(ProjectExplorer::Node *context,
|
||||
ProjectExplorer::ProjectAction action,
|
||||
@@ -44,6 +46,7 @@ private:
|
||||
|
||||
QList<FileEntry> m_files;
|
||||
QList<FileEntry> m_qmlImportPaths;
|
||||
PythonBuildConfiguration *m_buildConfig = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
@@ -32,6 +32,9 @@ const char C_PY_MIMETYPE[] = "text/x-python";
|
||||
const char C_PY_GUI_MIMETYPE[] = "text/x-python-gui";
|
||||
const char C_PY3_MIMETYPE[] = "text/x-python3";
|
||||
const char C_PY_MIME_ICON[] = "text-x-python";
|
||||
const char C_PY_PROJECT_MIME_TYPE[] = "text/x-python-project";
|
||||
const char C_PY_PROJECT_MIME_TYPE_LEGACY[] = "text/x-pyqt-project";
|
||||
|
||||
|
||||
} // namespace Constants
|
||||
} // namespace Python
|
||||
|
@@ -4,10 +4,13 @@
|
||||
#include "pythoneditor.h"
|
||||
|
||||
#include "pyside.h"
|
||||
#include "pythonbuildconfiguration.h"
|
||||
#include "pythonconstants.h"
|
||||
#include "pythonhighlighter.h"
|
||||
#include "pythonindenter.h"
|
||||
#include "pythonkitaspect.h"
|
||||
#include "pythonlanguageclient.h"
|
||||
#include "pythonplugin.h"
|
||||
#include "pythonsettings.h"
|
||||
#include "pythontr.h"
|
||||
#include "pythonutils.h"
|
||||
@@ -17,12 +20,14 @@
|
||||
#include <coreplugin/coreplugintr.h>
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
#include <projectexplorer/buildinfo.h>
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectexplorer.h>
|
||||
#include <projectexplorer/projectmanager.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <texteditor/textdocument.h>
|
||||
#include <texteditor/texteditoractionhandler.h>
|
||||
|
||||
#include <utils/stylehelper.h>
|
||||
@@ -73,37 +78,6 @@ static void registerReplAction(QObject *parent)
|
||||
Constants::PYTHON_OPEN_REPL_IMPORT_TOPLEVEL);
|
||||
}
|
||||
|
||||
class PythonDocument : public TextDocument
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PythonDocument() : TextDocument(Constants::C_PYTHONEDITOR_ID)
|
||||
{
|
||||
connect(PythonSettings::instance(),
|
||||
&PythonSettings::pylsEnabledChanged,
|
||||
this,
|
||||
[this](const bool enabled) {
|
||||
if (!enabled)
|
||||
return;
|
||||
const FilePath &python = detectPython(filePath());
|
||||
if (python.exists())
|
||||
PyLSConfigureAssistant::openDocumentWithPython(python, this);
|
||||
});
|
||||
connect(this, &PythonDocument::openFinishedSuccessfully,
|
||||
this, &PythonDocument::checkForPyls);
|
||||
}
|
||||
|
||||
void checkForPyls()
|
||||
{
|
||||
const FilePath &python = detectPython(filePath());
|
||||
if (!python.exists())
|
||||
return;
|
||||
|
||||
PyLSConfigureAssistant::openDocumentWithPython(python, this);
|
||||
PySideInstaller::checkPySideInstallation(python, this);
|
||||
}
|
||||
};
|
||||
|
||||
class PythonEditorWidget : public TextEditorWidget
|
||||
{
|
||||
public:
|
||||
@@ -111,12 +85,10 @@ public:
|
||||
|
||||
protected:
|
||||
void finalizeInitialization() override;
|
||||
void setUserDefinedPython(const Interpreter &interpreter);
|
||||
void updateInterpretersSelector();
|
||||
|
||||
private:
|
||||
QToolButton *m_interpreters = nullptr;
|
||||
QList<QMetaObject::Connection> m_projectConnections;
|
||||
};
|
||||
|
||||
PythonEditorWidget::PythonEditorWidget(QWidget *parent) : TextEditorWidget(parent)
|
||||
@@ -142,31 +114,15 @@ void PythonEditorWidget::finalizeInitialization()
|
||||
{
|
||||
connect(textDocument(), &TextDocument::filePathChanged,
|
||||
this, &PythonEditorWidget::updateInterpretersSelector);
|
||||
connect(PythonSettings::instance(), &PythonSettings::interpretersChanged,
|
||||
this, &PythonEditorWidget::updateInterpretersSelector);
|
||||
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::fileListChanged,
|
||||
this, &PythonEditorWidget::updateInterpretersSelector);
|
||||
}
|
||||
|
||||
void PythonEditorWidget::setUserDefinedPython(const Interpreter &interpreter)
|
||||
{
|
||||
const auto pythonDocument = qobject_cast<PythonDocument *>(textDocument());
|
||||
QTC_ASSERT(pythonDocument, return);
|
||||
FilePath documentPath = pythonDocument->filePath();
|
||||
QTC_ASSERT(!documentPath.isEmpty(), return);
|
||||
if (Project *project = ProjectManager::projectForFile(documentPath)) {
|
||||
if (Target *target = project->activeTarget()) {
|
||||
if (RunConfiguration *rc = target->activeRunConfiguration()) {
|
||||
if (auto interpretersAspect= rc->aspect<InterpreterAspect>()) {
|
||||
interpretersAspect->setCurrentInterpreter(interpreter);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
connect(KitManager::instance(), &KitManager::kitsChanged,
|
||||
this, &PythonEditorWidget::updateInterpretersSelector);
|
||||
auto pythonDocument = qobject_cast<PythonDocument *>(textDocument());
|
||||
if (QTC_GUARD(pythonDocument)) {
|
||||
connect(pythonDocument, &PythonDocument::pythonUpdated,
|
||||
this, &PythonEditorWidget::updateInterpretersSelector);
|
||||
}
|
||||
definePythonForDocument(textDocument()->filePath(), interpreter.command);
|
||||
updateInterpretersSelector();
|
||||
pythonDocument->checkForPyls();
|
||||
}
|
||||
|
||||
void PythonEditorWidget::updateInterpretersSelector()
|
||||
@@ -183,30 +139,6 @@ void PythonEditorWidget::updateInterpretersSelector()
|
||||
QMenu *menu = m_interpreters->menu();
|
||||
QTC_ASSERT(menu, return);
|
||||
menu->clear();
|
||||
for (const QMetaObject::Connection &connection : m_projectConnections)
|
||||
disconnect(connection);
|
||||
m_projectConnections.clear();
|
||||
const FilePath documentPath = textDocument()->filePath();
|
||||
if (Project *project = ProjectManager::projectForFile(documentPath)) {
|
||||
m_projectConnections << connect(project,
|
||||
&Project::activeTargetChanged,
|
||||
this,
|
||||
&PythonEditorWidget::updateInterpretersSelector);
|
||||
if (Target *target = project->activeTarget()) {
|
||||
m_projectConnections << connect(target,
|
||||
&Target::activeRunConfigurationChanged,
|
||||
this,
|
||||
&PythonEditorWidget::updateInterpretersSelector);
|
||||
if (RunConfiguration *rc = target->activeRunConfiguration()) {
|
||||
if (auto interpreterAspect = rc->aspect<InterpreterAspect>()) {
|
||||
m_projectConnections << connect(interpreterAspect,
|
||||
&InterpreterAspect::changed,
|
||||
this,
|
||||
&PythonEditorWidget::updateInterpretersSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto setButtonText = [this](QString text) {
|
||||
constexpr int maxTextLength = 25;
|
||||
@@ -215,50 +147,130 @@ void PythonEditorWidget::updateInterpretersSelector()
|
||||
m_interpreters->setText(text);
|
||||
};
|
||||
|
||||
const FilePath currentInterpreterPath = detectPython(textDocument()->filePath());
|
||||
const QList<Interpreter> configuredInterpreters = PythonSettings::interpreters();
|
||||
auto interpretersGroup = new QActionGroup(menu);
|
||||
interpretersGroup->setExclusive(true);
|
||||
std::optional<Interpreter> currentInterpreter;
|
||||
for (const Interpreter &interpreter : configuredInterpreters) {
|
||||
QAction *action = interpretersGroup->addAction(interpreter.name);
|
||||
connect(action, &QAction::triggered, this, [this, interpreter]() {
|
||||
setUserDefinedPython(interpreter);
|
||||
});
|
||||
action->setCheckable(true);
|
||||
if (!currentInterpreter && interpreter.command == currentInterpreterPath) {
|
||||
currentInterpreter = interpreter;
|
||||
action->setChecked(true);
|
||||
setButtonText(interpreter.name);
|
||||
m_interpreters->setToolTip(interpreter.command.toUserOutput());
|
||||
const FilePath documentPath = textDocument()->filePath();
|
||||
Project *project = Utils::findOrDefault(ProjectManager::projects(),
|
||||
[documentPath](Project *project) {
|
||||
return project->mimeType()
|
||||
== Constants::C_PY_PROJECT_MIME_TYPE
|
||||
&& project->isKnownFile(documentPath);
|
||||
});
|
||||
|
||||
if (project) {
|
||||
auto interpretersGroup = new QActionGroup(menu);
|
||||
interpretersGroup->setExclusive(true);
|
||||
for (Target *target : project->targets()) {
|
||||
QTC_ASSERT(target, continue);
|
||||
for (auto buildConfiguration : target->buildConfigurations()) {
|
||||
QTC_ASSERT(buildConfiguration, continue);
|
||||
const QString name = buildConfiguration->displayName();
|
||||
QAction *action = interpretersGroup->addAction(buildConfiguration->displayName());
|
||||
action->setCheckable(true);
|
||||
if (target == project->activeTarget()
|
||||
&& target->activeBuildConfiguration() == buildConfiguration) {
|
||||
action->setChecked(true);
|
||||
setButtonText(name);
|
||||
if (auto pbc = qobject_cast<PythonBuildConfiguration *>(buildConfiguration))
|
||||
m_interpreters->setToolTip(pbc->python().toUserOutput());
|
||||
}
|
||||
connect(action,
|
||||
&QAction::triggered,
|
||||
project,
|
||||
[project, target, buildConfiguration]() {
|
||||
target->setActiveBuildConfiguration(buildConfiguration,
|
||||
SetActive::NoCascade);
|
||||
if (target != project->activeTarget())
|
||||
project->setActiveTarget(target, SetActive::NoCascade);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
menu->addActions(interpretersGroup->actions());
|
||||
if (!currentInterpreter) {
|
||||
if (currentInterpreterPath.exists())
|
||||
setButtonText(currentInterpreterPath.toUserOutput());
|
||||
else
|
||||
setButtonText(Tr::tr("No Python Selected"));
|
||||
}
|
||||
if (!interpretersGroup->actions().isEmpty()) {
|
||||
|
||||
menu->addActions(interpretersGroup->actions());
|
||||
|
||||
QMenu *addMenu = menu->addMenu("Add new Interpreter");
|
||||
for (auto kit : KitManager::kits()) {
|
||||
if (std::optional<Interpreter> python = PythonKitAspect::python(kit)) {
|
||||
if (auto buildConficurationFactory
|
||||
= ProjectExplorer::BuildConfigurationFactory::find(kit,
|
||||
project->projectFilePath())) {
|
||||
const QString name = kit->displayName();
|
||||
QMenu *interpreterAddMenu = addMenu->addMenu(name);
|
||||
const QList<BuildInfo> buildInfos
|
||||
= buildConficurationFactory->allAvailableSetups(kit,
|
||||
project->projectFilePath());
|
||||
for (const BuildInfo &buildInfo : buildInfos) {
|
||||
QAction *action = interpreterAddMenu->addAction(buildInfo.displayName);
|
||||
connect(action, &QAction::triggered, project, [project, buildInfo]() {
|
||||
if (BuildConfiguration *buildConfig = project->setup(buildInfo)) {
|
||||
buildConfig->target()
|
||||
->setActiveBuildConfiguration(buildConfig, SetActive::NoCascade);
|
||||
project->setActiveTarget(buildConfig->target(),
|
||||
SetActive::NoCascade);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
menu->addSeparator();
|
||||
auto venvAction = menu->addAction(Tr::tr("Create Virtual Environment"));
|
||||
connect(venvAction,
|
||||
&QAction::triggered,
|
||||
this,
|
||||
[self = QPointer<PythonEditorWidget>(this), currentInterpreter]() {
|
||||
if (!currentInterpreter)
|
||||
return;
|
||||
auto callback = [self](const std::optional<Interpreter> &venvInterpreter) {
|
||||
if (self && venvInterpreter)
|
||||
self->setUserDefinedPython(*venvInterpreter);
|
||||
};
|
||||
PythonSettings::createVirtualEnvironmentInteractive(self->textDocument()
|
||||
->filePath()
|
||||
.parentDir(),
|
||||
*currentInterpreter,
|
||||
callback);
|
||||
});
|
||||
} else {
|
||||
auto setUserDefinedPython = [this](const FilePath &interpreter){
|
||||
const auto pythonDocument = qobject_cast<PythonDocument *>(textDocument());
|
||||
QTC_ASSERT(pythonDocument, return);
|
||||
const FilePath documentPath = pythonDocument->filePath();
|
||||
QTC_ASSERT(!documentPath.isEmpty(), return);
|
||||
definePythonForDocument(documentPath, interpreter);
|
||||
updateInterpretersSelector();
|
||||
pythonDocument->updateCurrentPython();
|
||||
};
|
||||
const FilePath currentInterpreterPath = detectPython(documentPath);
|
||||
const QList<Interpreter> configuredInterpreters = PythonSettings::interpreters();
|
||||
auto interpretersGroup = new QActionGroup(menu);
|
||||
interpretersGroup->setExclusive(true);
|
||||
std::optional<Interpreter> currentInterpreter;
|
||||
for (const Interpreter &interpreter : configuredInterpreters) {
|
||||
QAction *action = interpretersGroup->addAction(interpreter.name);
|
||||
connect(action, &QAction::triggered, this, [interpreter, setUserDefinedPython]() {
|
||||
setUserDefinedPython(interpreter.command);
|
||||
});
|
||||
action->setCheckable(true);
|
||||
if (!currentInterpreter && interpreter.command == currentInterpreterPath) {
|
||||
currentInterpreter = interpreter;
|
||||
action->setChecked(true);
|
||||
setButtonText(interpreter.name);
|
||||
m_interpreters->setToolTip(interpreter.command.toUserOutput());
|
||||
}
|
||||
}
|
||||
menu->addActions(interpretersGroup->actions());
|
||||
if (!currentInterpreter) {
|
||||
if (currentInterpreterPath.exists())
|
||||
setButtonText(currentInterpreterPath.toUserOutput());
|
||||
else
|
||||
setButtonText(Tr::tr("No Python Selected"));
|
||||
}
|
||||
if (!interpretersGroup->actions().isEmpty()) {
|
||||
menu->addSeparator();
|
||||
auto venvAction = menu->addAction(Tr::tr("Create Virtual Environment"));
|
||||
connect(venvAction,
|
||||
&QAction::triggered,
|
||||
this,
|
||||
[self = QPointer<PythonEditorWidget>(this),
|
||||
currentInterpreter,
|
||||
setUserDefinedPython]() {
|
||||
if (!currentInterpreter)
|
||||
return;
|
||||
auto callback = [self, setUserDefinedPython](
|
||||
const std::optional<FilePath> &venvInterpreter) {
|
||||
if (self && venvInterpreter)
|
||||
setUserDefinedPython(*venvInterpreter);
|
||||
};
|
||||
PythonSettings::createVirtualEnvironmentInteractive(self->textDocument()
|
||||
->filePath()
|
||||
.parentDir(),
|
||||
*currentInterpreter,
|
||||
callback);
|
||||
});
|
||||
}
|
||||
}
|
||||
auto settingsAction = menu->addAction(Tr::tr("Manage Python Interpreters"));
|
||||
connect(settingsAction, &QAction::triggered, this, []() {
|
||||
@@ -288,6 +300,35 @@ PythonEditorFactory::PythonEditorFactory()
|
||||
setCodeFoldingSupported(true);
|
||||
}
|
||||
|
||||
} // Python::Internal
|
||||
PythonDocument::PythonDocument()
|
||||
: TextDocument(Constants::C_PYTHONEDITOR_ID)
|
||||
{
|
||||
connect(PythonSettings::instance(),
|
||||
&PythonSettings::pylsEnabledChanged,
|
||||
this,
|
||||
[this](const bool enabled) {
|
||||
if (!enabled)
|
||||
return;
|
||||
const FilePath &python = detectPython(filePath());
|
||||
if (python.exists())
|
||||
PyLSConfigureAssistant::openDocumentWithPython(python, this);
|
||||
});
|
||||
connect(this,
|
||||
&PythonDocument::openFinishedSuccessfully,
|
||||
this,
|
||||
&PythonDocument::updateCurrentPython);
|
||||
}
|
||||
|
||||
#include "pythoneditor.moc"
|
||||
void PythonDocument::updateCurrentPython()
|
||||
{
|
||||
updatePython(detectPython(filePath()));
|
||||
}
|
||||
|
||||
void PythonDocument::updatePython(const FilePath &python)
|
||||
{
|
||||
PyLSConfigureAssistant::openDocumentWithPython(python, this);
|
||||
PySideInstaller::checkPySideInstallation(python, this);
|
||||
emit pythonUpdated(python);
|
||||
}
|
||||
|
||||
} // Python::Internal
|
||||
|
@@ -3,6 +3,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <texteditor/textdocument.h>
|
||||
#include <texteditor/texteditor.h>
|
||||
|
||||
namespace Python::Internal {
|
||||
@@ -15,4 +16,17 @@ private:
|
||||
QObject m_guard;
|
||||
};
|
||||
|
||||
class PythonDocument : public TextEditor::TextDocument
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PythonDocument();
|
||||
|
||||
void updateCurrentPython();
|
||||
void updatePython(const Utils::FilePath &python);
|
||||
|
||||
signals:
|
||||
void pythonUpdated(const Utils::FilePath &python);
|
||||
};
|
||||
|
||||
} // Python::Internal
|
||||
|
@@ -119,6 +119,13 @@ public:
|
||||
}
|
||||
|
||||
KitAspect *createKitAspect(Kit *k) const override { return new PythonKitAspectImpl(k, this); }
|
||||
|
||||
QSet<Id> availableFeatures(const Kit *k) const override
|
||||
{
|
||||
if (k->isAspectRelevant(PythonKitAspect::id()) && PythonKitAspect::python(k))
|
||||
return {PythonKitAspect::id()};
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
std::optional<Interpreter> PythonKitAspect::python(const Kit *kit)
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "pythonlanguageclient.h"
|
||||
|
||||
#include "pipsupport.h"
|
||||
#include "pythonbuildconfiguration.h"
|
||||
#include "pysideuicextracompiler.h"
|
||||
#include "pythonconstants.h"
|
||||
#include "pythonplugin.h"
|
||||
@@ -22,6 +23,8 @@
|
||||
#include <languageserverprotocol/textsynchronization.h>
|
||||
#include <languageserverprotocol/workspace.h>
|
||||
|
||||
#include <projectexplorer/buildconfiguration.h>
|
||||
#include <projectexplorer/buildsteplist.h>
|
||||
#include <projectexplorer/extracompiler.h>
|
||||
#include <projectexplorer/projectmanager.h>
|
||||
#include <projectexplorer/target.h>
|
||||
@@ -207,12 +210,13 @@ void PyLSClient::openDocument(TextEditor::TextDocument *document)
|
||||
const FilePath documentPath = document->filePath();
|
||||
if (PythonProject *project = pythonProjectForFile(documentPath)) {
|
||||
if (Target *target = project->activeTarget()) {
|
||||
if (RunConfiguration *rc = target->activeRunConfiguration())
|
||||
if (auto aspect = rc->aspect<InterpreterAspect>()) {
|
||||
updateExtraCompilers(project,
|
||||
static_cast<PythonInterpreterAspect *>(aspect)
|
||||
->extraCompilers());
|
||||
if (BuildConfiguration *buildConfig = target->activeBuildConfiguration()) {
|
||||
if (BuildStepList *buildSteps = buildConfig->buildSteps()) {
|
||||
BuildStep *buildStep = buildSteps->firstStepWithId(PySideBuildStep::id());
|
||||
if (auto *pythonBuildStep = qobject_cast<PySideBuildStep *>(buildStep))
|
||||
updateExtraCompilers(project, pythonBuildStep->extraCompilers());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (isSupportedDocument(document)) {
|
||||
const FilePath workspacePath = documentPath.parentDir();
|
||||
@@ -321,7 +325,7 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python,
|
||||
TextEditor::TextDocument *document)
|
||||
{
|
||||
instance()->resetEditorInfoBar(document);
|
||||
if (!PythonSettings::pylsEnabled())
|
||||
if (!PythonSettings::pylsEnabled() || !python.exists())
|
||||
return;
|
||||
|
||||
if (auto client = pythonClients().value(python)) {
|
||||
@@ -347,9 +351,13 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python,
|
||||
if (!document || !watcher)
|
||||
return;
|
||||
instance()->handlePyLSState(python, watcher->result(), document);
|
||||
watcher->deleteLater();
|
||||
});
|
||||
connect(watcher, &CheckPylsWatcher::finished, watcher, &CheckPylsWatcher::deleteLater);
|
||||
connect(watcher, &CheckPylsWatcher::finished, instance(), [document](){
|
||||
instance()->m_runningChecks.remove(document);
|
||||
});
|
||||
watcher->setFuture(Utils::asyncRun(&checkPythonLanguageServer, python));
|
||||
instance()->m_runningChecks[document] = watcher;
|
||||
}
|
||||
|
||||
void PyLSConfigureAssistant::handlePyLSState(const FilePath &python,
|
||||
@@ -383,6 +391,8 @@ void PyLSConfigureAssistant::resetEditorInfoBar(TextEditor::TextDocument *docume
|
||||
for (QList<TextEditor::TextDocument *> &documents : m_infoBarEntries)
|
||||
documents.removeAll(document);
|
||||
document->infoBar()->removeInfo(installPylsInfoBarId);
|
||||
if (auto watcher = m_runningChecks.value(document))
|
||||
watcher->cancel();
|
||||
}
|
||||
|
||||
PyLSConfigureAssistant::PyLSConfigureAssistant(QObject *parent)
|
||||
|
@@ -67,6 +67,8 @@ private:
|
||||
QPointer<TextEditor::TextDocument> document);
|
||||
|
||||
QHash<Utils::FilePath, QList<TextEditor::TextDocument *>> m_infoBarEntries;
|
||||
QHash<TextEditor::TextDocument *, QPointer<QFutureWatcher<PythonLanguageServerState>>>
|
||||
m_runningChecks;
|
||||
};
|
||||
|
||||
} // Python::Internal
|
||||
|
@@ -3,7 +3,8 @@
|
||||
|
||||
#include "pythonplugin.h"
|
||||
|
||||
#include "pysidebuildconfiguration.h"
|
||||
#include "pythonbuildconfiguration.h"
|
||||
#include "pythonconstants.h"
|
||||
#include "pythoneditor.h"
|
||||
#include "pythonkitaspect.h"
|
||||
#include "pythonproject.h"
|
||||
@@ -36,7 +37,7 @@ public:
|
||||
PythonOutputFormatterFactory outputFormatterFactory;
|
||||
PythonRunConfigurationFactory runConfigFactory;
|
||||
PySideBuildStepFactory buildStepFactory;
|
||||
PySideBuildConfigurationFactory buildConfigFactory;
|
||||
PythonBuildConfigurationFactory buildConfigFactory;
|
||||
SimpleTargetRunnerFactory runWorkerFactory{{runConfigFactory.runConfigurationId()}};
|
||||
PythonSettings settings;
|
||||
PythonWizardPageFactory pythonWizardPageFactory;
|
||||
@@ -65,8 +66,8 @@ void PythonPlugin::initialize()
|
||||
KitManager::setIrrelevantAspects(KitManager::irrelevantAspects()
|
||||
+ QSet<Id>{PythonKitAspect::id()});
|
||||
|
||||
ProjectManager::registerProjectType<PythonProject>(PythonMimeType);
|
||||
ProjectManager::registerProjectType<PythonProject>(PythonMimeTypeLegacy);
|
||||
ProjectManager::registerProjectType<PythonProject>(Constants::C_PY_PROJECT_MIME_TYPE);
|
||||
ProjectManager::registerProjectType<PythonProject>(Constants::C_PY_PROJECT_MIME_TYPE_LEGACY);
|
||||
}
|
||||
|
||||
void PythonPlugin::extensionsInitialized()
|
||||
|
@@ -7,6 +7,8 @@
|
||||
|
||||
namespace Python::Internal {
|
||||
|
||||
class PythonBuildConfigurationFactory;
|
||||
|
||||
class PythonPlugin final : public ExtensionSystem::IPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include <coreplugin/icontext.h>
|
||||
|
||||
#include <projectexplorer/projectexplorerconstants.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
using namespace Core;
|
||||
using namespace ProjectExplorer;
|
||||
@@ -17,16 +18,13 @@ using namespace Utils;
|
||||
namespace Python::Internal {
|
||||
|
||||
PythonProject::PythonProject(const FilePath &fileName)
|
||||
: Project(Constants::C_PY_MIMETYPE, fileName)
|
||||
: Project(Constants::C_PY_PROJECT_MIME_TYPE, fileName)
|
||||
{
|
||||
setId(PythonProjectId);
|
||||
setProjectLanguages(Context(ProjectExplorer::Constants::PYTHON_LANGUAGE_ID));
|
||||
setDisplayName(fileName.completeBaseName());
|
||||
|
||||
setBuildSystemCreator([](Target *t) { return new PythonBuildSystem(t); });
|
||||
}
|
||||
|
||||
|
||||
Project::RestoreResult PythonProject::fromMap(const Store &map, QString *errorMessage)
|
||||
{
|
||||
Project::RestoreResult res = Project::fromMap(map, errorMessage);
|
||||
|
@@ -10,8 +10,6 @@ namespace Utils { class FilePath; }
|
||||
|
||||
namespace Python::Internal {
|
||||
|
||||
const char PythonMimeType[] = "text/x-python-project";
|
||||
const char PythonMimeTypeLegacy[] = "text/x-pyqt-project";
|
||||
const char PythonProjectId[] = "PythonProject";
|
||||
const char PythonErrorTaskCategory[] = "Task.Category.Python";
|
||||
|
||||
|
@@ -3,24 +3,21 @@
|
||||
|
||||
#include "pythonrunconfiguration.h"
|
||||
|
||||
#include "pipsupport.h"
|
||||
#include "pyside.h"
|
||||
#include "pysidebuildconfiguration.h"
|
||||
#include "pysideuicextracompiler.h"
|
||||
#include "pythonbuildconfiguration.h"
|
||||
#include "pythonconstants.h"
|
||||
#include "pythoneditor.h"
|
||||
#include "pythonkitaspect.h"
|
||||
#include "pythonlanguageclient.h"
|
||||
#include "pythonproject.h"
|
||||
#include "pythonsettings.h"
|
||||
#include "pythontr.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <languageclient/languageclientmanager.h>
|
||||
|
||||
#include <projectexplorer/buildsteplist.h>
|
||||
#include <projectexplorer/buildsystem.h>
|
||||
#include <projectexplorer/devicesupport/idevice.h>
|
||||
@@ -36,6 +33,7 @@
|
||||
#include <utils/futuresynchronizer.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
#include <utils/outputformatter.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/theme/theme.h>
|
||||
|
||||
#include <QComboBox>
|
||||
@@ -118,229 +116,6 @@ private:
|
||||
bool m_inTraceBack;
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class PythonInterpreterAspectPrivate : public QObject
|
||||
{
|
||||
public:
|
||||
PythonInterpreterAspectPrivate(PythonInterpreterAspect *parent, RunConfiguration *rc)
|
||||
: q(parent), rc(rc)
|
||||
{
|
||||
connect(q, &InterpreterAspect::changed,
|
||||
this, &PythonInterpreterAspectPrivate::currentInterpreterChanged);
|
||||
|
||||
connect(PySideInstaller::instance(), &PySideInstaller::pySideInstalled, this,
|
||||
[this](const FilePath &python) {
|
||||
if (python == q->currentInterpreter().command)
|
||||
checkForPySide(python);
|
||||
}
|
||||
);
|
||||
|
||||
connect(rc->target(), &Target::buildSystemUpdated,
|
||||
this, &PythonInterpreterAspectPrivate::updateExtraCompilers);
|
||||
}
|
||||
|
||||
~PythonInterpreterAspectPrivate() { qDeleteAll(m_extraCompilers); }
|
||||
|
||||
void checkForPySide(const FilePath &python);
|
||||
void checkForPySide(const FilePath &python, const QString &pySidePackageName);
|
||||
void handlePySidePackageInfo(const PipPackageInfo &pySideInfo,
|
||||
const FilePath &python,
|
||||
const QString &requestedPackageName);
|
||||
void updateExtraCompilers();
|
||||
void currentInterpreterChanged();
|
||||
|
||||
struct PySideTools
|
||||
{
|
||||
FilePath pySideProjectPath;
|
||||
FilePath pySideUicPath;
|
||||
};
|
||||
void updateTools(const PySideTools &tools);
|
||||
|
||||
FilePath m_pySideUicPath;
|
||||
|
||||
PythonInterpreterAspect *q;
|
||||
RunConfiguration *rc;
|
||||
QList<PySideUicExtraCompiler *> m_extraCompilers;
|
||||
QFutureWatcher<PipPackageInfo> *m_watcher = nullptr;
|
||||
QMetaObject::Connection m_watcherConnection;
|
||||
};
|
||||
|
||||
PythonInterpreterAspect::PythonInterpreterAspect(AspectContainer *container, RunConfiguration *rc)
|
||||
: InterpreterAspect(container), d(new PythonInterpreterAspectPrivate(this, rc))
|
||||
{
|
||||
setSettingsKey("PythonEditor.RunConfiguation.Interpreter");
|
||||
setSettingsDialogId(Constants::C_PYTHONOPTIONS_PAGE_ID);
|
||||
|
||||
updateInterpreters(PythonSettings::interpreters());
|
||||
|
||||
const QList<Interpreter> interpreters = PythonSettings::detectPythonVenvs(
|
||||
rc->project()->projectDirectory());
|
||||
Interpreter defaultInterpreter = interpreters.isEmpty() ? PythonSettings::defaultInterpreter()
|
||||
: interpreters.first();
|
||||
if (!defaultInterpreter.command.isExecutableFile())
|
||||
defaultInterpreter = PythonSettings::interpreters().value(0);
|
||||
if (defaultInterpreter.command.isExecutableFile()) {
|
||||
const IDeviceConstPtr device = DeviceKitAspect::device(rc->kit());
|
||||
if (device && !device->handlesFile(defaultInterpreter.command)) {
|
||||
defaultInterpreter = Utils::findOr(PythonSettings::interpreters(),
|
||||
defaultInterpreter,
|
||||
[device](const Interpreter &interpreter) {
|
||||
return device->handlesFile(interpreter.command);
|
||||
});
|
||||
}
|
||||
}
|
||||
setDefaultInterpreter(defaultInterpreter);
|
||||
|
||||
connect(PythonSettings::instance(), &PythonSettings::interpretersChanged,
|
||||
this, &InterpreterAspect::updateInterpreters);
|
||||
}
|
||||
|
||||
PythonInterpreterAspect::~PythonInterpreterAspect()
|
||||
{
|
||||
delete d;
|
||||
}
|
||||
|
||||
void PythonInterpreterAspectPrivate::checkForPySide(const FilePath &python)
|
||||
{
|
||||
PySideTools tools;
|
||||
const FilePath dir = python.parentDir();
|
||||
tools.pySideProjectPath = dir.pathAppended("pyside6-project").withExecutableSuffix();
|
||||
tools.pySideUicPath = dir.pathAppended("pyside6-uic").withExecutableSuffix();
|
||||
|
||||
if (tools.pySideProjectPath.isExecutableFile() && tools.pySideUicPath.isExecutableFile())
|
||||
updateTools(tools);
|
||||
else
|
||||
checkForPySide(python, "PySide6-Essentials");
|
||||
}
|
||||
|
||||
void PythonInterpreterAspectPrivate::checkForPySide(const FilePath &python,
|
||||
const QString &pySidePackageName)
|
||||
{
|
||||
const PipPackage package(pySidePackageName);
|
||||
QObject::disconnect(m_watcherConnection);
|
||||
delete m_watcher;
|
||||
m_watcher = new QFutureWatcher<PipPackageInfo>(this);
|
||||
m_watcherConnection = QObject::connect(m_watcher, &QFutureWatcherBase::finished, q, [=] {
|
||||
handlePySidePackageInfo(m_watcher->result(), python, pySidePackageName);
|
||||
});
|
||||
const auto future = Pip::instance(python)->info(package);
|
||||
m_watcher->setFuture(future);
|
||||
ExtensionSystem::PluginManager::futureSynchronizer()->addFuture(future);
|
||||
}
|
||||
|
||||
void PythonInterpreterAspectPrivate::handlePySidePackageInfo(const PipPackageInfo &pySideInfo,
|
||||
const FilePath &python,
|
||||
const QString &requestedPackageName)
|
||||
{
|
||||
const auto findPythonTools = [](const FilePaths &files,
|
||||
const FilePath &location,
|
||||
const FilePath &python) -> PySideTools {
|
||||
PySideTools result;
|
||||
const QString pySide6ProjectName
|
||||
= OsSpecificAspects::withExecutableSuffix(python.osType(), "pyside6-project");
|
||||
const QString pySide6UicName
|
||||
= OsSpecificAspects::withExecutableSuffix(python.osType(), "pyside6-uic");
|
||||
for (const FilePath &file : files) {
|
||||
if (file.fileName() == pySide6ProjectName) {
|
||||
result.pySideProjectPath = python.withNewMappedPath(location.resolvePath(file));
|
||||
result.pySideProjectPath = result.pySideProjectPath.cleanPath();
|
||||
if (!result.pySideUicPath.isEmpty())
|
||||
return result;
|
||||
} else if (file.fileName() == pySide6UicName) {
|
||||
result.pySideUicPath = python.withNewMappedPath(location.resolvePath(file));
|
||||
result.pySideUicPath = result.pySideUicPath.cleanPath();
|
||||
if (!result.pySideProjectPath.isEmpty())
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
PySideTools tools = findPythonTools(pySideInfo.files, pySideInfo.location, python);
|
||||
if (!tools.pySideProjectPath.isExecutableFile() && requestedPackageName != "PySide6") {
|
||||
checkForPySide(python, "PySide6");
|
||||
return;
|
||||
}
|
||||
|
||||
updateTools(tools);
|
||||
}
|
||||
|
||||
void PythonInterpreterAspectPrivate::currentInterpreterChanged()
|
||||
{
|
||||
const FilePath python = q->currentInterpreter().command;
|
||||
checkForPySide(python);
|
||||
|
||||
for (FilePath &file : rc->project()->files(Project::AllFiles)) {
|
||||
if (auto document = TextEditor::TextDocument::textDocumentForFilePath(file)) {
|
||||
if (document->mimeType() == Constants::C_PY_MIMETYPE
|
||||
|| document->mimeType() == Constants::C_PY3_MIMETYPE) {
|
||||
PyLSConfigureAssistant::openDocumentWithPython(python, document);
|
||||
PySideInstaller::checkPySideInstallation(python, document);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PythonInterpreterAspectPrivate::updateTools(const PySideTools &tools)
|
||||
{
|
||||
m_pySideUicPath = tools.pySideUicPath;
|
||||
|
||||
updateExtraCompilers();
|
||||
|
||||
if (Target *target = rc->target()) {
|
||||
if (BuildConfiguration *buildConfiguration = target->activeBuildConfiguration()) {
|
||||
if (BuildStepList *buildSteps = buildConfiguration->buildSteps()) {
|
||||
if (auto buildStep = buildSteps->firstOfType<PySideBuildStep>())
|
||||
buildStep->updatePySideProjectPath(tools.pySideProjectPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QList<PySideUicExtraCompiler *> PythonInterpreterAspect::extraCompilers() const
|
||||
{
|
||||
return d->m_extraCompilers;
|
||||
}
|
||||
|
||||
void PythonInterpreterAspectPrivate::updateExtraCompilers()
|
||||
{
|
||||
QList<PySideUicExtraCompiler *> oldCompilers = m_extraCompilers;
|
||||
m_extraCompilers.clear();
|
||||
|
||||
if (m_pySideUicPath.isExecutableFile()) {
|
||||
auto uiMatcher = [](const Node *node) {
|
||||
if (const FileNode *fileNode = node->asFileNode())
|
||||
return fileNode->fileType() == FileType::Form;
|
||||
return false;
|
||||
};
|
||||
const FilePaths uiFiles = rc->project()->files(uiMatcher);
|
||||
for (const FilePath &uiFile : uiFiles) {
|
||||
FilePath generated = uiFile.parentDir();
|
||||
generated = generated.pathAppended("/ui_" + uiFile.baseName() + ".py");
|
||||
int index = Utils::indexOf(oldCompilers, [&](PySideUicExtraCompiler *oldCompiler) {
|
||||
return oldCompiler->pySideUicPath() == m_pySideUicPath
|
||||
&& oldCompiler->project() == rc->project() && oldCompiler->source() == uiFile
|
||||
&& oldCompiler->targets() == FilePaths{generated};
|
||||
});
|
||||
if (index < 0) {
|
||||
m_extraCompilers << new PySideUicExtraCompiler(m_pySideUicPath,
|
||||
rc->project(),
|
||||
uiFile,
|
||||
{generated},
|
||||
this);
|
||||
} else {
|
||||
m_extraCompilers << oldCompilers.takeAt(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (LanguageClient::Client *client : LanguageClient::LanguageClientManager::clients()) {
|
||||
if (auto pylsClient = qobject_cast<PyLSClient *>(client))
|
||||
pylsClient->updateExtraCompilers(rc->project(), m_extraCompilers);
|
||||
}
|
||||
qDeleteAll(oldCompilers);
|
||||
}
|
||||
|
||||
// RunConfiguration
|
||||
|
||||
class PythonRunConfiguration : public RunConfiguration
|
||||
@@ -368,11 +143,14 @@ public:
|
||||
x11Forwarding.setMacroExpander(macroExpander());
|
||||
x11Forwarding.setVisible(HostOsInfo::isAnyUnixHost());
|
||||
|
||||
if (const std::optional<Interpreter> kitPython = PythonKitAspect::python(target->kit()))
|
||||
interpreter.setCurrentInterpreter(*kitPython);
|
||||
interpreter.setLabelText(Tr::tr("Python:"));
|
||||
interpreter.setReadOnly(true);
|
||||
|
||||
setCommandLineGetter([this] {
|
||||
CommandLine cmd{interpreter.currentInterpreter().command};
|
||||
CommandLine cmd;
|
||||
cmd.setExecutable(interpreter());
|
||||
if (interpreter().isEmpty())
|
||||
return cmd;
|
||||
if (!buffered())
|
||||
cmd.addArg("-u");
|
||||
cmd.addArg(mainScript().fileName());
|
||||
@@ -382,6 +160,9 @@ public:
|
||||
|
||||
setUpdater([this] {
|
||||
const BuildTargetInfo bti = buildTargetInfo();
|
||||
const auto python = FilePath::fromSettings(bti.additionalData.toMap().value("python"));
|
||||
interpreter.setValue(python);
|
||||
|
||||
setDefaultDisplayName(Tr::tr("Run %1").arg(bti.targetFilePath.toUserOutput()));
|
||||
mainScript.setValue(bti.targetFilePath);
|
||||
workingDir.setDefaultWorkingDirectory(bti.targetFilePath.parentDir());
|
||||
@@ -390,7 +171,7 @@ public:
|
||||
connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update);
|
||||
}
|
||||
|
||||
PythonInterpreterAspect interpreter{this, this};
|
||||
FilePathAspect interpreter{this};
|
||||
BoolAspect buffered{this};
|
||||
MainScriptAspect mainScript{this};
|
||||
EnvironmentAspect environment{this};
|
||||
@@ -411,7 +192,7 @@ PythonRunConfigurationFactory::PythonRunConfigurationFactory()
|
||||
PythonOutputFormatterFactory::PythonOutputFormatterFactory()
|
||||
{
|
||||
setFormatterCreator([](Target *t) -> QList<OutputLineParser *> {
|
||||
if (t && t->project()->mimeType() == Constants::C_PY_MIMETYPE)
|
||||
if (t && t->project()->mimeType() == Constants::C_PY_PROJECT_MIME_TYPE)
|
||||
return {new PythonOutputLineParser};
|
||||
return {};
|
||||
});
|
||||
|
@@ -10,7 +10,6 @@
|
||||
namespace Python::Internal {
|
||||
|
||||
class PySideUicExtraCompiler;
|
||||
class PythonRunConfiguration;
|
||||
|
||||
class PythonInterpreterAspect final : public ProjectExplorer::InterpreterAspect
|
||||
{
|
||||
@@ -18,8 +17,6 @@ public:
|
||||
PythonInterpreterAspect(Utils::AspectContainer *container, ProjectExplorer::RunConfiguration *rc);
|
||||
~PythonInterpreterAspect() final;
|
||||
|
||||
QList<PySideUicExtraCompiler *> extraCompilers() const;
|
||||
|
||||
private:
|
||||
friend class PythonRunConfiguration;
|
||||
class PythonInterpreterAspectPrivate *d = nullptr;
|
||||
|
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <coreplugin/dialogs/ioptionspage.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/progressmanager/processprogress.h>
|
||||
|
||||
#include <projectexplorer/kitaspects.h>
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
@@ -813,7 +814,7 @@ void PythonSettings::addKitsForInterpreter(const Interpreter &interpreter)
|
||||
const Id kitId = Id::fromString(interpreter.id);
|
||||
if (Kit *k = KitManager::kit(kitId)) {
|
||||
setRelevantAspectsToKit(k);
|
||||
} else {
|
||||
} else if (!isVenvPython(interpreter.command)) {
|
||||
KitManager::registerKit(
|
||||
[interpreter](Kit *k) {
|
||||
k->setAutoDetected(true);
|
||||
@@ -821,6 +822,7 @@ void PythonSettings::addKitsForInterpreter(const Interpreter &interpreter)
|
||||
k->setUnexpandedDisplayName(interpreter.name);
|
||||
setRelevantAspectsToKit(k);
|
||||
PythonKitAspect::setPython(k, interpreter.id);
|
||||
k->setSticky(PythonKitAspect::id(), true);
|
||||
},
|
||||
kitId);
|
||||
}
|
||||
@@ -914,7 +916,7 @@ PythonSettings *PythonSettings::instance()
|
||||
void PythonSettings::createVirtualEnvironmentInteractive(
|
||||
const FilePath &startDirectory,
|
||||
const Interpreter &defaultInterpreter,
|
||||
const std::function<void(std::optional<Interpreter>)> &callback)
|
||||
const std::function<void(const FilePath &)> &callback)
|
||||
{
|
||||
QDialog dialog;
|
||||
dialog.setModal(true);
|
||||
@@ -954,26 +956,37 @@ void PythonSettings::createVirtualEnvironmentInteractive(
|
||||
interpreters->currentData().toString());
|
||||
|
||||
auto venvDir = pathChooser->filePath();
|
||||
createVirtualEnvironment(venvDir, interpreter, callback);
|
||||
createVirtualEnvironment(interpreter.command, venvDir, callback);
|
||||
}
|
||||
|
||||
void PythonSettings::createVirtualEnvironment(
|
||||
const FilePath &python,
|
||||
const FilePath &directory,
|
||||
const Interpreter &interpreter,
|
||||
const std::function<void(std::optional<Interpreter>)> &callback,
|
||||
const QString &nameSuffix)
|
||||
const std::function<void(const FilePath &)> &callback)
|
||||
{
|
||||
createVenv(interpreter.command, directory, [directory, callback, nameSuffix](bool success) {
|
||||
std::optional<Interpreter> result;
|
||||
if (success) {
|
||||
QTC_ASSERT(python.isExecutableFile(), return);
|
||||
QTC_ASSERT(!directory.exists() || directory.isDir(), return);
|
||||
|
||||
const CommandLine command(python, QStringList{"-m", "venv", directory.toUserOutput()});
|
||||
|
||||
auto process = new Process;
|
||||
auto progress = new Core::ProcessProgress(process);
|
||||
progress->setDisplayName(Tr::tr("Create Python venv"));
|
||||
QObject::connect(process, &Process::done, [directory, process, callback](){
|
||||
if (process->result() == ProcessResult::FinishedWithSuccess) {
|
||||
FilePath venvPython = directory.osType() == Utils::OsTypeWindows ? directory / "Scripts"
|
||||
: directory / "bin";
|
||||
venvPython = venvPython.pathAppended("python").withExecutableSuffix();
|
||||
if (venvPython.exists())
|
||||
result = PythonSettings::addInterpreter(venvPython, false, nameSuffix);
|
||||
if (venvPython.exists()) {
|
||||
if (callback)
|
||||
callback(venvPython);
|
||||
emit instance()->virtualEnvironmentCreated(venvPython);
|
||||
}
|
||||
}
|
||||
callback(result);
|
||||
process->deleteLater();
|
||||
});
|
||||
process->setCommand(command);
|
||||
process->start();
|
||||
}
|
||||
|
||||
QList<Interpreter> PythonSettings::detectPythonVenvs(const FilePath &path)
|
||||
|
@@ -35,12 +35,11 @@ public:
|
||||
static void createVirtualEnvironmentInteractive(
|
||||
const Utils::FilePath &startDirectory,
|
||||
const Interpreter &defaultInterpreter,
|
||||
const std::function<void(std::optional<Interpreter>)> &callback);
|
||||
const std::function<void(const Utils::FilePath &)> &callback);
|
||||
static void createVirtualEnvironment(
|
||||
const Utils::FilePath &interpreter,
|
||||
const Utils::FilePath &directory,
|
||||
const Interpreter &interpreter,
|
||||
const std::function<void(std::optional<Interpreter>)> &callback,
|
||||
const QString &nameSuffix = {});
|
||||
const std::function<void(const Utils::FilePath &)> &callback = {});
|
||||
static QList<Interpreter> detectPythonVenvs(const Utils::FilePath &path);
|
||||
static void addKitsForInterpreter(const Interpreter &interpreter);
|
||||
static void removeKitsForInterpreter(const Interpreter &interpreter);
|
||||
@@ -49,6 +48,7 @@ signals:
|
||||
void interpretersChanged(const QList<Interpreter> &interpreters, const QString &defaultId);
|
||||
void pylsConfigurationChanged(const QString &configuration);
|
||||
void pylsEnabledChanged(const bool enabled);
|
||||
void virtualEnvironmentCreated(const Utils::FilePath &venvPython);
|
||||
|
||||
public slots:
|
||||
void detectPythonOnDevice(const Utils::FilePaths &searchPaths,
|
||||
|
@@ -3,6 +3,9 @@
|
||||
|
||||
#include "pythonutils.h"
|
||||
|
||||
#include "pythonbuildconfiguration.h"
|
||||
#include "pythonconstants.h"
|
||||
#include "pythonkitaspect.h"
|
||||
#include "pythonproject.h"
|
||||
#include "pythonsettings.h"
|
||||
#include "pythontr.h"
|
||||
@@ -38,14 +41,12 @@ FilePath detectPython(const FilePath &documentPath)
|
||||
|
||||
FilePaths dirs = Environment::systemEnvironment().path();
|
||||
|
||||
if (project) {
|
||||
if (auto target = project->activeTarget()) {
|
||||
if (auto runConfig = target->activeRunConfiguration()) {
|
||||
if (auto interpreter = runConfig->aspect<InterpreterAspect>())
|
||||
return interpreter->currentInterpreter().command;
|
||||
if (auto environmentAspect = runConfig->aspect<EnvironmentAspect>())
|
||||
dirs = environmentAspect->environment().path();
|
||||
}
|
||||
if (project && project->mimeType() == Constants::C_PY_PROJECT_MIME_TYPE) {
|
||||
if (const Target *target = project->activeTarget()) {
|
||||
if (auto bc = qobject_cast<PythonBuildConfiguration *>(target->activeBuildConfiguration()))
|
||||
return bc->python();
|
||||
if (const std::optional<Interpreter> python = PythonKitAspect::python(target->kit()))
|
||||
return python->command;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,4 +187,9 @@ void createVenv(const Utils::FilePath &python,
|
||||
process->start();
|
||||
}
|
||||
|
||||
bool isVenvPython(const Utils::FilePath &python)
|
||||
{
|
||||
return python.parentDir().parentDir().contains("pyvenv.cfg");
|
||||
}
|
||||
|
||||
} // Python::Internal
|
||||
|
@@ -20,4 +20,6 @@ void createVenv(const Utils::FilePath &python,
|
||||
const Utils::FilePath &venvPath,
|
||||
const std::function<void(bool)> &callback);
|
||||
|
||||
bool isVenvPython(const Utils::FilePath &python);
|
||||
|
||||
} // Python::Internal
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "pythonwizardpage.h"
|
||||
|
||||
#include "pythonconstants.h"
|
||||
#include "pythonkitaspect.h"
|
||||
#include "pythonsettings.h"
|
||||
#include "pythontr.h"
|
||||
|
||||
@@ -14,6 +15,7 @@
|
||||
#include <utils/mimeutils.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <projectexplorer/kitmanager.h>
|
||||
#include <projectexplorer/project.h>
|
||||
#include <projectexplorer/projectmanager.h>
|
||||
#include <projectexplorer/target.h>
|
||||
@@ -86,11 +88,6 @@ PythonWizardPage::PythonWizardPage(const QList<QPair<QString, QVariant>> &pySide
|
||||
const int defaultPyside)
|
||||
{
|
||||
using namespace Layouting;
|
||||
m_interpreter.setSettingsDialogId(Constants::C_PYTHONOPTIONS_PAGE_ID);
|
||||
connect(PythonSettings::instance(),
|
||||
&PythonSettings::interpretersChanged,
|
||||
this,
|
||||
&PythonWizardPage::updateInterpreters);
|
||||
|
||||
m_pySideVersion.setLabelText(Tr::tr("PySide version:"));
|
||||
m_pySideVersion.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
|
||||
@@ -99,49 +96,13 @@ PythonWizardPage::PythonWizardPage(const QList<QPair<QString, QVariant>> &pySide
|
||||
if (defaultPyside >= 0)
|
||||
m_pySideVersion.setDefaultValue(defaultPyside);
|
||||
|
||||
m_createVenv.setLabelText(Tr::tr("Create new virtual environment"));
|
||||
|
||||
m_venvPath.setLabelText(Tr::tr("Path to virtual environment:"));
|
||||
m_venvPath.setEnabler(&m_createVenv);
|
||||
m_venvPath.setExpectedKind(PathChooser::Directory);
|
||||
|
||||
m_stateLabel = new InfoLabel();
|
||||
m_stateLabel->setWordWrap(true);
|
||||
m_stateLabel->setFilled(true);
|
||||
m_stateLabel->setType(InfoLabel::Error);
|
||||
connect(&m_venvPath, &FilePathAspect::validChanged, this, &PythonWizardPage::updateStateLabel);
|
||||
connect(&m_createVenv, &BaseAspect::changed, this, &PythonWizardPage::updateStateLabel);
|
||||
|
||||
Form {
|
||||
m_pySideVersion, st, br,
|
||||
m_interpreter, st, br,
|
||||
m_createVenv, st, br,
|
||||
m_venvPath, br,
|
||||
m_stateLabel, br
|
||||
}.attachTo(this);
|
||||
}
|
||||
|
||||
void PythonWizardPage::initializePage()
|
||||
{
|
||||
auto wiz = qobject_cast<JsonWizard *>(wizard());
|
||||
QTC_ASSERT(wiz, return);
|
||||
connect(wiz, &JsonWizard::filesPolished,
|
||||
this, &PythonWizardPage::setupProject,
|
||||
Qt::UniqueConnection);
|
||||
|
||||
const FilePath projectDir = FilePath::fromString(wiz->property("ProjectDirectory").toString());
|
||||
m_createVenv.setValue(!projectDir.isEmpty());
|
||||
if (m_venvPath().isEmpty())
|
||||
m_venvPath.setValue(projectDir.isEmpty() ? FilePath{} : projectDir / "venv");
|
||||
|
||||
updateInterpreters();
|
||||
updateStateLabel();
|
||||
}
|
||||
|
||||
bool PythonWizardPage::validatePage()
|
||||
{
|
||||
if (m_createVenv() && !m_venvPath.pathChooser()->isValid())
|
||||
return false;
|
||||
auto wiz = qobject_cast<JsonWizard *>(wizard());
|
||||
const QMap<QString, QVariant> data = m_pySideVersion.itemValue().toMap();
|
||||
for (auto it = data.begin(), end = data.end(); it != end; ++it)
|
||||
@@ -149,70 +110,5 @@ bool PythonWizardPage::validatePage()
|
||||
return true;
|
||||
}
|
||||
|
||||
void PythonWizardPage::setupProject(const JsonWizard::GeneratorFiles &files)
|
||||
{
|
||||
for (const JsonWizard::GeneratorFile &f : files) {
|
||||
if (f.file.attributes() & Core::GeneratedFile::OpenProjectAttribute) {
|
||||
Interpreter interpreter = m_interpreter.currentInterpreter();
|
||||
Project *project = ProjectManager::openProject(Utils::mimeTypeForFile(f.file.filePath()),
|
||||
f.file.filePath().absoluteFilePath());
|
||||
if (m_createVenv()) {
|
||||
auto openProjectWithInterpreter = [f](const std::optional<Interpreter> &interpreter) {
|
||||
if (!interpreter)
|
||||
return;
|
||||
Project *project = ProjectManager::projectWithProjectFilePath(f.file.filePath());
|
||||
if (!project)
|
||||
return;
|
||||
if (Target *target = project->activeTarget()) {
|
||||
if (RunConfiguration *rc = target->activeRunConfiguration()) {
|
||||
if (auto interpreters = rc->aspect<InterpreterAspect>())
|
||||
interpreters->setCurrentInterpreter(*interpreter);
|
||||
}
|
||||
}
|
||||
};
|
||||
PythonSettings::createVirtualEnvironment(m_venvPath(),
|
||||
interpreter,
|
||||
openProjectWithInterpreter,
|
||||
project ? project->displayName()
|
||||
: QString{});
|
||||
}
|
||||
|
||||
if (project) {
|
||||
project->addTargetForDefaultKit();
|
||||
if (Target *target = project->activeTarget()) {
|
||||
if (RunConfiguration *rc = target->activeRunConfiguration()) {
|
||||
if (auto interpreters = rc->aspect<InterpreterAspect>()) {
|
||||
interpreters->setCurrentInterpreter(interpreter);
|
||||
project->saveSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
delete project;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PythonWizardPage::updateInterpreters()
|
||||
{
|
||||
m_interpreter.setDefaultInterpreter(PythonSettings::defaultInterpreter());
|
||||
m_interpreter.updateInterpreters(PythonSettings::interpreters());
|
||||
}
|
||||
|
||||
void PythonWizardPage::updateStateLabel()
|
||||
{
|
||||
QTC_ASSERT(m_stateLabel, return);
|
||||
if (m_createVenv()) {
|
||||
if (PathChooser *pathChooser = m_venvPath.pathChooser()) {
|
||||
if (!pathChooser->isValid()) {
|
||||
m_stateLabel->show();
|
||||
m_stateLabel->setText(pathChooser->errorMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_stateLabel->hide();
|
||||
}
|
||||
|
||||
} // namespace Python::Internal
|
||||
|
||||
|
@@ -27,19 +27,10 @@ class PythonWizardPage : public Utils::WizardPage
|
||||
{
|
||||
public:
|
||||
PythonWizardPage(const QList<QPair<QString, QVariant>> &pySideAndData, const int defaultPyside);
|
||||
void initializePage() override;
|
||||
bool validatePage() override;
|
||||
|
||||
private:
|
||||
void setupProject(const ProjectExplorer::JsonWizard::GeneratorFiles &files);
|
||||
void updateInterpreters();
|
||||
void updateStateLabel();
|
||||
|
||||
ProjectExplorer::InterpreterAspect m_interpreter;
|
||||
Utils::SelectionAspect m_pySideVersion;
|
||||
Utils::BoolAspect m_createVenv;
|
||||
Utils::FilePathAspect m_venvPath;
|
||||
Utils::InfoLabel *m_stateLabel = nullptr;
|
||||
};
|
||||
|
||||
} // namespace Python::Internal
|
||||
|
Reference in New Issue
Block a user