Files
qt-creator/src/plugins/python/pyside.cpp

138 lines
4.8 KiB
C++
Raw Normal View History

// 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 "pyside.h"
#include "pipsupport.h"
#include "pythonplugin.h"
#include "pythonsettings.h"
#include "pythontr.h"
#include "pythonutils.h"
#include <coreplugin/icore.h>
#include <projectexplorer/runconfigurationaspects.h>
#include <projectexplorer/target.h>
#include <texteditor/textdocument.h>
#include <utils/algorithm.h>
#include <utils/asynctask.h>
#include <utils/infobar.h>
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <QRegularExpression>
#include <QTextCursor>
using namespace Utils;
using namespace ProjectExplorer;
namespace Python::Internal {
const char installPySideInfoBarId[] = "Python::InstallPySide";
PySideInstaller *PySideInstaller::instance()
{
static PySideInstaller *instance = new PySideInstaller; // FIXME: Leaks.
return instance;
}
void PySideInstaller::checkPySideInstallation(const FilePath &python,
TextEditor::TextDocument *document)
{
document->infoBar()->removeInfo(installPySideInfoBarId);
const QString pySide = importedPySide(document->plainText());
if (pySide == "PySide2" || pySide == "PySide6")
instance()->runPySideChecker(python, pySide, document);
}
bool PySideInstaller::missingPySideInstallation(const FilePath &pythonPath,
const QString &pySide)
{
QTC_ASSERT(!pySide.isEmpty(), return false);
static QMap<FilePath, QSet<QString>> pythonWithPyside;
if (pythonWithPyside[pythonPath].contains(pySide))
return false;
QtcProcess pythonProcess;
pythonProcess.setCommand({pythonPath, {"-c", "import " + pySide}});
pythonProcess.runBlocking();
const bool missing = pythonProcess.result() != ProcessResult::FinishedWithSuccess;
if (!missing)
pythonWithPyside[pythonPath].insert(pySide);
return missing;
}
QString PySideInstaller::importedPySide(const QString &text)
{
static QRegularExpression importScanner("^\\s*(import|from)\\s+(PySide\\d)",
QRegularExpression::MultilineOption);
const QRegularExpressionMatch match = importScanner.match(text);
return match.captured(2);
}
PySideInstaller::PySideInstaller()
: QObject(PythonPlugin::instance())
{}
void PySideInstaller::installPyside(const FilePath &python,
const QString &pySide,
TextEditor::TextDocument *document)
{
document->infoBar()->removeInfo(installPySideInfoBarId);
auto install = new PipInstallTask(python);
connect(install, &PipInstallTask::finished, install, &QObject::deleteLater);
connect(install, &PipInstallTask::finished, this, [=](bool success){
if (success)
emit pySideInstalled(python, pySide);
});
install->setPackages({PipPackage(pySide)});
install->run();
}
void PySideInstaller::handlePySideMissing(const FilePath &python,
const QString &pySide,
TextEditor::TextDocument *document)
{
if (!document || !document->infoBar()->canInfoBeAdded(installPySideInfoBarId))
return;
const QString message = Tr::tr("%1 installation missing for %2 (%3)")
.arg(pySide, pythonName(python), python.toUserOutput());
InfoBarEntry info(installPySideInfoBarId, message, InfoBarEntry::GlobalSuppression::Enabled);
auto installCallback = [=]() { installPyside(python, pySide, document); };
const QString installTooltip = Tr::tr("Install %1 for %2 using pip package installer.")
.arg(pySide, python.toUserOutput());
info.addCustomButton(Tr::tr("Install"), installCallback, installTooltip);
document->infoBar()->addInfo(info);
}
void PySideInstaller::runPySideChecker(const FilePath &python,
const QString &pySide,
TextEditor::TextDocument *document)
{
using CheckPySideWatcher = QFutureWatcher<bool>;
QPointer<CheckPySideWatcher> watcher = new CheckPySideWatcher();
// cancel and delete watcher after a 10 second timeout
QTimer::singleShot(10000, this, [watcher]() {
if (watcher) {
watcher->cancel();
watcher->deleteLater();
}
});
connect(watcher,
&CheckPySideWatcher::resultReadyAt,
this,
[=, document = QPointer<TextEditor::TextDocument>(document)]() {
if (watcher->result())
handlePySideMissing(python, pySide, document);
watcher->deleteLater();
});
watcher->setFuture(Utils::asyncRun(&missingPySideInstallation, python, pySide));
}
} // Python::Internal