forked from qt-creator/qt-creator
Python: add create venv option to the wizard
and optimize layouting Fixes: PYSIDE-2152 Change-Id: If3ecb76c4bac885840f54fd382471ac22a06dee3 Reviewed-by: Christian Stenger <christian.stenger@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -251,7 +251,7 @@ void PythonEditorWidget::updateInterpretersSelector()
|
|||||||
if (self && venvInterpreter)
|
if (self && venvInterpreter)
|
||||||
self->setUserDefinedPython(*venvInterpreter);
|
self->setUserDefinedPython(*venvInterpreter);
|
||||||
};
|
};
|
||||||
PythonSettings::createVirtualEnvironment(self->textDocument()
|
PythonSettings::createVirtualEnvironmentInteractive(self->textDocument()
|
||||||
->filePath()
|
->filePath()
|
||||||
.parentDir(),
|
.parentDir(),
|
||||||
*currentInterpreter,
|
*currentInterpreter,
|
||||||
|
|||||||
@@ -773,9 +773,11 @@ void PythonSettings::addInterpreter(const Interpreter &interpreter, bool isDefau
|
|||||||
saveSettings();
|
saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
Interpreter PythonSettings::addInterpreter(const FilePath &interpreterPath, bool isDefault)
|
Interpreter PythonSettings::addInterpreter(const FilePath &interpreterPath,
|
||||||
|
bool isDefault,
|
||||||
|
const QString &nameSuffix)
|
||||||
{
|
{
|
||||||
const Interpreter interpreter = createInterpreter(interpreterPath, {});
|
const Interpreter interpreter = createInterpreter(interpreterPath, {}, nameSuffix);
|
||||||
addInterpreter(interpreter, isDefault);
|
addInterpreter(interpreter, isDefault);
|
||||||
return interpreter;
|
return interpreter;
|
||||||
}
|
}
|
||||||
@@ -786,7 +788,7 @@ PythonSettings *PythonSettings::instance()
|
|||||||
return settingsInstance;
|
return settingsInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PythonSettings::createVirtualEnvironment(
|
void PythonSettings::createVirtualEnvironmentInteractive(
|
||||||
const FilePath &startDirectory,
|
const FilePath &startDirectory,
|
||||||
const Interpreter &defaultInterpreter,
|
const Interpreter &defaultInterpreter,
|
||||||
const std::function<void(std::optional<Interpreter>)> &callback)
|
const std::function<void(std::optional<Interpreter>)> &callback)
|
||||||
@@ -829,14 +831,23 @@ void PythonSettings::createVirtualEnvironment(
|
|||||||
interpreters->currentData().toString());
|
interpreters->currentData().toString());
|
||||||
|
|
||||||
auto venvDir = pathChooser->filePath();
|
auto venvDir = pathChooser->filePath();
|
||||||
createVenv(interpreter.command, venvDir, [venvDir, callback](bool success){
|
createVirtualEnvironment(venvDir, interpreter, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PythonSettings::createVirtualEnvironment(
|
||||||
|
const FilePath &directory,
|
||||||
|
const Interpreter &interpreter,
|
||||||
|
const std::function<void(std::optional<Interpreter>)> &callback,
|
||||||
|
const QString &nameSuffix)
|
||||||
|
{
|
||||||
|
createVenv(interpreter.command, directory, [directory, callback, nameSuffix](bool success) {
|
||||||
std::optional<Interpreter> result;
|
std::optional<Interpreter> result;
|
||||||
if (success) {
|
if (success) {
|
||||||
FilePath venvPython = venvDir.osType() == Utils::OsTypeWindows ? venvDir / "Scripts"
|
FilePath venvPython = directory.osType() == Utils::OsTypeWindows ? directory / "Scripts"
|
||||||
: venvDir / "bin";
|
: directory / "bin";
|
||||||
venvPython = venvPython.pathAppended("python").withExecutableSuffix();
|
venvPython = venvPython.pathAppended("python").withExecutableSuffix();
|
||||||
if (venvPython.exists())
|
if (venvPython.exists())
|
||||||
result = PythonSettings::addInterpreter(venvPython);
|
result = PythonSettings::addInterpreter(venvPython, false, nameSuffix);
|
||||||
}
|
}
|
||||||
callback(result);
|
callback(result);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,13 +25,22 @@ public:
|
|||||||
static void setInterpreter(const QList<Interpreter> &interpreters, const QString &defaultId);
|
static void setInterpreter(const QList<Interpreter> &interpreters, const QString &defaultId);
|
||||||
static void addInterpreter(const Interpreter &interpreter, bool isDefault = false);
|
static void addInterpreter(const Interpreter &interpreter, bool isDefault = false);
|
||||||
static Interpreter addInterpreter(const Utils::FilePath &interpreterPath,
|
static Interpreter addInterpreter(const Utils::FilePath &interpreterPath,
|
||||||
bool isDefault = false);
|
bool isDefault = false,
|
||||||
|
const QString &nameSuffix = {});
|
||||||
static void setPyLSConfiguration(const QString &configuration);
|
static void setPyLSConfiguration(const QString &configuration);
|
||||||
static bool pylsEnabled();
|
static bool pylsEnabled();
|
||||||
static void setPylsEnabled(const bool &enabled);
|
static void setPylsEnabled(const bool &enabled);
|
||||||
static QString pylsConfiguration();
|
static QString pylsConfiguration();
|
||||||
static PythonSettings *instance();
|
static PythonSettings *instance();
|
||||||
static void createVirtualEnvironment(const Utils::FilePath &startDirectory, const Interpreter &defaultInterpreter, const std::function<void (std::optional<Interpreter>)> &callback);
|
static void createVirtualEnvironmentInteractive(
|
||||||
|
const Utils::FilePath &startDirectory,
|
||||||
|
const Interpreter &defaultInterpreter,
|
||||||
|
const std::function<void(std::optional<Interpreter>)> &callback);
|
||||||
|
static void createVirtualEnvironment(
|
||||||
|
const Utils::FilePath &directory,
|
||||||
|
const Interpreter &interpreter,
|
||||||
|
const std::function<void(std::optional<Interpreter>)> &callback,
|
||||||
|
const QString &nameSuffix = {});
|
||||||
static QList<Interpreter> detectPythonVenvs(const Utils::FilePath &path);
|
static QList<Interpreter> detectPythonVenvs(const Utils::FilePath &path);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|||||||
@@ -34,18 +34,18 @@ WizardPage *PythonWizardPageFactory::create(JsonWizard *wizard, Id typeId, const
|
|||||||
|
|
||||||
QTC_ASSERT(canCreate(typeId), return nullptr);
|
QTC_ASSERT(canCreate(typeId), return nullptr);
|
||||||
|
|
||||||
auto page = new PythonWizardPage;
|
QList<QPair<QString, QVariant>> pySideAndData;
|
||||||
for (const QVariant &item : data.toMap().value("items").toList()) {
|
for (const QVariant &item : data.toMap().value("items").toList()) {
|
||||||
const QMap<QString, QVariant> map = item.toMap();
|
const QMap<QString, QVariant> map = item.toMap();
|
||||||
const QVariant name = map.value("trKey");
|
const QVariant name = map.value("trKey");
|
||||||
if (name.isValid())
|
if (name.isValid())
|
||||||
page->addPySideVersions(name.toString(), map.value("value"));
|
pySideAndData.emplaceBack(QPair<QString, QVariant>{name.toString(), map.value("value")});
|
||||||
}
|
}
|
||||||
bool validIndex = false;
|
bool validIndex = false;
|
||||||
const int index = data.toMap().value("index").toInt(&validIndex);
|
int defaultPySide = data.toMap().value("index").toInt(&validIndex);
|
||||||
if (validIndex)
|
if (!validIndex)
|
||||||
page->setDefaultPySideVersions(index);
|
defaultPySide = -1;
|
||||||
return page;
|
return new PythonWizardPage(pySideAndData, defaultPySide);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool validItem(const QVariant &item)
|
static bool validItem(const QVariant &item)
|
||||||
@@ -82,8 +82,10 @@ bool PythonWizardPageFactory::validateData(Id typeId, const QVariant &data, QStr
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
PythonWizardPage::PythonWizardPage()
|
PythonWizardPage::PythonWizardPage(const QList<QPair<QString, QVariant>> &pySideAndData,
|
||||||
|
const int defaultPyside)
|
||||||
{
|
{
|
||||||
|
using namespace Utils::Layouting;
|
||||||
m_interpreter.setSettingsDialogId(Constants::C_PYTHONOPTIONS_PAGE_ID);
|
m_interpreter.setSettingsDialogId(Constants::C_PYTHONOPTIONS_PAGE_ID);
|
||||||
connect(PythonSettings::instance(),
|
connect(PythonSettings::instance(),
|
||||||
&PythonSettings::interpretersChanged,
|
&PythonSettings::interpretersChanged,
|
||||||
@@ -92,27 +94,55 @@ PythonWizardPage::PythonWizardPage()
|
|||||||
|
|
||||||
m_pySideVersion.setLabelText(Tr::tr("PySide version"));
|
m_pySideVersion.setLabelText(Tr::tr("PySide version"));
|
||||||
m_pySideVersion.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
|
m_pySideVersion.setDisplayStyle(SelectionAspect::DisplayStyle::ComboBox);
|
||||||
|
for (auto [name, data] : pySideAndData)
|
||||||
|
m_pySideVersion.addOption(SelectionAspect::Option(name, {}, data));
|
||||||
|
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.setDisplayStyle(StringAspect::PathChooserDisplay);
|
||||||
|
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, &StringAspect::valueChanged, this, &PythonWizardPage::updateStateLabel);
|
||||||
|
connect(&m_createVenv, &BoolAspect::valueChanged, this, &PythonWizardPage::updateStateLabel);
|
||||||
|
|
||||||
|
Grid {
|
||||||
|
m_pySideVersion, br,
|
||||||
|
m_interpreter, br,
|
||||||
|
m_createVenv, br,
|
||||||
|
m_venvPath, br,
|
||||||
|
m_stateLabel, br
|
||||||
|
}.attachTo(this, WithoutMargins);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PythonWizardPage::initializePage()
|
void PythonWizardPage::initializePage()
|
||||||
{
|
{
|
||||||
using namespace Utils::Layouting;
|
|
||||||
|
|
||||||
auto wiz = qobject_cast<JsonWizard *>(wizard());
|
auto wiz = qobject_cast<JsonWizard *>(wizard());
|
||||||
QTC_ASSERT(wiz, return);
|
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.filePath().isEmpty())
|
||||||
|
m_venvPath.setFilePath(projectDir.isEmpty() ? FilePath{} : projectDir / "venv");
|
||||||
|
|
||||||
updateInterpreters();
|
updateInterpreters();
|
||||||
|
updateStateLabel();
|
||||||
connect(wiz, &JsonWizard::filesPolished, this, &PythonWizardPage::setupProject);
|
|
||||||
|
|
||||||
Grid {
|
|
||||||
m_pySideVersion, br,
|
|
||||||
m_interpreter, br
|
|
||||||
}.attachTo(this, WithoutMargins);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PythonWizardPage::validatePage()
|
bool PythonWizardPage::validatePage()
|
||||||
{
|
{
|
||||||
|
if (m_createVenv.value() && !m_venvPath.pathChooser()->isValid())
|
||||||
|
return false;
|
||||||
auto wiz = qobject_cast<JsonWizard *>(wizard());
|
auto wiz = qobject_cast<JsonWizard *>(wizard());
|
||||||
const QMap<QString, QVariant> data = m_pySideVersion.itemValue().toMap();
|
const QMap<QString, QVariant> data = m_pySideVersion.itemValue().toMap();
|
||||||
for (auto it = data.begin(), end = data.end(); it != end; ++it)
|
for (auto it = data.begin(), end = data.end(); it != end; ++it)
|
||||||
@@ -120,28 +150,40 @@ bool PythonWizardPage::validatePage()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PythonWizardPage::addPySideVersions(const QString &name, const QVariant &data)
|
|
||||||
{
|
|
||||||
m_pySideVersion.addOption(SelectionAspect::Option(name, {}, data));
|
|
||||||
}
|
|
||||||
|
|
||||||
void PythonWizardPage::setDefaultPySideVersions(int index)
|
|
||||||
{
|
|
||||||
m_pySideVersion.setDefaultValue(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PythonWizardPage::setupProject(const JsonWizard::GeneratorFiles &files)
|
void PythonWizardPage::setupProject(const JsonWizard::GeneratorFiles &files)
|
||||||
{
|
{
|
||||||
for (const JsonWizard::GeneratorFile &f : files) {
|
for (const JsonWizard::GeneratorFile &f : files) {
|
||||||
if (f.file.attributes() & Core::GeneratedFile::OpenProjectAttribute) {
|
if (f.file.attributes() & Core::GeneratedFile::OpenProjectAttribute) {
|
||||||
|
Interpreter interpreter = m_interpreter.currentInterpreter();
|
||||||
Project *project = ProjectManager::openProject(Utils::mimeTypeForFile(f.file.filePath()),
|
Project *project = ProjectManager::openProject(Utils::mimeTypeForFile(f.file.filePath()),
|
||||||
f.file.filePath().absoluteFilePath());
|
f.file.filePath().absoluteFilePath());
|
||||||
|
if (m_createVenv.value()) {
|
||||||
|
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.filePath(),
|
||||||
|
interpreter,
|
||||||
|
openProjectWithInterpreter,
|
||||||
|
project ? project->displayName()
|
||||||
|
: QString{});
|
||||||
|
}
|
||||||
|
|
||||||
if (project) {
|
if (project) {
|
||||||
project->addTargetForDefaultKit();
|
project->addTargetForDefaultKit();
|
||||||
if (Target *target = project->activeTarget()) {
|
if (Target *target = project->activeTarget()) {
|
||||||
if (RunConfiguration *rc = target->activeRunConfiguration()) {
|
if (RunConfiguration *rc = target->activeRunConfiguration()) {
|
||||||
if (auto interpreters = rc->aspect<InterpreterAspect>()) {
|
if (auto interpreters = rc->aspect<InterpreterAspect>()) {
|
||||||
interpreters->setCurrentInterpreter(m_interpreter.currentInterpreter());
|
interpreters->setCurrentInterpreter(interpreter);
|
||||||
project->saveSettings();
|
project->saveSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,5 +200,20 @@ void PythonWizardPage::updateInterpreters()
|
|||||||
m_interpreter.updateInterpreters(PythonSettings::interpreters());
|
m_interpreter.updateInterpreters(PythonSettings::interpreters());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PythonWizardPage::updateStateLabel()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_stateLabel, return);
|
||||||
|
if (m_createVenv.value()) {
|
||||||
|
if (PathChooser *pathChooser = m_venvPath.pathChooser()) {
|
||||||
|
if (!pathChooser->isValid()) {
|
||||||
|
m_stateLabel->show();
|
||||||
|
m_stateLabel->setText(pathChooser->errorMessage());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_stateLabel->hide();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Python::Internal
|
} // namespace Python::Internal
|
||||||
|
|
||||||
|
|||||||
@@ -24,19 +24,20 @@ public:
|
|||||||
class PythonWizardPage : public Utils::WizardPage
|
class PythonWizardPage : public Utils::WizardPage
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PythonWizardPage();
|
PythonWizardPage(const QList<QPair<QString, QVariant>> &pySideAndData, const int defaultPyside);
|
||||||
void initializePage() override;
|
void initializePage() override;
|
||||||
bool validatePage() override;
|
bool validatePage() override;
|
||||||
|
|
||||||
void addPySideVersions(const QString &name, const QVariant &data);
|
|
||||||
void setDefaultPySideVersions(int index);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupProject(const ProjectExplorer::JsonWizard::GeneratorFiles &files);
|
void setupProject(const ProjectExplorer::JsonWizard::GeneratorFiles &files);
|
||||||
void updateInterpreters();
|
void updateInterpreters();
|
||||||
|
void updateStateLabel();
|
||||||
|
|
||||||
ProjectExplorer::InterpreterAspect m_interpreter;
|
ProjectExplorer::InterpreterAspect m_interpreter;
|
||||||
Utils::SelectionAspect m_pySideVersion;
|
Utils::SelectionAspect m_pySideVersion;
|
||||||
|
Utils::BoolAspect m_createVenv;
|
||||||
|
Utils::StringAspect m_venvPath;
|
||||||
|
Utils::InfoLabel *m_stateLabel = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Python::Internal
|
} // namespace Python::Internal
|
||||||
|
|||||||
Reference in New Issue
Block a user