forked from qt-creator/qt-creator
Python: offer to install pyside also in qml files
This shwos the same editor toolbar as in the python editor that offers to install pyside, if the qml file can be associated to a python project and the configured python for that project does not contain a valid pyside. Change-Id: Id05a2621aec9d78c4a22e61830813cd261eda4fc Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -4,9 +4,13 @@
|
|||||||
#include "pyside.h"
|
#include "pyside.h"
|
||||||
|
|
||||||
#include "pipsupport.h"
|
#include "pipsupport.h"
|
||||||
|
#include "pythonbuildconfiguration.h"
|
||||||
|
#include "pythonconstants.h"
|
||||||
|
#include "pythonproject.h"
|
||||||
#include "pythontr.h"
|
#include "pythontr.h"
|
||||||
#include "pythonutils.h"
|
#include "pythonutils.h"
|
||||||
|
|
||||||
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
#include <projectexplorer/runconfigurationaspects.h>
|
#include <projectexplorer/runconfigurationaspects.h>
|
||||||
@@ -19,8 +23,9 @@
|
|||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/async.h>
|
#include <utils/async.h>
|
||||||
#include <utils/infobar.h>
|
#include <utils/infobar.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/mimeconstants.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QBoxLayout>
|
#include <QBoxLayout>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
@@ -39,13 +44,13 @@ void PySideInstaller::checkPySideInstallation(const FilePath &python,
|
|||||||
TextEditor::TextDocument *document)
|
TextEditor::TextDocument *document)
|
||||||
{
|
{
|
||||||
document->infoBar()->removeInfo(installPySideInfoBarId);
|
document->infoBar()->removeInfo(installPySideInfoBarId);
|
||||||
if (QPointer<QFutureWatcher<bool>> watcher = pySideInstaller().m_futureWatchers.value(document))
|
if (QPointer<QFutureWatcher<bool>> watcher = m_futureWatchers.value(document))
|
||||||
watcher->cancel();
|
watcher->cancel();
|
||||||
if (!python.exists())
|
if (!python.exists())
|
||||||
return;
|
return;
|
||||||
const QString pySide = importedPySide(document->plainText());
|
const QString pySide = usedPySide(document->plainText(), document->mimeType());
|
||||||
if (pySide == "PySide2" || pySide == "PySide6")
|
if (pySide == "PySide2" || pySide == "PySide6")
|
||||||
pySideInstaller().runPySideChecker(python, pySide, document);
|
runPySideChecker(python, pySide, document);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PySideInstaller::missingPySideInstallation(const FilePath &pythonPath,
|
bool PySideInstaller::missingPySideInstallation(const FilePath &pythonPath,
|
||||||
@@ -65,15 +70,25 @@ bool PySideInstaller::missingPySideInstallation(const FilePath &pythonPath,
|
|||||||
return missing;
|
return missing;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString PySideInstaller::importedPySide(const QString &text)
|
QString PySideInstaller::usedPySide(const QString &text, const QString &mimeType)
|
||||||
{
|
{
|
||||||
static QRegularExpression importScanner("^\\s*(import|from)\\s+(PySide\\d)",
|
using namespace Python::Constants;
|
||||||
QRegularExpression::MultilineOption);
|
if (mimeType == C_PY_MIMETYPE || mimeType == C_PY3_MIMETYPE || mimeType == C_PY_GUI_MIMETYPE) {
|
||||||
const QRegularExpressionMatch match = importScanner.match(text);
|
static QRegularExpression
|
||||||
|
scanner("^\\s*(import|from)\\s+(PySide\\d)", QRegularExpression::MultilineOption);
|
||||||
|
const QRegularExpressionMatch match = scanner.match(text);
|
||||||
return match.captured(2);
|
return match.captured(2);
|
||||||
}
|
}
|
||||||
|
if (mimeType == Utils::Constants::QML_MIMETYPE)
|
||||||
|
return QStringLiteral("PySide6"); // Good enough for now.
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
PySideInstaller::PySideInstaller() = default;
|
PySideInstaller::PySideInstaller()
|
||||||
|
{
|
||||||
|
connect(Core::EditorManager::instance(), &Core::EditorManager::documentOpened,
|
||||||
|
this, &PySideInstaller::handleDocumentOpened);
|
||||||
|
}
|
||||||
|
|
||||||
void PySideInstaller::installPyside(const FilePath &python,
|
void PySideInstaller::installPyside(const FilePath &python,
|
||||||
const QString &pySide,
|
const QString &pySide,
|
||||||
@@ -191,6 +206,30 @@ void PySideInstaller::handlePySideMissing(const FilePath &python,
|
|||||||
document->infoBar()->addInfo(info);
|
document->infoBar()->addInfo(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PySideInstaller::handleDocumentOpened(Core::IDocument *document)
|
||||||
|
{
|
||||||
|
if (document->mimeType() != Utils::Constants::QML_MIMETYPE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
TextEditor::TextDocument *textDocument = qobject_cast<TextEditor::TextDocument *>(document);
|
||||||
|
if (!textDocument)
|
||||||
|
return;
|
||||||
|
PythonProject *project = pythonProjectForFile(textDocument->filePath());
|
||||||
|
if (!project)
|
||||||
|
return;
|
||||||
|
Target *target = project->activeTarget();
|
||||||
|
if (!target)
|
||||||
|
return;
|
||||||
|
BuildConfiguration *buildConfig = target->activeBuildConfiguration();
|
||||||
|
if (!buildConfig)
|
||||||
|
return;
|
||||||
|
auto *pythonBuildConfig = qobject_cast<PythonBuildConfiguration *>(buildConfig);
|
||||||
|
if (!pythonBuildConfig)
|
||||||
|
return;
|
||||||
|
|
||||||
|
PySideInstaller::instance().checkPySideInstallation(pythonBuildConfig->python(), textDocument);
|
||||||
|
}
|
||||||
|
|
||||||
void PySideInstaller::runPySideChecker(const FilePath &python,
|
void PySideInstaller::runPySideChecker(const FilePath &python,
|
||||||
const QString &pySide,
|
const QString &pySide,
|
||||||
TextEditor::TextDocument *document)
|
TextEditor::TextDocument *document)
|
||||||
@@ -217,7 +256,7 @@ void PySideInstaller::runPySideChecker(const FilePath &python,
|
|||||||
m_futureWatchers[document] = watcher;
|
m_futureWatchers[document] = watcher;
|
||||||
}
|
}
|
||||||
|
|
||||||
PySideInstaller &pySideInstaller()
|
PySideInstaller &PySideInstaller::instance()
|
||||||
{
|
{
|
||||||
static PySideInstaller thePySideInstaller;
|
static PySideInstaller thePySideInstaller;
|
||||||
return thePySideInstaller;
|
return thePySideInstaller;
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include <QPointer>
|
#include <QPointer>
|
||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
|
|
||||||
|
namespace Core { class IDocument; }
|
||||||
namespace TextEditor { class TextDocument; }
|
namespace TextEditor { class TextDocument; }
|
||||||
namespace ProjectExplorer { class RunConfiguration; }
|
namespace ProjectExplorer { class RunConfiguration; }
|
||||||
|
|
||||||
@@ -27,32 +28,30 @@ class PySideInstaller : public QObject
|
|||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void checkPySideInstallation(const Utils::FilePath &python,
|
void checkPySideInstallation(const Utils::FilePath &python, TextEditor::TextDocument *document);
|
||||||
TextEditor::TextDocument *document);
|
static PySideInstaller &instance();
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void pySideInstalled(const Utils::FilePath &python, const QString &pySide);
|
void pySideInstalled(const Utils::FilePath &python, const QString &pySide);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PySideInstaller();
|
PySideInstaller();
|
||||||
friend PySideInstaller &pySideInstaller();
|
|
||||||
|
|
||||||
void installPyside(const Utils::FilePath &python,
|
void installPyside(const Utils::FilePath &python,
|
||||||
const QString &pySide, TextEditor::TextDocument *document);
|
const QString &pySide, TextEditor::TextDocument *document);
|
||||||
void handlePySideMissing(const Utils::FilePath &python,
|
void handlePySideMissing(const Utils::FilePath &python,
|
||||||
const QString &pySide,
|
const QString &pySide,
|
||||||
TextEditor::TextDocument *document);
|
TextEditor::TextDocument *document);
|
||||||
|
void handleDocumentOpened(Core::IDocument *document);
|
||||||
|
|
||||||
void runPySideChecker(const Utils::FilePath &python,
|
void runPySideChecker(const Utils::FilePath &python,
|
||||||
const QString &pySide,
|
const QString &pySide,
|
||||||
TextEditor::TextDocument *document);
|
TextEditor::TextDocument *document);
|
||||||
static bool missingPySideInstallation(const Utils::FilePath &python, const QString &pySide);
|
static bool missingPySideInstallation(const Utils::FilePath &python, const QString &pySide);
|
||||||
static QString importedPySide(const QString &text);
|
static QString usedPySide(const QString &text, const QString &mimeType);
|
||||||
|
|
||||||
QHash<Utils::FilePath, QList<TextEditor::TextDocument *>> m_infoBarEntries;
|
QHash<Utils::FilePath, QList<TextEditor::TextDocument *>> m_infoBarEntries;
|
||||||
QHash<TextEditor::TextDocument *, QPointer<QFutureWatcher<bool>>> m_futureWatchers;
|
QHash<TextEditor::TextDocument *, QPointer<QFutureWatcher<bool>>> m_futureWatchers;
|
||||||
};
|
};
|
||||||
|
|
||||||
PySideInstaller &pySideInstaller();
|
|
||||||
|
|
||||||
} // Python::Internal
|
} // Python::Internal
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include <utils/detailswidget.h>
|
#include <utils/detailswidget.h>
|
||||||
#include <utils/futuresynchronizer.h>
|
#include <utils/futuresynchronizer.h>
|
||||||
#include <utils/layoutbuilder.h>
|
#include <utils/layoutbuilder.h>
|
||||||
|
#include <utils/mimeconstants.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
using namespace ProjectExplorer;
|
using namespace ProjectExplorer;
|
||||||
@@ -265,7 +266,7 @@ PythonBuildConfiguration::PythonBuildConfiguration(Target *target, const Id &id)
|
|||||||
|
|
||||||
updateCacheAndEmitEnvironmentChanged();
|
updateCacheAndEmitEnvironmentChanged();
|
||||||
|
|
||||||
connect(&pySideInstaller(),
|
connect(&PySideInstaller::instance(),
|
||||||
&PySideInstaller::pySideInstalled,
|
&PySideInstaller::pySideInstalled,
|
||||||
this,
|
this,
|
||||||
&PythonBuildConfiguration::handlePythonUpdated);
|
&PythonBuildConfiguration::handlePythonUpdated);
|
||||||
@@ -273,13 +274,7 @@ PythonBuildConfiguration::PythonBuildConfiguration(Target *target, const Id &id)
|
|||||||
auto update = [this] {
|
auto update = [this] {
|
||||||
if (isActive()) {
|
if (isActive()) {
|
||||||
m_buildSystem->emitBuildSystemUpdated();
|
m_buildSystem->emitBuildSystemUpdated();
|
||||||
const FilePaths files = project()->files(Project::AllFiles);
|
updateDocuments();
|
||||||
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(target, &Target::activeBuildConfigurationChanged, this, update);
|
||||||
@@ -338,16 +333,23 @@ void PythonBuildConfiguration::updatePython(const FilePath &python)
|
|||||||
m_python = python;
|
m_python = python;
|
||||||
if (auto buildStep = buildSteps()->firstOfType<PySideBuildStep>())
|
if (auto buildStep = buildSteps()->firstOfType<PySideBuildStep>())
|
||||||
buildStep->checkForPySide(python);
|
buildStep->checkForPySide(python);
|
||||||
|
updateDocuments();
|
||||||
|
m_buildSystem->requestParse();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PythonBuildConfiguration::updateDocuments()
|
||||||
|
{
|
||||||
if (isActive()) {
|
if (isActive()) {
|
||||||
const FilePaths files = project()->files(Project::AllFiles);
|
const FilePaths files = project()->files(Project::AllFiles);
|
||||||
for (const FilePath &file : files) {
|
for (const FilePath &file : files) {
|
||||||
if (auto doc = qobject_cast<PythonDocument *>(
|
if (auto doc = TextEditor::TextDocument::textDocumentForFilePath(file)) {
|
||||||
Core::DocumentModel::documentForFilePath(file))) {
|
if (auto pyDoc = qobject_cast<PythonDocument *>(doc))
|
||||||
doc->updatePython(m_python);
|
pyDoc->updatePython(m_python);
|
||||||
|
else if (doc->mimeType() == Utils::Constants::QML_MIMETYPE)
|
||||||
|
PySideInstaller::instance().checkPySideInstallation(m_python, doc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_buildSystem->requestParse();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PythonBuildConfiguration::handlePythonUpdated(const FilePath &python)
|
void PythonBuildConfiguration::handlePythonUpdated(const FilePath &python)
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ private:
|
|||||||
void initialize(const ProjectExplorer::BuildInfo &info);
|
void initialize(const ProjectExplorer::BuildInfo &info);
|
||||||
void updateInterpreter(const std::optional<ProjectExplorer::Interpreter> &python);
|
void updateInterpreter(const std::optional<ProjectExplorer::Interpreter> &python);
|
||||||
void updatePython(const Utils::FilePath &python);
|
void updatePython(const Utils::FilePath &python);
|
||||||
|
void updateDocuments();
|
||||||
void handlePythonUpdated(const Utils::FilePath &python);
|
void handlePythonUpdated(const Utils::FilePath &python);
|
||||||
|
|
||||||
Utils::FilePath m_python;
|
Utils::FilePath m_python;
|
||||||
|
|||||||
@@ -303,7 +303,7 @@ void PythonDocument::updateCurrentPython()
|
|||||||
void PythonDocument::updatePython(const FilePath &python)
|
void PythonDocument::updatePython(const FilePath &python)
|
||||||
{
|
{
|
||||||
openDocumentWithPython(python, this);
|
openDocumentWithPython(python, this);
|
||||||
PySideInstaller::checkPySideInstallation(python, this);
|
PySideInstaller::instance().checkPySideInstallation(python, this);
|
||||||
emit pythonUpdated(python);
|
emit pythonUpdated(python);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -158,11 +158,11 @@ QString pythonName(const FilePath &pythonPath)
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
PythonProject *pythonProjectForFile(const FilePath &pythonFile)
|
PythonProject *pythonProjectForFile(const FilePath &file)
|
||||||
{
|
{
|
||||||
for (Project *project : ProjectManager::projects()) {
|
for (Project *project : ProjectManager::projects()) {
|
||||||
if (auto pythonProject = qobject_cast<PythonProject *>(project)) {
|
if (auto pythonProject = qobject_cast<PythonProject *>(project)) {
|
||||||
if (pythonProject->isKnownFile(pythonFile))
|
if (pythonProject->isKnownFile(file))
|
||||||
return pythonProject;
|
return pythonProject;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user