QmlProjectManager: Integrate QDS landing page

Task-number: QDS-6564
Change-Id: Ia1a4188ba1bb561bbfeadf5fb29bcba75d05b5ce
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Tapani Mattila
2022-05-06 14:27:58 +03:00
parent 515845b815
commit 8bb1a862a0
7 changed files with 412 additions and 83 deletions

View File

@@ -23,16 +23,19 @@
**
****************************************************************************/
#include "qdslandingpage.h"
#include "qmlprojectplugin.h"
#include "qmlproject.h"
#include "qmlprojectconstants.h"
#include "qmlprojectrunconfiguration.h"
#include "projectfilecontenttools.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/coreconstants.h>
#include <coreplugin/designmode.h>
#include <coreplugin/fileiconprovider.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
#include <coreplugin/modemanager.h>
#include <projectexplorer/projectmanager.h>
#include <projectexplorer/runcontrol.h>
@@ -40,14 +43,18 @@
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <qmljseditor/qmljseditor.h>
#include <qmljseditor/qmljseditorconstants.h>
#include <qmljstools/qmljstoolsconstants.h>
#include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginspec.h>
#include <utils/infobar.h>
#include <utils/fileutils.h>
#include <utils/qtcprocess.h>
#include <QDesktopServices>
#include <QMessageBox>
#include <QPushButton>
#include <QTimer>
@@ -58,8 +65,8 @@ using namespace ProjectExplorer;
namespace QmlProjectManager {
namespace Internal {
const char openInQDSAppInfoBar[] = "OpenInQDSAppUiQml";
const char alwaysOpenUiQmlInQDS[] = "J.QtQuick/QmlJSEditor.openUiQmlFilesInQDS";
const char alwaysOpenUiQmlMode[] = "J.QtQuick/QmlJSEditor.openUiQmlMode";
const char installQdsUrl[] = "https://www.qt.io/product/ui-design-tools";
static bool isQmlDesigner(const ExtensionSystem::PluginSpec *spec)
{
@@ -76,14 +83,19 @@ static bool qmlDesignerEnabled()
return it != plugins.end() && (*it)->plugin();
}
static bool alwaysOpenUiQmlfileInQds()
static QString alwaysOpenWithMode()
{
return Core::ICore::settings()->value(alwaysOpenUiQmlInQDS, false).toBool();
return Core::ICore::settings()->value(alwaysOpenUiQmlMode, "").toString();
}
static void enableAlwaysOpenUiQmlfileInQds()
static void setAlwaysOpenWithMode(const QString &mode)
{
return Core::ICore::settings()->setValue(alwaysOpenUiQmlInQDS, true);
Core::ICore::settings()->setValue(alwaysOpenUiQmlMode, mode);
}
static void clearAlwaysOpenWithMode()
{
Core::ICore::settings()->remove(alwaysOpenUiQmlMode);
}
class QmlProjectPluginPrivate
@@ -94,12 +106,15 @@ public:
{ProjectExplorer::Constants::NORMAL_RUN_MODE},
{runConfigFactory.runConfigurationId()}};
QPointer<QMessageBox> lastMessageBox;
QdsLandingPage *landingPage = nullptr;
};
QmlProjectPlugin::~QmlProjectPlugin()
{
if (d->lastMessageBox)
d->lastMessageBox->deleteLater();
if (d->landingPage)
d->landingPage->deleteLater();
delete d;
}
@@ -119,6 +134,8 @@ void QmlProjectPlugin::openQDS(const Utils::FilePath &fileName)
QMessageBox::warning(Core::ICore::dialogParent(),
fileName.fileName(),
QObject::tr("Failed to start Qt Design Studio."));
if (alwaysOpenWithMode() == Core::Constants::MODE_DESIGN)
clearAlwaysOpenWithMode();
}
}
@@ -135,15 +152,30 @@ bool QmlProjectPlugin::qdsInstallationExists()
return qdsInstallationEntry().exists();
}
Utils::FilePath findQmlProject(const Utils::FilePath &folder)
bool QmlProjectPlugin::checkIfEditorIsuiQml(Core::IEditor *editor)
{
QDir dir = folder.toDir();
for (const QString &file : dir.entryList({"*.qmlproject"}))
return Utils::FilePath::fromString(folder.toString() + "/" + file);
return {};
if (editor
&& (editor->document()->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID
|| editor->document()->id() == QmlJSEditor::Constants::C_QTQUICKDESIGNEREDITOR_ID)) {
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
QmlJS::Document::Ptr document =
modelManager->ensuredGetDocumentForPath(editor->document()->filePath().toString());
if (!document.isNull())
return document->language() == QmlJS::Dialect::QmlQtQuick2Ui;
}
return false;
}
Utils::FilePath findQmlProjectUpwards(const Utils::FilePath &folder)
const Utils::FilePath findQmlProject(const Utils::FilePath &folder)
{
const Utils::FilePaths files = folder.dirEntries({QStringList("*.qmlproject"), QDir::Files});
if (files.isEmpty())
return {};
return files.constFirst();
}
const Utils::FilePath findQmlProjectUpwards(const Utils::FilePath &folder)
{
auto ret = findQmlProject(folder);
if (ret.exists())
@@ -205,55 +237,7 @@ bool QmlProjectPlugin::initialize(const QStringList &, QString *errorMessage)
d = new QmlProjectPluginPrivate;
if (!qmlDesignerEnabled()) {
connect(Core::EditorManager::instance(),
&Core::EditorManager::currentEditorChanged,
[this](Core::IEditor *editor) {
QmlJS::ModelManagerInterface *modelManager
= QmlJS::ModelManagerInterface::instance();
if (!editor || !modelManager)
return;
if (d->lastMessageBox)
return;
auto filePath = editor->document()->filePath();
QmlJS::Document::Ptr document = modelManager->ensuredGetDocumentForPath(
filePath.toString());
if (!document.isNull()
&& document->language() == QmlJS::Dialect::QmlQtQuick2Ui) {
const QString description = tr("Files of the type ui.qml are intended for Qt Design Studio.");
if (!qdsInstallationExists()) {
if (Core::ICore::infoBar()->canInfoBeAdded(openInQDSAppInfoBar)) {
Utils::InfoBarEntry
info(openInQDSAppInfoBar,
description + tr(" Learn more about Qt Design Studio here: ")
+ "<a href='https://www.qt.io/product/ui-design-tools'>Qt Design Studio</a>",
Utils::InfoBarEntry::GlobalSuppression::Disabled);
Core::ICore::infoBar()->addInfo(info);
}
return;
}
if (alwaysOpenUiQmlfileInQds()) {
openInQDSWithProject(filePath);
} else if (Core::ICore::infoBar()->canInfoBeAdded(openInQDSAppInfoBar)) {
Utils::InfoBarEntry
info(openInQDSAppInfoBar,
description + "\n" + tr("Do you want to open this file always in Qt Design Studio?"),
Utils::InfoBarEntry::GlobalSuppression::Disabled);
info.addCustomButton(tr("Always open in Qt Design Studio"), [filePath] {
Core::ICore::infoBar()->removeInfo(openInQDSAppInfoBar);
enableAlwaysOpenUiQmlfileInQds();
openInQDSWithProject(filePath);
});
Core::ICore::infoBar()->addInfo(info);
}
}
});
initializeQmlLandingPage();
}
ProjectManager::registerProjectType<QmlProject>(QmlJSTools::Constants::QMLPROJECT_MIMETYPE);
@@ -262,5 +246,112 @@ bool QmlProjectPlugin::initialize(const QStringList &, QString *errorMessage)
return true;
}
void QmlProjectPlugin::initializeQmlLandingPage()
{
d->landingPage = new QdsLandingPage();
connect(d->landingPage, &QdsLandingPage::openCreator, this, &QmlProjectPlugin::openQtc);
connect(d->landingPage, &QdsLandingPage::openDesigner, this, &QmlProjectPlugin::openQds);
connect(d->landingPage, &QdsLandingPage::installDesigner, this, &QmlProjectPlugin::installQds);
connect(d->landingPage, &QdsLandingPage::generateCmake, this, &QmlProjectPlugin::generateCmake);
connect(d->landingPage, &QdsLandingPage::generateProjectFile, this, &QmlProjectPlugin::generateProjectFile);
auto dialog = d->landingPage->dialog();
const QStringList mimeTypes = {QmlJSTools::Constants::QMLUI_MIMETYPE};
auto context = new Internal::DesignModeContext(dialog);
Core::ICore::addContextObject(context);
Core::DesignMode::registerDesignWidget(dialog, mimeTypes, context->context());
connect(Core::ModeManager::instance(), &Core::ModeManager::currentModeChanged,
this, &QmlProjectPlugin::editorModeChanged);
}
void QmlProjectPlugin::displayQmlLandingPage()
{
const QString qtVersionString = ProjectFileContentTools::qtVersion(projectFilePath());
const QString qdsVersionString = ProjectFileContentTools::qdsVersion(projectFilePath());
d->landingPage->setQdsInstalled(qdsInstallationExists());
d->landingPage->setProjectFileExists(projectFilePath().exists());
d->landingPage->setCmakeResources(ProjectFileContentTools::rootCmakeFiles());
d->landingPage->setQtVersion(qtVersionString);
d->landingPage->setQdsVersion(qdsVersionString);
d->landingPage->show();
}
void QmlProjectPlugin::hideQmlLandingPage()
{
d->landingPage->hide();
}
static bool isDesignerMode(Utils::Id mode)
{
return mode == Core::Constants::MODE_DESIGN;
}
void QmlProjectPlugin::editorModeChanged(Utils::Id newMode, Utils::Id oldMode)
{
Core::IEditor *currentEditor = Core::EditorManager::currentEditor();
if (checkIfEditorIsuiQml(currentEditor)) {
if (isDesignerMode(newMode)) {
if (alwaysOpenWithMode() == Core::Constants::MODE_DESIGN)
openQds();
else if (alwaysOpenWithMode() == Core::Constants::MODE_EDIT)
openQtc();
else
displayQmlLandingPage();
} else if (isDesignerMode(oldMode)) {
hideQmlLandingPage();
}
}
}
void QmlProjectPlugin::openQtc(bool permanent)
{
if (permanent)
setAlwaysOpenWithMode(Core::Constants::MODE_EDIT);
hideQmlLandingPage();
Core::ModeManager::activateMode(Core::Constants::MODE_EDIT);
}
void QmlProjectPlugin::openQds(bool permanent)
{
if (permanent)
setAlwaysOpenWithMode(Core::Constants::MODE_DESIGN);
hideQmlLandingPage();
auto editor = Core::EditorManager::currentEditor();
if (editor)
openInQDSWithProject(editor->document()->filePath());
}
void QmlProjectPlugin::installQds()
{
QDesktopServices::openUrl(QUrl(installQdsUrl));
hideQmlLandingPage();
}
void QmlProjectPlugin::generateCmake()
{
qWarning() << "TODO generate cmake";
}
void QmlProjectPlugin::generateProjectFile()
{
qWarning() << "TODO generate .qmlproject";
}
Utils::FilePath QmlProjectPlugin::projectFilePath()
{
auto project = ProjectExplorer::SessionManager::startupProject();
const QmlProjectManager::QmlProject *qmlProject = qobject_cast<const QmlProjectManager::QmlProject*>(project);
if (qmlProject)
return qmlProject->projectFilePath();
return {};
}
} // namespace Internal
} // namespace QmlProjectManager