From fb6e9770dc2cba20375279b3cf6c33d8aaf10cbe Mon Sep 17 00:00:00 2001 From: Przemyslaw Lewandowski Date: Mon, 6 Jan 2025 11:17:47 +0100 Subject: [PATCH 01/14] Design System: fix MCU variable generation Task-number: QDS-14393 Change-Id: I70df1d3e4a7e8c2be381dea5bfe7d1014cc0f019 Reviewed-by: Vikas Pachdha --- .../qmldesigner/libs/designsystem/dsthemegroup.cpp | 11 ++++------- .../qmldesigner/libs/designsystem/dsthemegroup.h | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.cpp b/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.cpp index d2a5cb67ac8..2fd8cf4a3a9 100644 --- a/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.cpp +++ b/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.cpp @@ -199,7 +199,7 @@ void DSThemeGroup::decorate(ThemeId theme, ModelNode themeNode, bool wrapInGroup for (auto &[propName, values] : m_values) { auto themeValue = values.find(theme); if (themeValue != values.end()) - addProperty(targetNode, propName, themeValue->second); + addProperty(targetNode, propName, themeValue->second, wrapInGroups); } } @@ -224,21 +224,18 @@ std::vector DSThemeGroup::propertyNames() const return names; } -void DSThemeGroup::addProperty(ModelNode n, PropertyNameView propName, const PropertyData &data) const +void DSThemeGroup::addProperty(ModelNode n, PropertyNameView propName, const PropertyData &data, bool createNewProperty) const { - auto metaInfo = n.model()->metaInfo(n.type()); - const bool propDefined = metaInfo.property(propName).isValid(); - const auto typeName = groupTypeName(m_type); if (data.isBinding) { - if (propDefined) + if (!createNewProperty) n.bindingProperty(propName).setExpression(data.value.toString()); else if (auto bindingProp = n.bindingProperty(propName)) bindingProp.setDynamicTypeNameAndExpression(*typeName, data.value.toString()); else qCDebug(dsLog) << "Assigning invalid binding" << propName << n.id(); } else { - if (propDefined) + if (!createNewProperty) n.variantProperty(propName).setValue(data.value); else if (auto nodeProp = n.variantProperty(propName)) nodeProp.setDynamicTypeNameAndValue(*typeName, data.value); diff --git a/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.h b/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.h index edb78fd66ba..e1ea8e93d96 100644 --- a/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.h +++ b/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.h @@ -54,7 +54,7 @@ public: std::vector propertyNames() const; private: - void addProperty(ModelNode n, PropertyNameView propName, const PropertyData &data) const; + void addProperty(ModelNode n, PropertyNameView propName, const PropertyData &data, bool createNewProperty) const; private: const GroupType m_type; From 75aef4f2d34aac4b684f5cb2965754b3f8824b63 Mon Sep 17 00:00:00 2001 From: Burak Hancerli Date: Tue, 10 Dec 2024 14:50:34 +0100 Subject: [PATCH 02/14] DeviceManager: Implement new states MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Right now only running and stopped states are supported. This patch introduces support for packaging, uploading and unpacking states as well as enabling cancellation of the process in any state. Task-number: QDS-14342 Task-number: QDS-14343 Task-number: QDS-14287 Change-Id: Ifebacc7f60834dc7e17910b9c6bbfc7c44426228 Reviewed-by: Henning Gründl --- src/plugins/qmldesigner/CMakeLists.txt | 1 - .../componentcore/resourcegenerator.cpp | 396 +++++++++++------- .../componentcore/resourcegenerator.h | 42 +- .../components/designviewer/dvconnector.cpp | 14 +- .../components/designviewer/dvconnector.h | 4 +- .../designviewer/resourcegeneratorproxy.cpp | 65 --- .../designviewer/resourcegeneratorproxy.h | 28 -- .../components/devicesharing/device.cpp | 141 +++++-- .../components/devicesharing/device.h | 31 +- .../components/devicesharing/deviceinfo.cpp | 5 + .../components/devicesharing/deviceinfo.h | 6 +- .../devicesharing/devicemanager.cpp | 303 +++++++++----- .../components/devicesharing/devicemanager.h | 47 ++- .../components/runmanager/runmanager.cpp | 15 +- 14 files changed, 660 insertions(+), 438 deletions(-) delete mode 100644 src/plugins/qmldesigner/components/designviewer/resourcegeneratorproxy.cpp delete mode 100644 src/plugins/qmldesigner/components/designviewer/resourcegeneratorproxy.h diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 72aa9521d5d..f504dede055 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -774,7 +774,6 @@ extend_qtc_plugin(QmlDesigner PUBLIC_DEFINES DVCONNECTOR_ENABLED SOURCES dvconnector.cpp dvconnector.h - resourcegeneratorproxy.cpp resourcegeneratorproxy.h ) add_qtc_plugin(assetexporterplugin diff --git a/src/plugins/qmldesigner/components/componentcore/resourcegenerator.cpp b/src/plugins/qmldesigner/components/componentcore/resourcegenerator.cpp index d512ce47546..1568427622d 100644 --- a/src/plugins/qmldesigner/components/componentcore/resourcegenerator.cpp +++ b/src/plugins/qmldesigner/components/componentcore/resourcegenerator.cpp @@ -19,127 +19,13 @@ #include -#include -#include - #include #include -#include -#include #include using namespace Utils; -namespace QmlDesigner::ResourceGenerator { - -void generateMenuEntry(QObject *parent) -{ - const Core::Context projectContext(QmlProjectManager::Constants::QML_PROJECT_ID); - // ToDo: move this to QtCreator and add tr to the string then - auto action = new QAction(Tr::tr("QmlDesigner::GenerateResource", "Generate QRC Resource File..."), - parent); - action->setEnabled(ProjectExplorer::ProjectManager::startupProject() != nullptr); - // todo make it more intelligent when it gets enabled - QObject::connect(ProjectExplorer::ProjectManager::instance(), - &ProjectExplorer::ProjectManager::startupProjectChanged, - [action]() { - if (auto buildSystem = QmlProjectManager::QmlBuildSystem::getStartupBuildSystem()) - action->setEnabled(!buildSystem->qtForMCUs()); - }); - - Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.CreateResource"); - QObject::connect(action, &QAction::triggered, []() { - auto project = ProjectExplorer::ProjectManager::startupProject(); - QTC_ASSERT(project, return); - const FilePath projectPath = project->projectFilePath().parentDir(); - auto qrcFilePath = Core::DocumentManager::getSaveFileNameWithExtension( - Tr::tr("QmlDesigner::GenerateResource", "Save Project as QRC File"), - projectPath.pathAppended(project->displayName() + ".qrc"), - Tr::tr("QmlDesigner::GenerateResource", "QML Resource File (*.qrc)")); - - if (qrcFilePath.toString().isEmpty()) - return; - - createQrcFile(qrcFilePath); - - Core::AsynchronousMessageBox::information( - Tr::tr("QmlDesigner::GenerateResource", "Success"), - Tr::tr("QmlDesigner::GenerateResource", "Successfully generated QRC resource file\n %1") - .arg(qrcFilePath.toString())); - }); - - // ToDo: move this to QtCreator and add tr to the string then - auto rccAction = new QAction(Tr::tr("QmlDesigner::GenerateResource", - "Generate Deployable Package..."), - parent); - rccAction->setEnabled(ProjectExplorer::ProjectManager::startupProject() != nullptr); - QObject::connect(ProjectExplorer::ProjectManager::instance(), - &ProjectExplorer::ProjectManager::startupProjectChanged, - [rccAction]() { - rccAction->setEnabled(ProjectExplorer::ProjectManager::startupProject()); - }); - - Core::Command *cmd2 = Core::ActionManager::registerAction(rccAction, - "QmlProject.CreateRCCResource"); - QObject::connect(rccAction, &QAction::triggered, []() { - auto project = ProjectExplorer::ProjectManager::startupProject(); - QTC_ASSERT(project, return); - const FilePath projectPath = project->projectFilePath().parentDir(); - const FilePath qmlrcFilePath = Core::DocumentManager::getSaveFileNameWithExtension( - Tr::tr("QmlDesigner::GenerateResource", "Save Project as Resource"), - projectPath.pathAppended(project->displayName() + ".qmlrc"), - "QML Resource File (*.qmlrc);;Resource File (*.rcc)"); - - if (qmlrcFilePath.toString().isEmpty()) - return; - - QProgressDialog progress; - progress.setLabelText(Tr::tr("QmlDesigner::GenerateResource", - "Generating deployable package. Please wait...")); - progress.setRange(0, 0); - progress.setWindowModality(Qt::WindowModal); - progress.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); - progress.setCancelButton(nullptr); - progress.show(); - - QFuture future = QtConcurrent::run( - [qmlrcFilePath]() { return createQmlrcFile(qmlrcFilePath); }); - - while (!future.isFinished()) - QCoreApplication::processEvents(); - - progress.close(); - - if (future.isCanceled()) { - qDebug() << "Operation canceled by user"; - return; - } - - if (!future.result()) { - Core::MessageManager::writeDisrupting( - Tr::tr("QmlDesigner::GenerateResource", "Failed to generate deployable package!")); - QMessageBox msgBox; - msgBox.setWindowTitle(Tr::tr("QmlDesigner::GenerateResource", "Error")); - msgBox.setText(Tr::tr("QmlDesigner::GenerateResource", - "Failed to generate deployable package!\n\nPlease check " - "the output pane for more information.")); - msgBox.exec(); - return; - } - - QMessageBox msgBox; - msgBox.setWindowTitle(Tr::tr("QmlDesigner::GenerateResource", "Success")); - msgBox.setText( - Tr::tr("QmlDesigner::GenerateResource", "Successfully generated deployable package")); - msgBox.exec(); - }); - - Core::ActionContainer *exportMenu = Core::ActionManager::actionContainer( - QmlProjectManager::Constants::EXPORT_MENU); - exportMenu->addAction(cmd, QmlProjectManager::Constants::G_EXPORT_GENERATE); - exportMenu->addAction(cmd2, QmlProjectManager::Constants::G_EXPORT_GENERATE); -} - +namespace QmlDesigner { QStringList getProjectFileList() { const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); @@ -156,12 +42,162 @@ QStringList getProjectFileList() return selectedFileList; } -bool createQrcFile(const FilePath &qrcFilePath) +ResourceGenerator::ResourceGenerator(QObject *parent) + : QObject(parent) +{ + connect(&m_rccProcess, &Utils::Process::done, this, [this]() { + const int exitCode = m_rccProcess.exitCode(); + if (exitCode != 0) { + Core::MessageManager::writeDisrupting(Tr::tr("\"%1\" failed (exit code %2).") + .arg(m_rccProcess.commandLine().toUserOutput()) + .arg(m_rccProcess.exitCode())); + emit errorOccurred(Tr::tr("Failed to generate deployable package!")); + return; + } + + if (m_rccProcess.exitStatus() != QProcess::NormalExit) { + Core::MessageManager::writeDisrupting( + Tr::tr("\"%1\" crashed.").arg(m_rccProcess.commandLine().toUserOutput())); + emit errorOccurred(Tr::tr("Failed to generate deployable package!")); + return; + } + + emit qmlrcCreated(m_qmlrcFilePath); + }); + + connect(&m_rccProcess, &Utils::Process::textOnStandardError, this, [](const QString &text) { + Core::MessageManager::writeFlashing(QString::fromLocal8Bit(text.toLocal8Bit())); + }); + + connect(&m_rccProcess, &Utils::Process::textOnStandardOutput, this, [](const QString &text) { + Core::MessageManager::writeFlashing(QString::fromLocal8Bit(text.toLocal8Bit())); + }); +} + +void ResourceGenerator::generateMenuEntry(QObject *parent) +{ + const Core::Context projectContext(QmlProjectManager::Constants::QML_PROJECT_ID); + // ToDo: move this to QtCreator and add tr to the string then + auto action = new QAction(Tr::tr("Generate QRC Resource File..."), parent); + action->setEnabled(ProjectExplorer::ProjectManager::startupProject() != nullptr); + // todo make it more intelligent when it gets enabled + QObject::connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, + [action]() { + if (auto buildSystem = QmlProjectManager::QmlBuildSystem::getStartupBuildSystem()) + action->setEnabled(!buildSystem->qtForMCUs()); + }); + + Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.CreateResource"); + QObject::connect(action, &QAction::triggered, []() { + auto project = ProjectExplorer::ProjectManager::startupProject(); + QTC_ASSERT(project, return); + const FilePath projectPath = project->projectFilePath().parentDir(); + auto qrcFilePath = Core::DocumentManager::getSaveFileNameWithExtension( + Tr::tr("Save Project as QRC File"), + projectPath.pathAppended(project->displayName() + ".qrc"), + Tr::tr("QML Resource File (*.qrc)")); + + if (qrcFilePath.toString().isEmpty()) + return; + + ResourceGenerator resourceGenerator; + resourceGenerator.createQrc(qrcFilePath); + + Core::AsynchronousMessageBox::information( + Tr::tr("Success"), + Tr::tr("Successfully generated QRC resource file\n %1").arg(qrcFilePath.toString())); + }); + + // ToDo: move this to QtCreator and add tr to the string then + auto rccAction = new QAction(Tr::tr("Generate Deployable Package..."), parent); + rccAction->setEnabled(ProjectExplorer::ProjectManager::startupProject() != nullptr); + QObject::connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, + [rccAction]() { + rccAction->setEnabled(ProjectExplorer::ProjectManager::startupProject()); + }); + + Core::Command *cmd2 = Core::ActionManager::registerAction(rccAction, + "QmlProject.CreateRCCResource"); + QObject::connect(rccAction, &QAction::triggered, []() { + auto project = ProjectExplorer::ProjectManager::startupProject(); + QTC_ASSERT(project, return); + const FilePath projectPath = project->projectFilePath().parentDir(); + const FilePath qmlrcFilePath = Core::DocumentManager::getSaveFileNameWithExtension( + Tr::tr("Save Project as Resource"), + projectPath.pathAppended(project->displayName() + ".qmlrc"), + "QML Resource File (*.qmlrc);;Resource File (*.rcc)"); + + if (qmlrcFilePath.toString().isEmpty()) + return; + + QProgressDialog progress; + progress.setLabelText(Tr::tr("Generating deployable package. Please wait...")); + progress.setRange(0, 0); + progress.setWindowModality(Qt::WindowModal); + progress.setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint); + progress.setCancelButton(nullptr); + progress.show(); + + QFuture future = QtConcurrent::run([qmlrcFilePath]() { + ResourceGenerator resourceGenerator; + return resourceGenerator.createQmlrcWithPath(qmlrcFilePath); + }); + + while (!future.isFinished()) + QCoreApplication::processEvents(); + + progress.close(); + + if (future.isCanceled()) { + qDebug() << "Operation canceled by user"; + return; + } + + if (!future.result()) { + Core::MessageManager::writeDisrupting(Tr::tr("Failed to generate deployable package!")); + QMessageBox msgBox; + msgBox.setWindowTitle(Tr::tr("Error")); + msgBox.setText(Tr::tr("Failed to generate deployable package!\n\nPlease check " + "the output pane for more information.")); + msgBox.exec(); + return; + } + + QMessageBox msgBox; + msgBox.setWindowTitle(Tr::tr("Success")); + msgBox.setText(Tr::tr("Successfully generated deployable package")); + msgBox.exec(); + }); + + Core::ActionContainer *exportMenu = Core::ActionManager::actionContainer( + QmlProjectManager::Constants::EXPORT_MENU); + exportMenu->addAction(cmd, QmlProjectManager::Constants::G_EXPORT_GENERATE); + exportMenu->addAction(cmd2, QmlProjectManager::Constants::G_EXPORT_GENERATE); +} + +std::optional ResourceGenerator::createQrc(const QString &projectName) +{ + const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); + const FilePath projectPath = project->projectFilePath().parentDir(); + const FilePath qrcFilePath = projectPath.pathAppended(projectName + ".qrc"); + + if (!createQrc(qrcFilePath)) + return {}; + + return qrcFilePath; +} + +bool ResourceGenerator::createQrc(const Utils::FilePath &qrcFilePath) { QFile qrcFile(qrcFilePath.toString()); - if (!qrcFile.open(QIODeviceBase::WriteOnly | QIODevice::Truncate)) + if (!qrcFile.open(QIODeviceBase::WriteOnly | QIODevice::Truncate)) { + Core::MessageManager::writeDisrupting( + Tr::tr("Failed to open file to write QRC XML: %1").arg(qrcFilePath.toString())); return false; + } QXmlStreamWriter writer(&qrcFile); writer.setAutoFormatting(true); @@ -180,12 +216,74 @@ bool createQrcFile(const FilePath &qrcFilePath) return true; } -bool createQmlrcFile(const FilePath &qmlrcFilePath) +void ResourceGenerator::createQmlrcAsyncWithName(const QString &projectName) { - const FilePath tempQrcFile = qmlrcFilePath.parentDir().pathAppended("temp.qrc"); - if (!createQrcFile(tempQrcFile)) + if (m_rccProcess.state() != QProcess::NotRunning) { + Core::MessageManager::writeDisrupting(Tr::tr("Resource generator is already running.")); + return; + } + + const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); + const FilePath projectPath = project->projectFilePath().parentDir(); + const FilePath qmlrcFilePath = projectPath.pathAppended(projectName + ".qmlrc"); + + createQmlrcAsyncWithPath(qmlrcFilePath); +} + +void ResourceGenerator::createQmlrcAsyncWithPath(const FilePath &qmlrcFilePath) +{ + if (m_rccProcess.state() != QProcess::NotRunning) { + Core::MessageManager::writeDisrupting(Tr::tr("Resource generator is already running.")); + return; + } + + m_qmlrcFilePath = qmlrcFilePath; + const FilePath tempQrcFile = m_qmlrcFilePath.parentDir().pathAppended("temp.qrc"); + if (!createQrc(tempQrcFile)) + return; + + runRcc(qmlrcFilePath, tempQrcFile, true); +} + +std::optional ResourceGenerator::createQmlrcWithName(const QString &projectName) +{ + const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); + const FilePath projectPath = project->projectFilePath().parentDir(); + const FilePath qmlrcFilePath = projectPath.pathAppended(projectName + ".qmlrc"); + + if (!createQmlrcWithPath(qmlrcFilePath)) + return {}; + + return qmlrcFilePath; +} + +bool ResourceGenerator::createQmlrcWithPath(const FilePath &qmlrcFilePath) +{ + if (m_rccProcess.state() != QProcess::NotRunning) { + Core::MessageManager::writeDisrupting(Tr::tr("Resource generator is already running.")); + return false; + } + + m_qmlrcFilePath = qmlrcFilePath; + const FilePath tempQrcFile = m_qmlrcFilePath.parentDir().pathAppended("temp.qrc"); + if (!createQrc(tempQrcFile)) return false; + bool retVal = true; + if (!runRcc(qmlrcFilePath, tempQrcFile)) { + retVal = false; + if (qmlrcFilePath.exists()) + qmlrcFilePath.removeFile(); + } + + tempQrcFile.removeFile(); + return retVal; +} + +bool ResourceGenerator::runRcc(const FilePath &qmlrcFilePath, + const Utils::FilePath &qrcFilePath, + const bool runAsync) +{ const ProjectExplorer::Project *project = ProjectExplorer::ProjectManager::startupProject(); const QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion( project->activeTarget()->kit()); @@ -193,8 +291,7 @@ bool createQmlrcFile(const FilePath &qmlrcFilePath) const FilePath rccBinary = qtVersion->rccFilePath(); - Utils::Process rccProcess; - rccProcess.setWorkingDirectory(project->projectDirectory()); + m_rccProcess.setWorkingDirectory(project->projectDirectory()); const QStringList arguments = {"--binary", "--no-zstd", @@ -204,46 +301,35 @@ bool createQmlrcFile(const FilePath &qmlrcFilePath) "30", "--output", qmlrcFilePath.toString(), - tempQrcFile.toString()}; + qrcFilePath.toString()}; - rccProcess.setCommand({rccBinary, arguments}); - rccProcess.start(); - if (!rccProcess.waitForStarted()) { + m_rccProcess.setCommand({rccBinary, arguments}); + m_rccProcess.start(); + if (!m_rccProcess.waitForStarted()) { Core::MessageManager::writeDisrupting( - Tr::tr("QmlDesigner::GenerateResource", "Unable to generate resource file: %1") - .arg(qmlrcFilePath.toString())); + Tr::tr("Unable to generate resource file: %1").arg(qmlrcFilePath.toString())); return false; } - QByteArray stdOut; - QByteArray stdErr; - if (!rccProcess.readDataFromProcess(&stdOut, &stdErr)) { - rccProcess.stop(); - Core::MessageManager::writeDisrupting( - Tr::tr("QmlDesigner::GenerateResource", "A timeout occurred running \"%1\".") - .arg(rccProcess.commandLine().toUserOutput())); - return false; + if (!runAsync) { + QByteArray stdOut; + QByteArray stdErr; + if (!m_rccProcess.readDataFromProcess(&stdOut, &stdErr)) { + m_rccProcess.stop(); + Core::MessageManager::writeDisrupting(Tr::tr("A timeout occurred running \"%1\".") + .arg(m_rccProcess.commandLine().toUserOutput())); + return false; + } + + if (m_rccProcess.exitStatus() != QProcess::NormalExit || m_rccProcess.exitCode() != 0) + return false; } - if (!stdOut.trimmed().isEmpty()) - Core::MessageManager::writeFlashing(QString::fromLocal8Bit(stdOut)); - - if (!stdErr.trimmed().isEmpty()) - Core::MessageManager::writeFlashing(QString::fromLocal8Bit(stdErr)); - - if (rccProcess.exitStatus() != QProcess::NormalExit) { - Core::MessageManager::writeDisrupting(Tr::tr("QmlDesigner::GenerateResource", "\"%1\" crashed.") - .arg(rccProcess.commandLine().toUserOutput())); - return false; - } - if (rccProcess.exitCode() != 0) { - Core::MessageManager::writeDisrupting( - Tr::tr("QmlDesigner::GenerateResource", "\"%1\" failed (exit code %2).") - .arg(rccProcess.commandLine().toUserOutput()) - .arg(rccProcess.exitCode())); - return false; - } return true; } -} // namespace QmlDesigner::ResourceGenerator +void ResourceGenerator::cancel() +{ + m_rccProcess.kill(); +} +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/resourcegenerator.h b/src/plugins/qmldesigner/components/componentcore/resourcegenerator.h index e8c0fde0e81..f5b18aa4c4d 100644 --- a/src/plugins/qmldesigner/components/componentcore/resourcegenerator.h +++ b/src/plugins/qmldesigner/components/componentcore/resourcegenerator.h @@ -3,15 +3,41 @@ #pragma once -#include - #include +#include +#include -namespace QmlDesigner::ResourceGenerator { +namespace QmlDesigner { +class ResourceGenerator : public QObject +{ + Q_OBJECT +public: + ResourceGenerator(QObject *parent = nullptr); + static void generateMenuEntry(QObject *parent); -QMLDESIGNERCOMPONENTS_EXPORT void generateMenuEntry(QObject *parent); -QMLDESIGNERCOMPONENTS_EXPORT QStringList getProjectFileList(); -QMLDESIGNERCOMPONENTS_EXPORT bool createQrcFile(const Utils::FilePath &qrcFilePath); -QMLDESIGNERCOMPONENTS_EXPORT bool createQmlrcFile(const Utils::FilePath &qmlrcFilePath); + Q_INVOKABLE bool createQrc(const Utils::FilePath &qrcFilePath); + Q_INVOKABLE std::optional createQrc(const QString &projectName = "share"); -} // namespace QmlDesigner::ResourceGenerator + Q_INVOKABLE bool createQmlrcWithPath(const Utils::FilePath &qmlrcFilePath); + Q_INVOKABLE std::optional createQmlrcWithName( + const QString &projectName = "share"); + Q_INVOKABLE void createQmlrcAsyncWithPath(const Utils::FilePath &qmlrcFilePath); + Q_INVOKABLE void createQmlrcAsyncWithName(const QString &projectName = "share"); + + Q_INVOKABLE void cancel(); + +private: + Utils::Process m_rccProcess; + Utils::FilePath m_qmlrcFilePath; + +private: + bool runRcc(const Utils::FilePath &qmlrcFilePath, + const Utils::FilePath &qrcFilePath, + const bool runAsync = false); + +signals: + void errorOccurred(const QString &error); + void qmlrcCreated(const Utils::FilePath &filePath); +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/designviewer/dvconnector.cpp b/src/plugins/qmldesigner/components/designviewer/dvconnector.cpp index 23f99ebafe3..4058c0f32e0 100644 --- a/src/plugins/qmldesigner/components/designviewer/dvconnector.cpp +++ b/src/plugins/qmldesigner/components/designviewer/dvconnector.cpp @@ -154,7 +154,7 @@ DVConnector::DVConnector(QObject *parent) }); connect(&m_resourceGenerator, - &ResourceGeneratorProxy::resourceFileCreated, + &ResourceGenerator::qmlrcCreated, this, [this](const std::optional &resourcePath) { emit projectIsUploading(); @@ -162,12 +162,10 @@ DVConnector::DVConnector(QObject *parent) uploadProject(projectName, resourcePath->toString()); }); - connect(&m_resourceGenerator, - &ResourceGeneratorProxy::errorOccurred, - [this](const QString &errorString) { - qCWarning(deploymentPluginLog) << "Error occurred while packing the project"; - emit projectPackingFailed(errorString); - }); + connect(&m_resourceGenerator, &ResourceGenerator::errorOccurred, [this](const QString &errorString) { + qCWarning(deploymentPluginLog) << "Error occurred while packing the project"; + emit projectPackingFailed(errorString); + }); fetchUserInfo(); } @@ -220,7 +218,7 @@ void DVConnector::projectList() void DVConnector::uploadCurrentProject() { QString projectName = ProjectExplorer::ProjectManager::startupProject()->displayName(); - m_resourceGenerator.createResourceFileAsync(projectName); + m_resourceGenerator.createQmlrcAsyncWithName(projectName); emit projectIsPacking(); } diff --git a/src/plugins/qmldesigner/components/designviewer/dvconnector.h b/src/plugins/qmldesigner/components/designviewer/dvconnector.h index 69248c5d93d..7becce4b056 100644 --- a/src/plugins/qmldesigner/components/designviewer/dvconnector.h +++ b/src/plugins/qmldesigner/components/designviewer/dvconnector.h @@ -9,7 +9,7 @@ #include #include -#include "resourcegeneratorproxy.h" +#include namespace QmlDesigner::DesignViewer { @@ -99,7 +99,7 @@ private: QByteArray m_userInfo; // other internals - ResourceGeneratorProxy m_resourceGenerator; + ResourceGenerator m_resourceGenerator; struct ReplyEvaluatorData { diff --git a/src/plugins/qmldesigner/components/designviewer/resourcegeneratorproxy.cpp b/src/plugins/qmldesigner/components/designviewer/resourcegeneratorproxy.cpp deleted file mode 100644 index 8f59d7f5891..00000000000 --- a/src/plugins/qmldesigner/components/designviewer/resourcegeneratorproxy.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#include "resourcegeneratorproxy.h" - -#include -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - -#include - -#include - -namespace QmlDesigner::DesignViewer { - -ResourceGeneratorProxy::~ResourceGeneratorProxy() -{ - if (m_future.isRunning()) { - m_future.cancel(); - m_future.waitForFinished(); - } -} - -void ResourceGeneratorProxy::createResourceFileAsync(const QString &projectName) -{ - m_future = QtConcurrent::run([&]() { - const std::optional filePath = createResourceFileSync(projectName); - - if (!filePath || filePath->isEmpty()) { - emit errorOccurred("Failed to create resource file"); - return; - } - - emit resourceFileCreated(filePath.value()); - }); -} - -std::optional ResourceGeneratorProxy::createResourceFileSync(const QString &projectName) -{ - const auto project = ProjectExplorer::ProjectManager::startupProject(); - std::optional resourcePath = project->projectDirectory().pathAppended( - projectName + ".qmlrc"); - - const bool retVal = ResourceGenerator::createQmlrcFile(resourcePath.value()); - - if (!retVal || resourcePath->fileSize() == 0) { - Core::MessageManager::writeDisrupting(tr("Failed to create resource file")); - resourcePath.reset(); - } - - return resourcePath; -} - -} // namespace QmlDesigner::DesignViewer diff --git a/src/plugins/qmldesigner/components/designviewer/resourcegeneratorproxy.h b/src/plugins/qmldesigner/components/designviewer/resourcegeneratorproxy.h deleted file mode 100644 index 1d83c477bde..00000000000 --- a/src/plugins/qmldesigner/components/designviewer/resourcegeneratorproxy.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -#pragma once - -#include - -#include - -namespace QmlDesigner::DesignViewer { - -class ResourceGeneratorProxy : public QObject -{ - Q_OBJECT -public: - ~ResourceGeneratorProxy(); - Q_INVOKABLE void createResourceFileAsync(const QString &projectName = "share"); - Q_INVOKABLE std::optional createResourceFileSync(const QString &projectName = "share"); - -private: - QFuture m_future; - -signals: - void errorOccurred(const QString &error); - void resourceFileCreated(const Utils::FilePath &filePath); -}; - -} // namespace QmlDesigner::DesignViewer diff --git a/src/plugins/qmldesigner/components/devicesharing/device.cpp b/src/plugins/qmldesigner/components/devicesharing/device.cpp index 7a9fe8b8f1d..b7a77a9d911 100644 --- a/src/plugins/qmldesigner/components/devicesharing/device.cpp +++ b/src/plugins/qmldesigner/components/devicesharing/device.cpp @@ -20,17 +20,24 @@ constexpr auto stopRunningProject = "stopRunningProject"_L1; namespace PackageFromDevice { using namespace Qt::Literals; constexpr auto deviceInfo = "deviceInfo"_L1; +constexpr auto projectReceivingProgress = "projectReceivingProgress"_L1; +constexpr auto projectStarting = "projectStarting"_L1; constexpr auto projectRunning = "projectRunning"_L1; constexpr auto projectStopped = "projectStopped"_L1; constexpr auto projectLogs = "projectLogs"_L1; }; // namespace PackageFromDevice -Device::Device(const DeviceInfo &deviceInfo, const DeviceSettings &deviceSettings, QObject *parent) +Device::Device(const QString designStudioId, + const DeviceInfo &deviceInfo, + const DeviceSettings &deviceSettings, + QObject *parent) : QObject(parent) , m_deviceInfo(deviceInfo) , m_deviceSettings(deviceSettings) , m_socket(nullptr) , m_socketWasConnected(false) + , m_socketManuallyClosed(false) + , m_designStudioId(designStudioId) { qCDebug(deviceSharePluginLog) << "initial device info:" << m_deviceInfo; @@ -38,40 +45,33 @@ Device::Device(const DeviceInfo &deviceInfo, const DeviceSettings &deviceSetting m_socket->setOutgoingFrameSize(128000); connect(m_socket.data(), &QWebSocket::textMessageReceived, this, &Device::processTextMessage); connect(m_socket.data(), &QWebSocket::disconnected, this, [this]() { - m_reconnectTimer.start(); + if (m_socketManuallyClosed) { + m_socketManuallyClosed = false; + return; + } + + m_reconnectTimer.start(m_reconnectTimeout); if (!m_socketWasConnected) return; m_socketWasConnected = false; - m_pingTimer.stop(); - m_pongTimer.stop(); + stopPingPong(); emit disconnected(m_deviceSettings.deviceId()); }); connect(m_socket.data(), &QWebSocket::connected, this, [this]() { m_socketWasConnected = true; m_reconnectTimer.stop(); - m_pingTimer.start(); - sendDesignStudioReady(m_deviceSettings.deviceId()); + restartPingPong(); + sendDesignStudioReady(); emit connected(m_deviceSettings.deviceId()); }); - connect(m_socket.data(), &QWebSocket::bytesWritten, this, [this](qint64 bytes) { - if (m_lastProjectSize == 0) - return; - - m_lastProjectSentSize += bytes; - const float percentage = ((float) m_lastProjectSentSize * 100.0) / (float) m_lastProjectSize; - - if (percentage != 100.0) - emit projectSendingProgress(m_deviceSettings.deviceId(), percentage); - - if (m_lastProjectSentSize >= m_lastProjectSize) - m_lastProjectSize = 0; - }); - m_reconnectTimer.setSingleShot(true); - m_reconnectTimer.setInterval(m_reconnectTimeout); - connect(&m_reconnectTimer, &QTimer::timeout, this, &Device::reconnect); + connect(&m_reconnectTimer, &QTimer::timeout, this, [this]() { reconnect(); }); + + m_sendTimer.setSingleShot(true); + m_sendTimer.setInterval(10); + connect(&m_sendTimer, &QTimer::timeout, this, &Device::sendProjectDataInternal, Qt::UniqueConnection); initPingPong(); reconnect(); @@ -114,10 +114,23 @@ void Device::initPingPong() }); } -void Device::reconnect() +void Device::stopPingPong() { - if (m_socket->state() == QAbstractSocket::ConnectedState) - m_socket->close(); + m_pingTimer.stop(); + m_pongTimer.stop(); +} + +void Device::restartPingPong() +{ + m_pingTimer.start(); +} + +void Device::reconnect(const QString &closeMessage) +{ + if (m_socket && m_socket->isValid() && m_socket->state() == QAbstractSocket::ConnectedState) { + m_socket->close(QWebSocketProtocol::CloseCodeNormal, closeMessage); + m_socketManuallyClosed = true; + } QUrl url(QStringLiteral("ws://%1:%2").arg(m_deviceSettings.ipAddress()).arg(40000)); m_socket->open(url); @@ -146,19 +159,63 @@ void Device::setDeviceSettings(const DeviceSettings &deviceSettings) reconnect(); } -bool Device::sendDesignStudioReady(const QString &uuid) +bool Device::sendDesignStudioReady() { - return sendTextMessage(PackageToDevice::designStudioReady, uuid); + QJsonObject data; + data["designStudioID"] = m_designStudioId; + data["commVersion"] = 1; + return sendTextMessage(PackageToDevice::designStudioReady, data); } -bool Device::sendProjectNotification(const int &projectSize) +bool Device::sendProjectNotification(const int &projectSize, const QString &qtVersion) { - return sendTextMessage(PackageToDevice::projectData, projectSize); + QJsonObject projectInfo; + projectInfo["projectSize"] = projectSize; + projectInfo["qtVersion"] = qtVersion; + + return sendTextMessage(PackageToDevice::projectData, projectInfo); } -bool Device::sendProjectData(const QByteArray &data) +bool Device::sendProjectData(const QByteArray &data, const QString &qtVersion) { - return sendBinaryMessage(data); + if (!isConnected()) + return false; + + sendProjectNotification(data.size(), qtVersion); + + m_sendProject = true; + m_projectData = data; + m_totalSentSize = 0; + m_lastSentProgress = 0; + + m_sendTimer.start(); + stopPingPong(); + + return true; +} + +void Device::sendProjectDataInternal() +{ + if (!isConnected()) + return; + + if (!m_sendProject) { + sendTextMessage(PackageToDevice::stopRunningProject); + restartPingPong(); + return; + } + + const int chunkSize = 1024 * 50; // 50KB + + const QByteArray chunk = m_projectData.mid(m_totalSentSize, chunkSize); + m_socket->sendBinaryMessage(chunk); + m_socket->flush(); + + m_totalSentSize += chunk.size(); + if (m_totalSentSize < m_projectData.size()) + m_sendTimer.start(); + else + restartPingPong(); } bool Device::sendProjectStopped() @@ -186,16 +243,12 @@ bool Device::sendTextMessage(const QLatin1String &dataType, const QJsonValue &da return true; } -bool Device::sendBinaryMessage(const QByteArray &data) +void Device::abortProjectTransmission() { if (!isConnected()) - return false; + return; - m_lastProjectSize = data.size(); - m_lastProjectSentSize = 0; - sendProjectNotification(m_lastProjectSize); - m_socket->sendBinaryMessage(data); - return true; + m_sendProject = false; } void Device::processTextMessage(const QString &data) @@ -213,7 +266,7 @@ void Device::processTextMessage(const QString &data) if (dataType == PackageFromDevice::deviceInfo) { QJsonObject deviceInfo = jsonObj.value("data").toObject(); m_deviceInfo.setJsonObject(deviceInfo); - emit deviceInfoReady(m_deviceSettings.ipAddress(), m_deviceSettings.deviceId()); + emit deviceInfoReady(m_deviceSettings.deviceId()); } else if (dataType == PackageFromDevice::projectRunning) { qCDebug(deviceSharePluginLog) << "Project started on device" << m_deviceSettings.deviceId(); emit projectStarted(m_deviceSettings.deviceId()); @@ -221,7 +274,15 @@ void Device::processTextMessage(const QString &data) qCDebug(deviceSharePluginLog) << "Project stopped on device" << m_deviceSettings.deviceId(); emit projectStopped(m_deviceSettings.deviceId()); } else if (dataType == PackageFromDevice::projectLogs) { - emit projectLogsReceived(m_deviceSettings.deviceId(), jsonObj.value("data").toString()); + const QString logs = jsonObj.value("data").toString(); + qCDebug(deviceSharePluginLog) << "Device Log:" << m_deviceSettings.deviceId() << logs; + emit projectLogsReceived(m_deviceSettings.deviceId(), logs); + } else if (dataType == PackageFromDevice::projectStarting) { + qCDebug(deviceSharePluginLog) << "Project starting on device" << m_deviceSettings.deviceId(); + emit projectStarting(m_deviceSettings.deviceId()); + } else if (dataType == PackageFromDevice::projectReceivingProgress) { + const int progress = jsonObj.value("data").toInt(); + emit projectSendingProgress(m_deviceSettings.deviceId(), progress); } else { qCDebug(deviceSharePluginLog) << "Invalid JSON message:" << jsonObj; } diff --git a/src/plugins/qmldesigner/components/devicesharing/device.h b/src/plugins/qmldesigner/components/devicesharing/device.h index 362cc6c1d47..feae5b2bc71 100644 --- a/src/plugins/qmldesigner/components/devicesharing/device.h +++ b/src/plugins/qmldesigner/components/devicesharing/device.h @@ -3,9 +3,12 @@ #pragma once +#include #include #include +#include + #include "deviceinfo.h" namespace QmlDesigner::DeviceShare { @@ -14,7 +17,8 @@ class Device : public QObject { Q_OBJECT public: - Device(const DeviceInfo &deviceInfo = {}, + Device(const QString designStudioId, + const DeviceInfo &deviceInfo = {}, const DeviceSettings &deviceSettings = {}, QObject *parent = nullptr); ~Device(); @@ -26,13 +30,13 @@ public: void setDeviceSettings(const DeviceSettings &deviceSettings); // device communication - bool sendDesignStudioReady(const QString &uuid); - bool sendProjectData(const QByteArray &data); + bool sendProjectData(const QByteArray &data, const QString &qtVersion); bool sendProjectStopped(); + void abortProjectTransmission(); // socket bool isConnected() const; - void reconnect(); + void reconnect(const QString &closeMessage = QString()); private slots: void processTextMessage(const QString &data); @@ -43,28 +47,39 @@ private: QScopedPointer m_socket; bool m_socketWasConnected; + bool m_socketManuallyClosed; QTimer m_reconnectTimer; QTimer m_pingTimer; QTimer m_pongTimer; + QTimer m_sendTimer; - int m_lastProjectSize; - int m_lastProjectSentSize; + std::atomic m_sendProject; + QByteArray m_projectData; + int m_totalSentSize; + int m_lastSentProgress; + + const QString m_designStudioId; static constexpr int m_reconnectTimeout = 5000; static constexpr int m_pingTimeout = 10000; static constexpr int m_pongTimeout = 30000; void initPingPong(); - bool sendProjectNotification(const int &projectSize); + void stopPingPong(); + void restartPingPong(); + void sendProjectDataInternal(); + bool sendDesignStudioReady(); + bool sendProjectNotification(const int &projectSize, const QString &qtVersion); bool sendTextMessage(const QLatin1String &dataType, const QJsonValue &data = QJsonValue()); bool sendBinaryMessage(const QByteArray &data); signals: void connected(const QString &deviceId); void disconnected(const QString &deviceId); - void deviceInfoReady(const QString &deviceIp, const QString &deviceId); + void deviceInfoReady(const QString &deviceId); void projectSendingProgress(const QString &deviceId, const int progress); + void projectStarting(const QString &deviceId); void projectStarted(const QString &deviceId); void projectStopped(const QString &deviceId); void projectLogsReceived(const QString &deviceId, const QString &logs); diff --git a/src/plugins/qmldesigner/components/devicesharing/deviceinfo.cpp b/src/plugins/qmldesigner/components/devicesharing/deviceinfo.cpp index 198efb070b6..2b85aecc615 100644 --- a/src/plugins/qmldesigner/components/devicesharing/deviceinfo.cpp +++ b/src/plugins/qmldesigner/components/devicesharing/deviceinfo.cpp @@ -127,6 +127,11 @@ void DeviceInfo::setScreenHeight(const int &screenHeight) m_data[keyScreenHeight] = screenHeight; } +void DeviceInfo::setSelfId(const QString &selfId) +{ + m_data[keySelfId] = selfId; +} + void DeviceInfo::setAppVersion(const QString &appVersion) { m_data[keyAppVersion] = appVersion; diff --git a/src/plugins/qmldesigner/components/devicesharing/deviceinfo.h b/src/plugins/qmldesigner/components/devicesharing/deviceinfo.h index af2614a169c..e5b103b5997 100644 --- a/src/plugins/qmldesigner/components/devicesharing/deviceinfo.h +++ b/src/plugins/qmldesigner/components/devicesharing/deviceinfo.h @@ -27,7 +27,7 @@ protected: class DeviceSettings : public IDeviceData { public: - DeviceSettings() = default; + using IDeviceData::IDeviceData; // Getters bool active() const; @@ -51,7 +51,7 @@ private: class DeviceInfo : public IDeviceData { public: - DeviceInfo() = default; + using IDeviceData::IDeviceData; // Getters QString os() const; @@ -76,7 +76,7 @@ private: static constexpr char keyOsVersion[] = "osVersion"; static constexpr char keyScreenWidth[] = "screenWidth"; static constexpr char keyScreenHeight[] = "screenHeight"; - static constexpr char keySelfId[] = "selfId"; + static constexpr char keySelfId[] = "deviceId"; static constexpr char keyArchitecture[] = "architecture"; static constexpr char keyAppVersion[] = "appVersion"; }; diff --git a/src/plugins/qmldesigner/components/devicesharing/devicemanager.cpp b/src/plugins/qmldesigner/components/devicesharing/devicemanager.cpp index 8ca7f86dcbd..a57691aaa7a 100644 --- a/src/plugins/qmldesigner/components/devicesharing/devicemanager.cpp +++ b/src/plugins/qmldesigner/components/devicesharing/devicemanager.cpp @@ -8,59 +8,66 @@ #include #include #include +#include #include #include #include +#include +#include +#include +#include namespace QmlDesigner::DeviceShare { +namespace JsonKeys { +using namespace Qt::Literals; +constexpr auto devices = "devices"_L1; +constexpr auto designStudioId = "designStudioId"_L1; +constexpr auto deviceInfo = "deviceInfo"_L1; +constexpr auto deviceSettings = "deviceSettings"_L1; +} // namespace JsonKeys + DeviceManager::DeviceManager(QObject *parent) : QObject(parent) + , m_currentState(OpTypes::Stopped) + , m_processInterrupted(false) { QFileInfo fileInfo(Core::ICore::settings()->fileName()); m_settingsPath = fileInfo.absolutePath() + "/device_manager.json"; readSettings(); - if (m_uuid.isEmpty()) { - m_uuid = QUuid::createUuid().toString(QUuid::WithoutBraces); - writeSettings(); - } initUdpDiscovery(); + + connect(&m_resourceGenerator, + &QmlDesigner::ResourceGenerator::errorOccurred, + this, + [this](const QString &error) { + qCDebug(deviceSharePluginLog) << "ResourceGenerator error:" << error; + handleError(ErrTypes::ProjectPackingError, m_currentDeviceId, error); + }); + + connect(&m_resourceGenerator, + &QmlDesigner::ResourceGenerator::qmlrcCreated, + this, + &DeviceManager::projectPacked); } DeviceManager::~DeviceManager() = default; void DeviceManager::initUdpDiscovery() { - const QList interfaces = QNetworkInterface::allInterfaces(); - for (const QNetworkInterface &interface : interfaces) { - if (interface.flags().testFlag(QNetworkInterface::IsUp) - && interface.flags().testFlag(QNetworkInterface::IsRunning)) { - for (const QNetworkAddressEntry &entry : interface.addressEntries()) { - if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol) { - QSharedPointer udpSocket = QSharedPointer::create(); - connect(udpSocket.data(), - &QUdpSocket::readyRead, - this, - &DeviceManager::incomingDatagram); - - bool retVal = udpSocket->bind(entry.ip(), 53452, QUdpSocket::ShareAddress); - - if (!retVal) { - qCWarning(deviceSharePluginLog) - << "UDP:: Failed to bind to UDP port 53452 on" << entry.ip().toString() - << "on interface" << interface.name() - << ". Error:" << udpSocket->errorString(); - continue; - } - - qCDebug(deviceSharePluginLog) << "UDP:: Listening on" << entry.ip().toString() - << "port" << udpSocket->localPort(); - m_udpSockets.append(udpSocket); - } - } - } + QSharedPointer udpSocket = QSharedPointer::create(); + bool retVal = udpSocket->bind(QHostAddress::AnyIPv4, 53452, QUdpSocket::ShareAddress); + if (!retVal) { + qCWarning(deviceSharePluginLog) << "UDP:: Failed to bind to UDP port 53452 on AnyIPv4" + << ". Error:" << udpSocket->errorString(); + return; } + + connect(udpSocket.data(), &QUdpSocket::readyRead, this, &DeviceManager::incomingDatagram); + + qCDebug(deviceSharePluginLog) << "UDP:: Listening on AnyIPv4 port" << udpSocket->localPort(); + m_udpSockets.append(udpSocket); } void DeviceManager::incomingDatagram() @@ -80,16 +87,20 @@ void DeviceManager::incomingDatagram() const QString id = message["id"].toString(); const QString ip = datagram.senderAddress().toString(); - qCDebug(deviceSharePluginLog) << "Qt UI VIewer found at" << ip << "with id" << id; + bool found = false; for (const auto &device : m_devices) { if (device->deviceInfo().selfId() == id) { + found = true; if (device->deviceSettings().ipAddress() != ip) { qCDebug(deviceSharePluginLog) << "Updating IP address for device" << id; - setDeviceIP(id, ip); + setDeviceIP(device->deviceSettings().deviceId(), ip); } } } + + if (!found) + qCDebug(deviceSharePluginLog) << "Qt UI VIewer discovered at" << ip << "with id" << id; } } @@ -99,13 +110,13 @@ void DeviceManager::writeSettings() QJsonArray devices; for (const auto &device : m_devices) { QJsonObject deviceInfo; - deviceInfo.insert("deviceInfo", device->deviceInfo().jsonObject()); - deviceInfo.insert("deviceSettings", device->deviceSettings().jsonObject()); + deviceInfo.insert(JsonKeys::deviceInfo, device->deviceInfo().jsonObject()); + deviceInfo.insert(JsonKeys::deviceSettings, device->deviceSettings().jsonObject()); devices.append(deviceInfo); } - root.insert("devices", devices); - root.insert("uuid", m_uuid); + root.insert(JsonKeys::devices, devices); + root.insert(JsonKeys::designStudioId, m_designStudioId); QJsonDocument doc(root); QFile file(m_settingsPath); @@ -127,15 +138,17 @@ void DeviceManager::readSettings() } QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); - m_uuid = doc.object()["uuid"].toString(); - QJsonArray devices = doc.object()["devices"].toArray(); + m_designStudioId = doc.object()[JsonKeys::designStudioId].toString(); + if (m_designStudioId.isEmpty()) { + m_designStudioId = QUuid::createUuid().toString(QUuid::WithoutBraces); + writeSettings(); + } + + QJsonArray devices = doc.object()[JsonKeys::devices].toArray(); for (const QJsonValue &deviceInfoJson : devices) { - DeviceInfo deviceInfo; - DeviceSettings deviceSettings; - deviceInfo.setJsonObject(deviceInfoJson.toObject()["deviceInfo"].toObject()); - deviceSettings.setJsonObject(deviceInfoJson.toObject()["deviceSettings"].toObject()); - auto device = initDevice(deviceInfo, deviceSettings); - m_devices.append(device); + DeviceInfo deviceInfo{deviceInfoJson.toObject()[JsonKeys::deviceInfo].toObject()}; + DeviceSettings deviceSettings{deviceInfoJson.toObject()[JsonKeys::deviceSettings].toObject()}; + initDevice(deviceInfo, deviceSettings); } } @@ -267,60 +280,68 @@ bool DeviceManager::addDevice(const QString &ip) deviceSettings.setAlias(generateDeviceAlias()); deviceSettings.setDeviceId(QUuid::createUuid().toString(QUuid::WithoutBraces)); - auto device = initDevice({}, deviceSettings); - m_devices.append(device); + initDevice({}, deviceSettings); writeSettings(); emit deviceAdded(deviceSettings.deviceId()); return true; } -QSharedPointer DeviceManager::initDevice(const DeviceInfo &deviceInfo, - const DeviceSettings &deviceSettings) +void DeviceManager::initDevice(const DeviceInfo &deviceInfo, const DeviceSettings &deviceSettings) { - QSharedPointer device = QSharedPointer(new Device{deviceInfo, deviceSettings}, + QSharedPointer device = QSharedPointer(new Device{m_designStudioId, + deviceInfo, + deviceSettings}, &QObject::deleteLater); + QString deviceId = device->deviceSettings().deviceId(); connect(device.data(), &Device::deviceInfoReady, this, &DeviceManager::deviceInfoReceived); - connect(device.data(), &Device::disconnected, this, &DeviceManager::deviceDisconnected); + connect(device.data(), &Device::disconnected, this, [this](const QString &deviceId) { + qCDebug(deviceSharePluginLog) << "Device" << deviceId << "disconnected"; + emit deviceOffline(deviceId); + handleError(ErrTypes::NoError, deviceId); + }); connect(device.data(), &Device::projectSendingProgress, this, &DeviceManager::projectSendingProgress); - connect(device.data(), &Device::projectStarted, this, &DeviceManager::projectStarted); - connect(device.data(), &Device::projectStopped, this, &DeviceManager::projectStopped); - connect(device.data(), - &Device::projectLogsReceived, - this, - [this](const QString deviceId, const QString &logs) { - qCDebug(deviceSharePluginLog) << "Log:" << deviceId << logs; - emit projectLogsReceived(deviceId, logs); - }); + connect(device.data(), &Device::projectStarting, this, [this](const QString &deviceId) { + m_currentState = OpTypes::Starting; + emit projectStarting(deviceId); + }); - return device; + connect(device.data(), &Device::projectStarted, this, [this](const QString &deviceId) { + m_currentState = OpTypes::Running; + emit projectStarted(deviceId); + }); + + connect(device.data(), &Device::projectStopped, this, [this](const QString &deviceId) { + handleError(ErrTypes::NoError, deviceId); + }); + connect(device.data(), &Device::projectLogsReceived, this, &DeviceManager::projectLogsReceived); + + m_devices.append(device); } -void DeviceManager::deviceInfoReceived(const QString &deviceIp, const QString &deviceId) +void DeviceManager::deviceInfoReceived(const QString &deviceId) { - auto newDevIt = std::find_if(m_devices.begin(), - m_devices.end(), - [deviceId, deviceIp](const auto &device) { - return device->deviceSettings().deviceId() == deviceId - && device->deviceSettings().ipAddress() == deviceIp; - }); + auto newDevice = findDevice(deviceId); + const QString selfId = newDevice->deviceInfo().selfId(); + const QString deviceIp = newDevice->deviceSettings().ipAddress(); + auto oldDevIt = std::find_if(m_devices.begin(), m_devices.end(), - [deviceId, deviceIp](const auto &device) { - return device->deviceSettings().deviceId() == deviceId + [selfId, deviceIp](const auto &device) { + return device->deviceInfo().selfId() == selfId && device->deviceSettings().ipAddress() != deviceIp; }); // if there are 2 devices with the same ID but different IPs, remove the old one // aka: merge devices with the same ID if (oldDevIt != m_devices.end()) { - QSharedPointer oldDevice = *oldDevIt; - QSharedPointer newDevice = *newDevIt; - DeviceSettings deviceSettings = oldDevice->deviceSettings(); - deviceSettings.setIpAddress(newDevice->deviceSettings().ipAddress()); - newDevice->setDeviceSettings(deviceSettings); - m_devices.removeOne(oldDevice); + auto oldDevice = *oldDevIt; + const QString alias = oldDevice->deviceSettings().alias(); + m_devices.removeOne(*oldDevIt); + DeviceSettings settings = newDevice->deviceSettings(); + settings.setAlias(alias); + newDevice->setDeviceSettings(settings); } writeSettings(); @@ -328,16 +349,6 @@ void DeviceManager::deviceInfoReceived(const QString &deviceIp, const QString &d emit deviceOnline(deviceId); } -void DeviceManager::deviceDisconnected(const QString &deviceId) -{ - auto device = findDevice(deviceId); - if (!device) - return; - - qCDebug(deviceSharePluginLog) << "Device" << deviceId << "disconnected"; - emit deviceOffline(deviceId); -} - void DeviceManager::removeDevice(const QString &deviceId) { auto device = findDevice(deviceId); @@ -360,29 +371,119 @@ void DeviceManager::removeDeviceAt(int index) emit deviceRemoved(deviceId); } -bool DeviceManager::sendProjectFile(const QString &deviceId, const QString &projectFile) +void DeviceManager::handleError(const ErrTypes &errType, const QString &deviceId, const QString &error) { - auto device = findDevice(deviceId); - if (!device) - return false; + if (!m_processInterrupted) { + if (errType != ErrTypes::NoError) + qCWarning(deviceSharePluginLog) << "Handling error" << error << "for device" << deviceId; - QFile file(projectFile); - if (!file.open(QIODevice::ReadOnly)) { - qCWarning(deviceSharePluginLog) << "Failed to open project file" << projectFile; - return false; + switch (errType) { + case ErrTypes::InternalError: + emit internalError(deviceId, error); + break; + case ErrTypes::ProjectPackingError: + emit projectPackingError(deviceId, error); + break; + case ErrTypes::ProjectSendingError: + emit projectSendingError(deviceId, error); + break; + case ErrTypes::ProjectStartError: + emit projectStartingError(deviceId, error); + break; + case ErrTypes::NoError: + break; + } } - qCDebug(deviceSharePluginLog) << "Sending project file to device" << deviceId; - return device->sendProjectData(file.readAll()); + m_processInterrupted = false; + m_currentQtKitVersion.clear(); + m_currentDeviceId.clear(); + m_currentState = OpTypes::Stopped; + emit projectStopped(deviceId); } -bool DeviceManager::stopRunningProject(const QString &deviceId) +void DeviceManager::runProject(const QString &deviceId) { auto device = findDevice(deviceId); - if (!device) - return false; + if (!device) { + handleError(ErrTypes::InternalError, deviceId, "Device not found"); + return; + } - return device->sendProjectStopped(); + if (m_currentState != OpTypes::Stopped) { + qCDebug(deviceSharePluginLog) << "Another operation is in progress"; + return; + } + + m_currentQtKitVersion.clear(); + ProjectExplorer::Target *target = QmlDesignerPlugin::instance()->currentDesignDocument()->currentTarget(); + if (target && target->kit()) { + if (QtSupport::QtVersion *qtVer = QtSupport::QtKitAspect::qtVersion(target->kit())) + m_currentQtKitVersion = qtVer->qtVersion().toString(); + } + + m_currentState = OpTypes::Packing; + m_currentDeviceId = deviceId; + m_resourceGenerator.createQmlrcAsyncWithName(); + emit projectPacking(deviceId); + qCDebug(deviceSharePluginLog) << "Packing project for device" << deviceId; +} + +void DeviceManager::projectPacked(const Utils::FilePath &filePath) +{ + qCDebug(deviceSharePluginLog) << "Project packed" << filePath.toString(); + emit projectSendingProgress(m_currentDeviceId, 0); + + m_currentState = OpTypes::Sending; + qCDebug(deviceSharePluginLog) << "Sending project file to device" << m_currentDeviceId; + QFile file(filePath.toString()); + + if (!file.open(QIODevice::ReadOnly)) { + handleError(ErrTypes::ProjectSendingError, m_currentDeviceId, "Failed to open project file"); + return; + } + + ProjectExplorer::Target *target = QmlDesignerPlugin::instance()->currentDesignDocument()->currentTarget(); + if (target && target->kit()) { + if (QtSupport::QtVersion *qtVer = QtSupport::QtKitAspect::qtVersion(target->kit())) + m_currentQtKitVersion = qtVer->qtVersion().toString(); + } + + if (!findDevice(m_currentDeviceId)->sendProjectData(file.readAll(), m_currentQtKitVersion)) { + handleError(ErrTypes::ProjectSendingError, m_currentDeviceId, "Failed to send project file"); + return; + } +} + +void DeviceManager::stopProject() +{ + auto device = findDevice(m_currentDeviceId); + if (!device) { + handleError(ErrTypes::InternalError, m_currentDeviceId, "Device not found"); + return; + } + + m_processInterrupted = true; + switch (m_currentState) { + case OpTypes::Stopped: + qCWarning(deviceSharePluginLog) << "No project is running"; + return; + case OpTypes::Packing: + qCDebug(deviceSharePluginLog) << "Canceling project packing"; + m_resourceGenerator.cancel(); + break; + case OpTypes::Sending: + qCDebug(deviceSharePluginLog) << "Cancelling project sending"; + device->abortProjectTransmission(); + break; + case OpTypes::Starting: + case OpTypes::Running: + qCDebug(deviceSharePluginLog) << "Stopping project on device" << m_currentDeviceId; + device->sendProjectStopped(); + break; + } + + emit projectStopping(m_currentDeviceId); } DeviceManagerWidget *DeviceManager::widget() diff --git a/src/plugins/qmldesigner/components/devicesharing/devicemanager.h b/src/plugins/qmldesigner/components/devicesharing/devicemanager.h index f6868d9cfd1..9385d73b165 100644 --- a/src/plugins/qmldesigner/components/devicesharing/devicemanager.h +++ b/src/plugins/qmldesigner/components/devicesharing/devicemanager.h @@ -7,6 +7,8 @@ #include #include +#include + #include "device.h" namespace QmlDesigner::DeviceShare { @@ -36,8 +38,10 @@ public: bool addDevice(const QString &ip); void removeDevice(const QString &deviceId); void removeDeviceAt(int index); - bool sendProjectFile(const QString &deviceId, const QString &projectFile); - bool stopRunningProject(const QString &deviceId); + + // project management functions + void runProject(const QString &deviceId); // async + void stopProject(); // async DeviceManagerWidget *widget(); @@ -48,7 +52,22 @@ private: // settings QString m_settingsPath; - QString m_uuid; + QString m_designStudioId; + + enum class ErrTypes { + NoError, + InternalError, + ProjectPackingError, + ProjectSendingError, + ProjectStartError + }; + enum class OpTypes { Stopped, Packing, Sending, Starting, Running }; + OpTypes m_currentState; + QString m_currentDeviceId; + QString m_currentQtKitVersion; + bool m_processInterrupted; + + QmlDesigner::ResourceGenerator m_resourceGenerator; QPointer m_widget; @@ -59,16 +78,21 @@ private: void incomingConnection(); void readSettings(); void writeSettings(); - QSharedPointer initDevice(const DeviceInfo &deviceInfo = DeviceInfo(), - const DeviceSettings &deviceSettings = DeviceSettings()); + void initDevice(const DeviceInfo &deviceInfo = DeviceInfo(), + const DeviceSettings &deviceSettings = DeviceSettings()); // device signals - void deviceInfoReceived(const QString &deviceIp, const QString &deviceId); - void deviceDisconnected(const QString &deviceId); + void deviceInfoReceived(const QString &deviceId); QSharedPointer findDevice(const QString &deviceId) const; QString generateDeviceAlias() const; + // internal functions + void projectPacked(const Utils::FilePath &filePath); + void handleError(const ErrTypes &errType, + const QString &deviceId, + const QString &error = QString()); + signals: void deviceAdded(const QString &deviceId); void deviceRemoved(const QString &deviceId); @@ -77,10 +101,19 @@ signals: void deviceActivated(const QString &deviceId); void deviceDeactivated(const QString &deviceId); void deviceAliasChanged(const QString &deviceId); + + void projectPacking(const QString &deviceId); + void projectPackingError(const QString &deviceId, const QString &error); void projectSendingProgress(const QString &deviceId, const int percentage); + void projectSendingError(const QString &deviceId, const QString &error); + void projectStarting(const QString &deviceId); + void projectStartingError(const QString &deviceId, const QString &error); void projectStarted(const QString &deviceId); + void projectStopping(const QString &deviceId); void projectStopped(const QString &deviceId); void projectLogsReceived(const QString &deviceId, const QString &logs); + + void internalError(const QString &deviceId, const QString &error); }; } // namespace QmlDesigner::DeviceShare diff --git a/src/plugins/qmldesigner/components/runmanager/runmanager.cpp b/src/plugins/qmldesigner/components/runmanager/runmanager.cpp index a83b247add0..4ac1a9a56eb 100644 --- a/src/plugins/qmldesigner/components/runmanager/runmanager.cpp +++ b/src/plugins/qmldesigner/components/runmanager/runmanager.cpp @@ -8,10 +8,6 @@ #include -#ifdef DVCONNECTOR_ENABLED -#include -#endif - namespace QmlDesigner { Q_LOGGING_CATEGORY(runManagerLog, "qtc.designer.runManager", QtWarningMsg) @@ -180,10 +176,7 @@ void RunManager::toggleCurrentTarget() if (!arg.isNull()) arg.get()->initiateStop(); }, - [](const QString arg) { - if (!arg.isEmpty()) - deviceManager()->stopRunningProject(arg); - }}, + [](const QString &) { deviceManager()->stopProject(); }}, runningTarget); } return; @@ -329,10 +322,8 @@ void AndroidTarget::run() const { if (!ProjectExplorer::ProjectExplorerPlugin::saveModifiedFiles()) return; -#ifdef DVCONNECTOR_ENABLED - auto qmlrcPath = DesignViewer::ResourceGeneratorProxy().createResourceFileSync(); - deviceManager()->sendProjectFile(m_deviceId, qmlrcPath->toString()); -#endif + + deviceManager()->runProject(m_deviceId); } } // namespace QmlDesigner From e5234c08c3aa2d5535bcdba0cd4f624dbe09e918 Mon Sep 17 00:00:00 2001 From: Pranta Dastider Date: Tue, 17 Dec 2024 17:15:00 +0100 Subject: [PATCH 03/14] QmlDesigner: Update tooltip for the anchored Rectangle component This patch updates tooltip for the anchored Rectangle component. Fixes: QDS-13219 Change-Id: I742b32743b028a194aaf304735cd47d8b8e156c7 Reviewed-by: Aleksei German --- .../propertyEditorQmlSources/QtQuick/GeometrySection.qml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GeometrySection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GeometrySection.qml index edf56c9b520..917b56e474e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GeometrySection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/GeometrySection.qml @@ -15,6 +15,7 @@ Section { anchors.right: parent.right readonly property string disabledTooltip: qsTr("This property is defined by an anchor or a layout.") + readonly property string disabledAnchoredTooltip: qsTr("Adjust this property manually from the 2D view or by changing margins from Layout.") function positionDisabled() { return anchorBackend.isFilled || anchorBackend.isInLayout @@ -67,7 +68,7 @@ Section { ControlLabel { text: "X" - tooltip: xSpinBox.enabled ? qsTr("X-coordinate") : root.disabledTooltip + tooltip: xSpinBox.enabled ? qsTr("X-coordinate") : root.disabledAnchoredTooltip enabled: xSpinBox.enabled } @@ -88,7 +89,7 @@ Section { ControlLabel { text: "Y" - tooltip: xSpinBox.enabled ? qsTr("Y-coordinate") : root.disabledTooltip + tooltip: ySpinBox.enabled ? qsTr("Y-coordinate") : root.disabledAnchoredTooltip enabled: ySpinBox.enabled } /* @@ -123,7 +124,7 @@ Section { ControlLabel { //: The width of the object text: qsTr("W", "width") - tooltip: widthSpinBox.enabled ? qsTr("Width") : root.disabledTooltip + tooltip: widthSpinBox.enabled ? qsTr("Width") : root.disabledAnchoredTooltip enabled: widthSpinBox.enabled } @@ -145,7 +146,7 @@ Section { ControlLabel { //: The height of the object text: qsTr("H", "height") - tooltip: heightSpinBox.enabled ? qsTr("Height") : root.disabledTooltip + tooltip: heightSpinBox.enabled ? qsTr("Height") : root.disabledAnchoredTooltip enabled: heightSpinBox.enabled } /* From 0eb93499eeeeb556c096f488231d92516810c6eb Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Fri, 3 Jan 2025 15:07:10 +0200 Subject: [PATCH 04/14] Doc: Update verbs for interacting with UI Fixed the occurrences of the following verbs: drag-and-drop, check, deselect, uncheck, press, press and hover, hover the mouse/cursor over, and type. Task-number: QDS-14114 Change-Id: I31d0082fe2d51b3e5e394e0f7db503ece1dcbf8a Reviewed-by: Leena Miettinen --- doc/qtcreator/src/analyze/creator-axivion.qdoc | 2 +- .../src/analyze/creator-clang-static-analyzer.qdoc | 4 ++-- doc/qtcreator/src/analyze/creator-valgrind.qdoc | 2 +- .../src/cmake/creator-projects-cmake.qdoc | 2 +- .../debugger/creator-only/creator-debugger.qdoc | 4 ++-- .../src/editors/creator-code-completion.qdoc | 2 +- .../src/editors/creator-code-indentation.qdoc | 2 +- .../src/editors/creator-editors-options-text.qdoc | 4 ++-- .../creator-only/creator-clang-codemodel.qdoc | 4 ++-- .../creator-only/creator-coding-edit-mode.qdoc | 2 +- .../src/editors/creator-only/creator-copilot.qdoc | 3 +-- .../src/editors/creator-only/creator-locator.qdoc | 6 +++--- .../creator-preferences-text-editor-behavior.qdoc | 2 +- .../src/howto/creator-only/creator-autotest.qdoc | 4 ++-- .../creator-only/creator-how-to-document-code.qdoc | 2 +- .../creator-how-to-record-screens.qdoc | 2 +- .../src/howto/creator-only/qtcreator-faq.qdoc | 8 ++++---- .../creator-deployment-embedded-linux.qdoc | 2 +- .../creator-only/creator-build-settings-qmake.qdoc | 4 ++-- ...ator-how-to-create-compiler-explorer-setup.qdoc | 2 +- .../creator-only/creator-projects-libraries.qdoc | 2 +- .../creator-only/creator-projects-qbs.qdoc | 2 +- .../creator-projects-settings-build-qbs.qdoc | 6 +++--- .../creator-projects-settings-editor.qdoc | 2 +- .../creator-projects-settings-overview.qdoc | 2 +- ...tor-tutorial-python-application-qt-widgets.qdoc | 2 +- .../creator-only/creator-how-to-detach-views.qdoc | 2 +- .../creator-how-to-show-and-hide-main-menu.qdoc | 2 +- .../creator-reference-sidebar-views.qdoc | 2 +- .../creator-reference-terminal-view.qdoc | 2 +- .../src/user-interface/creator-projects-view.qdoc | 4 ++-- .../creator-reference-output-views.qdoc | 2 +- .../vcs/creator-only/creator-vcs-clearcase.qdoc | 2 +- .../src/vcs/creator-only/creator-vcs-perforce.qdoc | 2 +- doc/qtcreatordev/src/qtcreator-ui-text.qdoc | 2 +- .../examples/doc/animationTutorial.qdoc | 2 +- doc/qtdesignstudio/examples/doc/coffeemachine.qdoc | 2 +- doc/qtdesignstudio/examples/doc/ebikedesign.qdoc | 2 +- doc/qtdesignstudio/examples/doc/loginui4.qdoc | 2 +- doc/qtdesignstudio/examples/doc/progressbar.qdoc | 10 +++++----- doc/qtdesignstudio/examples/doc/sidemenu.qdoc | 12 ++++++------ .../examples/doc/washingMachineUI.qdoc | 2 +- doc/qtdesignstudio/examples/doc/webinardemo.qdoc | 2 +- .../src/components/qtquick-animation-types.qdoc | 4 ++-- .../src/components/qtquick-buttons.qdoc | 12 ++++++------ .../components/qtquick-component-instances.qdoc | 2 +- .../src/components/qtquick-components-custom.qdoc | 2 +- .../src/components/qtquick-controls.qdoc | 4 ++-- .../src/components/qtquick-images.qdoc | 4 ++-- .../src/components/qtquick-pathview-editor.qdocinc | 2 +- .../qtquick-user-interaction-methods.qdoc | 2 +- .../src/overviews/qtquick-export.qdoc | 2 +- doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc | 2 +- .../src/qtdesignstudio-importing-2d.qdoc | 12 ++++++------ .../src/qtdesignstudio-simulink.qdoc | 4 ++-- .../exporting-3d/exporting-from-qt3ds.qdoc | 2 +- .../qtdesignstudio-3d-effects.qdoc | 2 +- .../qtquick3d-editor/qtdesignstudio-3d-group.qdoc | 2 +- .../qtdesignstudio-3d-instancing.qdoc | 6 +++--- .../qtdesignstudio-3d-materials.qdoc | 2 +- .../qtdesignstudio-3d-morph-target.qdoc | 2 +- .../qtdesignstudio-3d-particles.qdoc | 4 ++-- .../qtdesignstudio-logic-helpers.qdoc | 14 +++++++------- .../src/views/qtquick-curve-editor.qdoc | 4 ++-- .../src/views/qtquick-properties.qdoc | 2 +- doc/qtdesignstudio/src/views/qtquick-states.qdoc | 2 +- 66 files changed, 113 insertions(+), 114 deletions(-) diff --git a/doc/qtcreator/src/analyze/creator-axivion.qdoc b/doc/qtcreator/src/analyze/creator-axivion.qdoc index 72b5bfacfe6..472b666ded6 100644 --- a/doc/qtcreator/src/analyze/creator-axivion.qdoc +++ b/doc/qtcreator/src/analyze/creator-axivion.qdoc @@ -19,7 +19,7 @@ The editor shows found issues as inline annotations if the project matches the currently open one and the respective file is part of the project. - Hover the mouse over an annotation to bring up a tooltip with a short + hover over an annotation to bring up a tooltip with a short description of the issue. \image qtcreator-axivion-annotation.webp {Annotation popup} diff --git a/doc/qtcreator/src/analyze/creator-clang-static-analyzer.qdoc b/doc/qtcreator/src/analyze/creator-clang-static-analyzer.qdoc index 061feff3c56..b85de2db637 100644 --- a/doc/qtcreator/src/analyze/creator-clang-static-analyzer.qdoc +++ b/doc/qtcreator/src/analyze/creator-clang-static-analyzer.qdoc @@ -140,7 +140,7 @@ \li Select \uicontrol Projects > \uicontrol {Project Settings} > \uicontrol {Clang Tools}. \image qtcreator-clang-tools-settings.webp {Clang Tools customized settings} - \li Deselect \uicontrol {Use global settings}. + \li Clear \uicontrol {Use global settings}. \li Specify \uicontrol preferences for the project. \li In \uicontrol {Suppressed diagnostics}, you can view the suppression list for a project and to remove diagnostics from it. @@ -196,7 +196,7 @@ generated during the build. For big projects, not building the project might save some time. - \li To disable automatic analysis of open documents, deselect the + \li To disable automatic analysis of open documents, clear the \uicontrol {Analyze open files} check box. \li In the \uicontrol {Parallel jobs} field, select the number of jobs diff --git a/doc/qtcreator/src/analyze/creator-valgrind.qdoc b/doc/qtcreator/src/analyze/creator-valgrind.qdoc index dfc43effb49..f7cf6cf031d 100644 --- a/doc/qtcreator/src/analyze/creator-valgrind.qdoc +++ b/doc/qtcreator/src/analyze/creator-valgrind.qdoc @@ -122,7 +122,7 @@ Memcheck also reports uses of uninitialised values, most commonly with the message \uicontrol {Conditional jump or move depends on uninitialised value(s).} To determine the root cause of these errors, the \uicontrol {Track origins of - uninitialized memory} check box is selected by default. You can deselect it + uninitialized memory} check box is selected by default. You can clear it to make Memcheck run faster. \section1 Viewing a Summary diff --git a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc index 09a5bff85f4..fc0318d3d55 100644 --- a/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc +++ b/doc/qtcreator/src/cmake/creator-projects-cmake.qdoc @@ -94,7 +94,7 @@ source files are located. To hide the subfolder names and arrange the files only according to their source group, select \preferences > \uicontrol CMake > \uicontrol General, and then - deselect the \uicontrol {Show subfolders inside source group folders} check + clear the \uicontrol {Show subfolders inside source group folders} check box. The change takes effect after you select \uicontrol Build > \uicontrol {Run CMake}. diff --git a/doc/qtcreator/src/debugger/creator-only/creator-debugger.qdoc b/doc/qtcreator/src/debugger/creator-only/creator-debugger.qdoc index c15f1de3b42..c6a3b657520 100644 --- a/doc/qtcreator/src/debugger/creator-only/creator-debugger.qdoc +++ b/doc/qtcreator/src/debugger/creator-only/creator-debugger.qdoc @@ -1109,7 +1109,7 @@ If you cannot debug Qt objects because their data is corrupted, you can switch off the debugging helpers to make low-level structures visible. - To switch off the debugging helpers, deselect + To switch off the debugging helpers, clear \uicontrol {Use Debugging Helpers} in \preferences > \uicontrol Debugger > \uicontrol {Locals & Expressions}. @@ -2166,7 +2166,7 @@ \section1 Structure Members Are Not Sorted According to Structure Layout By default, structure members are displayed in alphabetic order. To inspect - the real layout in memory, deselect + the real layout in memory, clear \uicontrol {Sort Members of Classes and Structs Alphabetically} in the context menu in the \uicontrol Locals and \uicontrol Expressions views. diff --git a/doc/qtcreator/src/editors/creator-code-completion.qdoc b/doc/qtcreator/src/editors/creator-code-completion.qdoc index 568df6e96c9..c595748882c 100644 --- a/doc/qtcreator/src/editors/creator-code-completion.qdoc +++ b/doc/qtcreator/src/editors/creator-code-completion.qdoc @@ -166,7 +166,7 @@ When completion is invoked manually, \QC completes the common prefix of the list of suggestions. This is especially useful for classes with several - similarly named members. To disable this functionality, deselect the + similarly named members. To disable this functionality, clear the \uicontrol {Autocomplete common prefix} check box. Select the \uicontrol {Automatically split strings} check box to split diff --git a/doc/qtcreator/src/editors/creator-code-indentation.qdoc b/doc/qtcreator/src/editors/creator-code-indentation.qdoc index 42c3b2dd9ba..6b719908781 100644 --- a/doc/qtcreator/src/editors/creator-code-indentation.qdoc +++ b/doc/qtcreator/src/editors/creator-code-indentation.qdoc @@ -68,7 +68,7 @@ To help you keep line length at a particular number of characters, set the number of characters in the \uicontrol {Display right margin at column} field. To use a different color for the margin area, select the - \uicontrol {Tint whole margin area} check box. Deselect the check box to show + \uicontrol {Tint whole margin area} check box. Clear the check box to show the margin as a vertical line. To use a context-specific margin when available, select the diff --git a/doc/qtcreator/src/editors/creator-editors-options-text.qdoc b/doc/qtcreator/src/editors/creator-editors-options-text.qdoc index ce84c44cfcf..e29195c85d8 100644 --- a/doc/qtcreator/src/editors/creator-editors-options-text.qdoc +++ b/doc/qtcreator/src/editors/creator-editors-options-text.qdoc @@ -34,14 +34,14 @@ percentage for viewing the text. You can also zoom in or out by pressing \key {Ctrl++} or \key {Ctrl+-}, or by pressing \key Ctrl and rolling the mouse button up or down. To disable the mouse wheel function, select - \preferences > \uicontrol {Text Editor} > \uicontrol Behavior and deselect + \preferences > \uicontrol {Text Editor} > \uicontrol Behavior and clear the \uicontrol {Enable scroll wheel zooming} check box. To improve the readability of text in the editor, adjust the line spacing in the \uicontrol {Line spacing} field. Antialiasing is used by default to make text look smoother and more readable - on the screen. Deselect the \uicontrol Antialias check box to turn off + on the screen. Clear the \uicontrol Antialias check box to turn off antialiasing. \sa {Behavior}, {Change editor colors} diff --git a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc index ae81bdc3abd..8dbe339f080 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-clang-codemodel.qdoc @@ -88,7 +88,7 @@ \endlist To use the built-in code model instead, select \preferences > - \uicontrol C++ > \uicontrol clangd, and deselect the \uicontrol {Use clangd} check box. + \uicontrol C++ > \uicontrol clangd, and clear the \uicontrol {Use clangd} check box. This setting also exists on the project level, so that you can have the Clang-based services generally enabled, but switch them off for certain projects, or vice versa. @@ -337,7 +337,7 @@ \li Select \uicontrol Projects > \uicontrol {Project Settings} > \uicontrol {Clangd}. \image qtcreator-projects-settings-clangd.webp {Clangd preferences for a project} - \li Deselect \uicontrol {Use global settings}. + \li Clear \uicontrol {Use global settings}. \li Select \uicontrol {Use clangd}. \li Specify \uicontrol Clangd preferences for the project. \endlist diff --git a/doc/qtcreator/src/editors/creator-only/creator-coding-edit-mode.qdoc b/doc/qtcreator/src/editors/creator-only/creator-coding-edit-mode.qdoc index a0ae5419f4c..e61cf51f12b 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-coding-edit-mode.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-coding-edit-mode.qdoc @@ -230,7 +230,7 @@ filter to locate the files. To use the sorting from the selected tool instead of from \QC, - deselect the \uicontrol {Sort results} check box in the \c md + clear the \uicontrol {Sort results} check box in the \c md locator filter configuration. \image qtcreator-locator-filter-edit-md.webp {Filter Configuration dialog} diff --git a/doc/qtcreator/src/editors/creator-only/creator-copilot.qdoc b/doc/qtcreator/src/editors/creator-only/creator-copilot.qdoc index fa9382cbc1a..1b46f80a8fb 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-copilot.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-copilot.qdoc @@ -80,8 +80,7 @@ enter \uicontrol {t} (\uicontrol {Request Copilot Suggestion}) in the \l{Navigate with locator}{locator}. - Hover the mouse over a suggestion to show a toolbar with - \inlineimage icons/prev.png + Hover over a suggestion to show a toolbar with \inlineimage icons/prev.png and \inlineimage icons/next.png buttons for cycling between Copilot suggestions. diff --git a/doc/qtcreator/src/editors/creator-only/creator-locator.qdoc b/doc/qtcreator/src/editors/creator-only/creator-locator.qdoc index 4dd6aa72eeb..81d293ac05e 100644 --- a/doc/qtcreator/src/editors/creator-only/creator-locator.qdoc +++ b/doc/qtcreator/src/editors/creator-only/creator-locator.qdoc @@ -47,8 +47,8 @@ To use a locator filter: \list - \li Type the locator filter prefix followed by \key Space. The prefix - is usually short, from one to three characters. Then type the search + \li Enter the locator filter prefix followed by \key Space. The prefix + is usually short, from one to three characters. Then enter the search string (for example, a filename or class name) or the command to execute. @@ -58,7 +58,7 @@ selected filter. \endlist - As you type a search string, + As you enter a search string, the locator shows the occurrences of that string regardless of where in the name of an object it appears. Some locator filters, such as colon, \c m, and \c t, support \e fuzzy matching, which means that you can enter the diff --git a/doc/qtcreator/src/editors/creator-preferences-text-editor-behavior.qdoc b/doc/qtcreator/src/editors/creator-preferences-text-editor-behavior.qdoc index addf18052d4..09b54b3a416 100644 --- a/doc/qtcreator/src/editors/creator-preferences-text-editor-behavior.qdoc +++ b/doc/qtcreator/src/editors/creator-preferences-text-editor-behavior.qdoc @@ -68,7 +68,7 @@ select \preferences > \uicontrol {Text Editor} > \uicontrol Behavior > \uicontrol Typing. - To disable automatic indentation, deselect the + To disable automatic indentation, clear the \uicontrol {Enable automatic indentation} check box. You can specify how the indentation is decreased when you press diff --git a/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc b/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc index fa182111007..b461a72162f 100644 --- a/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc +++ b/doc/qtcreator/src/howto/creator-only/creator-autotest.qdoc @@ -368,7 +368,7 @@ If a Qt Quick test case does not have a name, it is marked \uicontrol Unnamed in the list. \uicontrol {Run All Tests} executes - unnamed test cases. You cannot select or deselect them. + unnamed test cases. You cannot select or clear them. \QC scans the project for tests when you open the project and updates the test list for the currently active test frameworks when you edit tests. @@ -848,7 +848,7 @@ To show all messages, select \uicontrol {Check All Filters}. - To deselect all message types, select \uicontrol {Uncheck All Filters}. + To clear all message types, select \uicontrol {Uncheck All Filters}. \section1 Blacklisting Tests diff --git a/doc/qtcreator/src/howto/creator-only/creator-how-to-document-code.qdoc b/doc/qtcreator/src/howto/creator-only/creator-how-to-document-code.qdoc index d56a1f288cb..1f5fb025046 100644 --- a/doc/qtcreator/src/howto/creator-only/creator-how-to-document-code.qdoc +++ b/doc/qtcreator/src/howto/creator-only/creator-how-to-document-code.qdoc @@ -15,7 +15,7 @@ To set preferences for documentation comments for a particular project, select \uicontrol Projects > \uicontrol {Project Settings} > - \uicontrol {Documentation Comments}, and deselect the + \uicontrol {Documentation Comments}, and clear the \uicontrol {Use global settings} check box. \image qtcreator-preferences-documentation-comments.webp {Documentation Comments settings} diff --git a/doc/qtcreator/src/howto/creator-only/creator-how-to-record-screens.qdoc b/doc/qtcreator/src/howto/creator-only/creator-how-to-record-screens.qdoc index c8a624622d3..590b5d60cff 100644 --- a/doc/qtcreator/src/howto/creator-only/creator-how-to-record-screens.qdoc +++ b/doc/qtcreator/src/howto/creator-only/creator-how-to-record-screens.qdoc @@ -137,7 +137,7 @@ Increase the limit if frames are dropped during the recording. \row \li \uicontrol {Export animated images as infinite loop} - \li Whether to export animated images as inifite loops. Deselect + \li Whether to export animated images as inifite loops. Clear this check box to only play the animation once. \row \li \uicontrol {Write command line of FFmpeg calls to General Messages} diff --git a/doc/qtcreator/src/howto/creator-only/qtcreator-faq.qdoc b/doc/qtcreator/src/howto/creator-only/qtcreator-faq.qdoc index b510ba618b5..cd50e37d23b 100644 --- a/doc/qtcreator/src/howto/creator-only/qtcreator-faq.qdoc +++ b/doc/qtcreator/src/howto/creator-only/qtcreator-faq.qdoc @@ -149,7 +149,7 @@ To trigger the GDB command that generates a core file while debugging, go to \uicontrol View > \uicontrol Views > \l {Debugger Log}. - In the \uicontrol Command field, type \c gcore and select \key Enter. The + In the \uicontrol Command field, enter \c gcore and select \key Enter. The core file is created in the current working directory. You can specify another location for the file, including a relative or absolute path, as an argument of the command. @@ -232,7 +232,7 @@ When you run a console application, you can view the output in the console window of the calling application. If the calling application is a GUI application (for example, a release-built - version of \QC), a new console window is opened. For this + version of \QC), a new console window is opened. For this type of application, \c qDebug() and related functions use standard output and error output. @@ -317,8 +317,8 @@ in the tab bar, find our that the function is inline, fix the problem, and forget where they came from. - With \QC, developers can type \c {Ctrl+K m AFun} to find the function. - Typically, they only need to type 3 to 4 characters of the function name. + With \QC, developers can enter \c {Ctrl+K m AFun} to find the function. + Typically, they only need to enter 3 to 4 characters of the function name. They can then fix the problem and select \key Alt+Back to go back to where they were. diff --git a/doc/qtcreator/src/linux-mobile/creator-deployment-embedded-linux.qdoc b/doc/qtcreator/src/linux-mobile/creator-deployment-embedded-linux.qdoc index 87c54e26faa..2ff4b7c85ad 100644 --- a/doc/qtcreator/src/linux-mobile/creator-deployment-embedded-linux.qdoc +++ b/doc/qtcreator/src/linux-mobile/creator-deployment-embedded-linux.qdoc @@ -100,7 +100,7 @@ deployment time and only copies files that have changed since the last deployment. However, when you make major changes on the device, such as removing files from the device manually or flashing a new disk image, or - when you use another device with the same IP address, deselect the check box + when you use another device with the same IP address, clear the check box once, to have \QC deploy all files again. \section2 Creating a Tarball diff --git a/doc/qtcreator/src/projects/creator-only/creator-build-settings-qmake.qdoc b/doc/qtcreator/src/projects/creator-only/creator-build-settings-qmake.qdoc index 814189ee7b6..512251398fc 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-build-settings-qmake.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-build-settings-qmake.qdoc @@ -22,7 +22,7 @@ By default, \QC builds qmake projects (that have .pro files) in a separate directory from the source directory, as \l{glossary-shadow-build} {shadow builds}. This keeps the files generated for each kit separate. If - you only build and run with a single kit, you can deselect the + you only build and run with a single kit, you can clear the \uicontrol {Shadow build} checkbox. Select the build directory in the \uicontrol {Build Directory} field. You @@ -38,7 +38,7 @@ \section1 Tooltips in Kit Selector In the \uicontrol {Tooltip in target selector} field, you can enter text - that is displayed as a tooltip when you hover the mouse over the build + that is displayed as a tooltip when you hover over the build configuration in the \l{Build for many platforms}{kit selector}. You can create separate versions of project files to keep platform-dependent diff --git a/doc/qtcreator/src/projects/creator-only/creator-how-to-create-compiler-explorer-setup.qdoc b/doc/qtcreator/src/projects/creator-only/creator-how-to-create-compiler-explorer-setup.qdoc index e228abe8e03..2c98c1ba78b 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-how-to-create-compiler-explorer-setup.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-how-to-create-compiler-explorer-setup.qdoc @@ -60,7 +60,7 @@ \li Enter code to see the resulting assembly code. \endlist - Hover the mouse over the assembly code, to have the matching source lines + hover over the assembly code, to have the matching source lines highlighted. You can also see the application status and output. diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-libraries.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-libraries.qdoc index 4dfbc400c01..e928e93ab1b 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-libraries.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-libraries.qdoc @@ -85,7 +85,7 @@ debug version. For example, if the release version is called example.lib, the debug version is called exampled.lib. You can specify that the letter is added for the debug version and removed for the release version. - If the library name ends in \e d, deselect the \uicontrol {Remove "d" suffix + If the library name ends in \e d, clear the \uicontrol {Remove "d" suffix for release version} option. For more information about the project file settings, see diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-qbs.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-qbs.qdoc index abdad87807e..38f07b2cde2 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-qbs.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-qbs.qdoc @@ -66,7 +66,7 @@ \list 1 \li Select \preferences > \uicontrol Qbs. \image qtcreator-options-qbs.png "Qbs preferences" - \li Deselect the \uicontrol {Use \QC settings directory for Qbs} check + \li Clear the \uicontrol {Use \QC settings directory for Qbs} check box to store Qbs profiles in the Qbs settings directory. \li In the \uicontrol {Path to qbs executable} field, you can view and change the path to the Qbs executable. diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-build-qbs.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-build-qbs.qdoc index 0c33472862d..e7b0be2a9fa 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-build-qbs.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-build-qbs.qdoc @@ -21,7 +21,7 @@ \uicontrol {Build Directory} field. In the \uicontrol {Tooltip in target selector} field, you can enter text - that is displayed as a tooltip when you hover the mouse over the build + that is displayed as a tooltip when you hover over the build configuration in the \l{Build for many platforms}{kit selector}. You can enter a name for the build configuration in the @@ -98,7 +98,7 @@ \note On Windows, the build will fail if the application is running because the executable file cannot be - overwritten. To avoid this issue, you can deselect this + overwritten. To avoid this issue, you can clear this check box and add a \uicontrol {Qbs Install} deployment step in the run settings that will be performed just before running the application. @@ -108,7 +108,7 @@ starts. \li Select \uicontrol {Use default location} to install the - artifacts to the default location. Deselect the check box to + artifacts to the default location. Clear the check box to specify another location in the \uicontrol {Installation directory} field. diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-editor.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-editor.qdoc index 5f1ff4073c6..54067302fb3 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-editor.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-editor.qdoc @@ -26,7 +26,7 @@ \li Select \uicontrol Projects > \uicontrol {Project Settings} > \uicontrol Editor. - \li Deselect \uicontrol {Use global settings}. + \li Clear \uicontrol {Use global settings}. \li Specify text editor settings for the project. diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc index acbf3a20c69..18ea38e4e34 100644 --- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc +++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-overview.qdoc @@ -72,7 +72,7 @@ \image qtcreator-settings-run-desktop.webp {Run Settings} To prevent \QC from automatically creating run configurations, select - \preferences > \uicontrol {Build & Run}, and then deselect the + \preferences > \uicontrol {Build & Run}, and then clear the \uicontrol {Create suitable run configurations automatically} check box. \section1 Overriding Global Preferences diff --git a/doc/qtcreator/src/python/creator-tutorial-python-application-qt-widgets.qdoc b/doc/qtcreator/src/python/creator-tutorial-python-application-qt-widgets.qdoc index 6235af0adb4..5911ddcda8e 100644 --- a/doc/qtcreator/src/python/creator-tutorial-python-application-qt-widgets.qdoc +++ b/doc/qtcreator/src/python/creator-tutorial-python-application-qt-widgets.qdoc @@ -41,7 +41,7 @@ \li Select \uicontrol{Next} (on Windows and Linux) or \uicontrol Continue (on \macos) to open the \uicontrol {Define Class} dialog. \image qtcreator-new-qt-for-python-app-widgets-define-class.webp {Define Class dialog} - \li In \uicontrol {Class name}, type \b {MyWidget} as the class + \li In \uicontrol {Class name}, enter \b {MyWidget} as the class name. \li In \uicontrol {Base class}, select \b {QWidget} as the base class. \note The \uicontrol {Source file} field is automatically updated to diff --git a/doc/qtcreator/src/user-interface/creator-only/creator-how-to-detach-views.qdoc b/doc/qtcreator/src/user-interface/creator-only/creator-how-to-detach-views.qdoc index 3534e055ec8..3334ad2b4a2 100644 --- a/doc/qtcreator/src/user-interface/creator-only/creator-how-to-detach-views.qdoc +++ b/doc/qtcreator/src/user-interface/creator-only/creator-how-to-detach-views.qdoc @@ -24,7 +24,7 @@ \endlist To show the title bars of views, select \uicontrol View > \uicontrol Views, - and deselect the \uicontrol {Automatically Hide Title Bars} check box. + and clear the \uicontrol {Automatically Hide Title Bars} check box. \section1 Attach views diff --git a/doc/qtcreator/src/user-interface/creator-only/creator-how-to-show-and-hide-main-menu.qdoc b/doc/qtcreator/src/user-interface/creator-only/creator-how-to-show-and-hide-main-menu.qdoc index beddf52bdf6..d22e51f8d9a 100644 --- a/doc/qtcreator/src/user-interface/creator-only/creator-how-to-show-and-hide-main-menu.qdoc +++ b/doc/qtcreator/src/user-interface/creator-only/creator-how-to-show-and-hide-main-menu.qdoc @@ -10,7 +10,7 @@ \title Show and hide the main menu On Linux and Windows, you can hide the main menu bar to save space on the - screen. Select \uicontrol View, and deselect the \uicontrol {Show Menu Bar} + screen. Select \uicontrol View, and clear the \uicontrol {Show Menu Bar} check box. \image qtcreator-without-menubar.webp {Qt Creator without the main menu} diff --git a/doc/qtcreator/src/user-interface/creator-only/creator-reference-sidebar-views.qdoc b/doc/qtcreator/src/user-interface/creator-only/creator-reference-sidebar-views.qdoc index 8fb8ebf315d..845e9fc697f 100644 --- a/doc/qtcreator/src/user-interface/creator-only/creator-reference-sidebar-views.qdoc +++ b/doc/qtcreator/src/user-interface/creator-only/creator-reference-sidebar-views.qdoc @@ -24,7 +24,7 @@ \inlineimage icons/sort_alphabetically.png (\uicontrol {Sort Alphabetically}). \li To stop the synchronization with the type or symbol selected in the - editor, deselect \inlineimage icons/linkicon.png + editor, clear \inlineimage icons/linkicon.png (\uicontrol {Synchronize with Editor}). \endlist */ diff --git a/doc/qtcreator/src/user-interface/creator-only/creator-reference-terminal-view.qdoc b/doc/qtcreator/src/user-interface/creator-only/creator-reference-terminal-view.qdoc index de8bf56335f..ffea2684da0 100644 --- a/doc/qtcreator/src/user-interface/creator-only/creator-reference-terminal-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-only/creator-reference-terminal-view.qdoc @@ -42,7 +42,7 @@ in the context menu or select \key {Ctrl+A}. \li To open links in a browser, files in the editor, or folders in the - \l Projects view, hover the mouse over them, and select \key Ctrl. + \l Projects view, hover over them, and select \key Ctrl. \li To \l{Search in current file}{search} through the output, press \key {Ctrl+F}. diff --git a/doc/qtcreator/src/user-interface/creator-projects-view.qdoc b/doc/qtcreator/src/user-interface/creator-projects-view.qdoc index a6826c9ca3e..af714894793 100644 --- a/doc/qtcreator/src/user-interface/creator-projects-view.qdoc +++ b/doc/qtcreator/src/user-interface/creator-projects-view.qdoc @@ -108,7 +108,7 @@ \li Close all files in a project. \li Close the selected project or all projects except the selected one. By default, this closes all files in the projects. To keep - them open, deselect the \preferences > \uicontrol {Build & Run} > + them open, clear the \preferences > \uicontrol {Build & Run} > \uicontrol General > \uicontrol {Close source files along with project} check box. \endlist @@ -139,7 +139,7 @@ \endlist To stop synchronizing the position in the project tree with the file - currently opened in the editor, deselect \inlineimage icons/linkicon.png + currently opened in the editor, clear \inlineimage icons/linkicon.png (\uicontrol {Synchronize with Editor}). Some build systems support adding and removing files to a project in \QC diff --git a/doc/qtcreator/src/user-interface/creator-reference-output-views.qdoc b/doc/qtcreator/src/user-interface/creator-reference-output-views.qdoc index f53031965b4..20ed1b84184 100644 --- a/doc/qtcreator/src/user-interface/creator-reference-output-views.qdoc +++ b/doc/qtcreator/src/user-interface/creator-reference-output-views.qdoc @@ -57,7 +57,7 @@ or select \key F6 and \key Shift+F6. By default, a new build clears the \uicontrol Issues view. To keep - the issues from the previous build rounds, deselect \preferences > + the issues from the previous build rounds, clear \preferences > \uicontrol {Build & Run} > \uicontrol General > \uicontrol {Clear issues list on new build}. diff --git a/doc/qtcreator/src/vcs/creator-only/creator-vcs-clearcase.qdoc b/doc/qtcreator/src/vcs/creator-only/creator-vcs-clearcase.qdoc index 740eabe5a8b..64cd447d964 100644 --- a/doc/qtcreator/src/vcs/creator-only/creator-vcs-clearcase.qdoc +++ b/doc/qtcreator/src/vcs/creator-only/creator-vcs-clearcase.qdoc @@ -54,7 +54,7 @@ Unified Change Management (UCM) view, they are added to the change set of a UCM activity. By default, the activities are automatically assigned names. To disable this functionality, select \preferences > - \uicontrol {Version Control} > \uicontrol ClearCase, and then deselect the + \uicontrol {Version Control} > \uicontrol ClearCase, and then clear the \uicontrol {Auto assign activity names} check box. To automatically check out files when you edit them, select the diff --git a/doc/qtcreator/src/vcs/creator-only/creator-vcs-perforce.qdoc b/doc/qtcreator/src/vcs/creator-only/creator-vcs-perforce.qdoc index 6c9c93ff51d..c32038620aa 100644 --- a/doc/qtcreator/src/vcs/creator-only/creator-vcs-perforce.qdoc +++ b/doc/qtcreator/src/vcs/creator-only/creator-vcs-perforce.qdoc @@ -64,7 +64,7 @@ within the client workspace. By default, files are automatically opened for editing. To disable this feature, select \preferences > \uicontrol {Version Control} > \uicontrol Perforce, - and then deselect the \uicontrol {Automatically open files when editing} + and then clear the \uicontrol {Automatically open files when editing} check box. To list files that are open for editing, select \uicontrol Tools > diff --git a/doc/qtcreatordev/src/qtcreator-ui-text.qdoc b/doc/qtcreatordev/src/qtcreator-ui-text.qdoc index 43a61dc1505..987cd4ce735 100644 --- a/doc/qtcreatordev/src/qtcreator-ui-text.qdoc +++ b/doc/qtcreatordev/src/qtcreator-ui-text.qdoc @@ -145,7 +145,7 @@ \row \li Check box - \uicontrol {Clean whitespace} \li Removes trailing whitespace upon saving. - \li Enable this check box to remove trailing whitespace upon saving. + \li Select this check box to remove trailing whitespace upon saving. \row \li Combo box - \uicontrol Size \li The font size used in the terminal (in points). diff --git a/doc/qtdesignstudio/examples/doc/animationTutorial.qdoc b/doc/qtdesignstudio/examples/doc/animationTutorial.qdoc index 4f801cd5151..ffe01a36d89 100644 --- a/doc/qtdesignstudio/examples/doc/animationTutorial.qdoc +++ b/doc/qtdesignstudio/examples/doc/animationTutorial.qdoc @@ -202,7 +202,7 @@ select \imageplus . \li In the \uicontrol {Property Type} field, enter \e {Item}. - This field is a drop-down list, but you can also type text. + This field is a drop-down list, but you can also enter text. \li In the \uicontrol {Property Value} field, enter \e {null}. \endlist \image animation-tutorial-property.png diff --git a/doc/qtdesignstudio/examples/doc/coffeemachine.qdoc b/doc/qtdesignstudio/examples/doc/coffeemachine.qdoc index ed007b0effd..084a55283d8 100644 --- a/doc/qtdesignstudio/examples/doc/coffeemachine.qdoc +++ b/doc/qtdesignstudio/examples/doc/coffeemachine.qdoc @@ -116,7 +116,7 @@ \image coffee-machine-properties.png - When we deselect the record button to stop recording the timeline, the + When we clear the record button to stop recording the timeline, the new timeline appears in the view. For more information about using the timeline, see diff --git a/doc/qtdesignstudio/examples/doc/ebikedesign.qdoc b/doc/qtdesignstudio/examples/doc/ebikedesign.qdoc index f379d4c9ad3..5765790007f 100644 --- a/doc/qtdesignstudio/examples/doc/ebikedesign.qdoc +++ b/doc/qtdesignstudio/examples/doc/ebikedesign.qdoc @@ -54,7 +54,7 @@ to return to the Standard screen. Finally, at frame 4000, we set the X coordinate to -19 to return to the Trip screen. - When we deselect the record button to stop recording the timeline, the + When we clear the record button to stop recording the timeline, the new timeline appears in the view. When we select \e tripScreen in the \uicontrol Navigator, we can see the diff --git a/doc/qtdesignstudio/examples/doc/loginui4.qdoc b/doc/qtdesignstudio/examples/doc/loginui4.qdoc index 6393029fb2c..40926e9e1fd 100644 --- a/doc/qtdesignstudio/examples/doc/loginui4.qdoc +++ b/doc/qtdesignstudio/examples/doc/loginui4.qdoc @@ -158,7 +158,7 @@ (\uicontrol {Per Property Recording}) button for the \uicontrol opacity property of \e repeatPassword to start recording property changes. - \li In \uicontrol Visibility > \uicontrol Opacity, type \e 0 to hide the button, and press + \li In \uicontrol Visibility > \uicontrol Opacity, enter \e 0 to hide the button, and press \key Enter to save the value. \li Move the playhead to frame \e 1000 and change the opacity value to \e 1 to show the button. diff --git a/doc/qtdesignstudio/examples/doc/progressbar.qdoc b/doc/qtdesignstudio/examples/doc/progressbar.qdoc index b99780eb32b..33e386f329f 100644 --- a/doc/qtdesignstudio/examples/doc/progressbar.qdoc +++ b/doc/qtdesignstudio/examples/doc/progressbar.qdoc @@ -23,7 +23,7 @@ \l {progress-bar-control}{Progress Bar} component available in \uicontrol Components > \uicontrol {Qt Quick Controls}. - In the \uicontrol Design mode, we drag-and-drop a \uicontrol Rectangle from + In the \uicontrol Design mode, we drag a \uicontrol Rectangle from \uicontrol Components > \uicontrol {Default Components} > \uicontrol Basic to the \l {2D} view and modify its size to create the background for the progress bar. We change its ID to \e pb_back in @@ -31,12 +31,12 @@ We want to be able to control the background rectangle and the text label that was added by the project wizard, so we will use an \uicontrol Item - component for that. We drag-and-drop the Item from \uicontrol Components > + component for that. We drag the Item from \uicontrol Components > \uicontrol {Default Components} > \uicontrol Basic to the \uicontrol {2D} view and change its ID to \e root in \uicontrol Properties. - To make the background and text children of the Item, we drag-and-drop them + To make the background and text children of the Item, we drag them to the Item in \l Navigator. This enables us to use the anchor buttons in \uicontrol Properties > \uicontrol Layout to anchor them to their parent. We anchor the background to its parent on all edges, with a 30-pixel @@ -45,7 +45,7 @@ \image progressbar-rectangle.png "Progress bar background in the 2D view" - We now drag-and-drop another rectangle on top of the background rectangle in + We now drag another rectangle on top of the background rectangle in \uicontrol Navigator and change its ID to \e pb_front in \uicontrol Properties. We then anchor the left, top, and bottom of the indicator to its parent with @@ -125,7 +125,7 @@ We want the progress bar to be reusable, so we'll move it to a separate component file. To make sure that the component will contain the timeline, we select \uicontrol {Filter Tree} in \uicontrol Navigator and then - deselect the \uicontrol {Show Only Visible Items} check box to show the + clear the \uicontrol {Show Only Visible Items} check box to show the timeline component in \uicontrol Navigator. We then move the timeline component to \e root to have it moved as a part of the root component. diff --git a/doc/qtdesignstudio/examples/doc/sidemenu.qdoc b/doc/qtdesignstudio/examples/doc/sidemenu.qdoc index 3f1a9070791..7a9b94fb66d 100644 --- a/doc/qtdesignstudio/examples/doc/sidemenu.qdoc +++ b/doc/qtdesignstudio/examples/doc/sidemenu.qdoc @@ -13,7 +13,7 @@ \e {Side Menu} displays a menu bar and a side menu that slides open when users click the menu icon. The appearance of the menu bar buttons changes - when users hover the cursor over them or select them. + when users hover over them or select them. Each button opens an image file. The side menu can be used to apply \l {2D effects}{graphical effects}, such as hue, saturation, @@ -82,7 +82,7 @@ We construct the menu bar in the \e {MainFile.ui.qml} file using the \l {2D} view. The CustomButton component is listed in \uicontrol Components > \uicontrol {My Components}. - We drag-and-drop several instances of the component to \uicontrol Navigator + We drag several instances of the component to \uicontrol Navigator or the \uicontrol {2D} view and enclose them in a \uicontrol {Row Layout} component instance to lay them out as a menu bar. @@ -90,8 +90,8 @@ We can change the properties of each CustomButton instance separately in the \uicontrol Properties view. We want only one of the menu bar buttons - to be checked at any time, so that checking another button automatically - unchecks the previously checked one. Therefore, we set the + to be selected at any time, so that selecting another button automatically + clears the previously selected one. Therefore, we set the \l {AbstractButton::}{autoExclusive} property to \c true for all button instances. @@ -104,7 +104,7 @@ \section1 Creating a side menu We can now continue to create a side menu that slides open when users - click the burger menu. We drag-and-drop a \l Text component from + click the burger menu. We drag a \l Text component from \uicontrol Components > \uicontrol {Default Components} > \uicontrol Basic and a \l {slider-control}{Slider} component from \uicontrol {Qt Quick Controls} to \uicontrol Navigator to create separate @@ -209,7 +209,7 @@ in the \uicontrol Settings menu of the \uicontrol Value property in \uicontrol Properties > \uicontrol Slider. - We open the \e {EffectStack.qml} file, and drag-and-drop components from + We open the \e {EffectStack.qml} file, and drag components from \uicontrol Components > \uicontrol {Qt Quick Studio Effects} to \uicontrol Navigator to create the effect stack. diff --git a/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc b/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc index 34c09f1c8f4..15f68d90f2b 100644 --- a/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc +++ b/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc @@ -167,7 +167,7 @@ In our UI, we use connections and states to move between screens. First, we specify the application workflow in \e ApplicationFlow.qml. When the - file is open in the \uicontrol {2D} view, we drag-and-drop the components + file is open in the \uicontrol {2D} view, we drag the components that define the screens in the application from \uicontrol Components to \uicontrol Navigator or the \uicontrol {2D} view: \e StartScreen, \e SettingsScreen, \e PresetsScreen, and \e RunningScreen. diff --git a/doc/qtdesignstudio/examples/doc/webinardemo.qdoc b/doc/qtdesignstudio/examples/doc/webinardemo.qdoc index 31a1b04a8e9..8ab2d061eeb 100644 --- a/doc/qtdesignstudio/examples/doc/webinardemo.qdoc +++ b/doc/qtdesignstudio/examples/doc/webinardemo.qdoc @@ -149,7 +149,7 @@ the UI we will create. We use the imported components to create the UI in the \e {MainApp.ui.qml} file. The imported components are listed in \uicontrol Components > \uicontrol {My Components}, - and we can drag-and-drop them to the \l {2D} view. + and we can drag them to the \l {2D} view. \image webinardemo-mainappui.png "Main app UI in Design mode" diff --git a/doc/qtdesignstudio/src/components/qtquick-animation-types.qdoc b/doc/qtdesignstudio/src/components/qtquick-animation-types.qdoc index 86d575515e7..8c982577cfe 100644 --- a/doc/qtdesignstudio/src/components/qtquick-animation-types.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-animation-types.qdoc @@ -13,7 +13,7 @@ that is to be animated, and apply the animation depending on the type of behavior that is required. - You can drag-and-drop animation components from + You can drag animation components from \uicontrol Components > \uicontrol {Default Components} > \uicontrol Animation to the \l Navigator or \l {2D} view to create instances of them. @@ -132,7 +132,7 @@ You can create several animations that can run in parallel or in sequence. To manage a group of animations that will play at the same time, create an - instance of a \uicontrol {Parallel Animation} component and drag-and-drop + instance of a \uicontrol {Parallel Animation} component and drag the other animations to it. To play the animations in the specified order, one after the other, create an instance of a \uicontrol {Sequential Animation} instead. diff --git a/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc b/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc index 476d3215a27..8fb2f04207b 100644 --- a/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc @@ -33,7 +33,7 @@ (\uicontrol W) and height (\uicontrol H) of the button in \l Properties. - \li Drag-and-drop a \uicontrol Rectangle from \uicontrol Components > + \li Drag a \uicontrol Rectangle from \uicontrol Components > \uicontrol {Default Components} > \uicontrol Basic to the component in \uicontrol Navigator. This creates a nested component where the Item is the parent of the Rectangle. Components are positioned @@ -57,7 +57,7 @@ \endlist - \li Drag-and-drop a \uicontrol {Text} component to the Item in + \li Drag a \uicontrol {Text} component to the Item in \uicontrol Navigator. \li In the \uicontrol Properties view, edit the properties of the @@ -150,11 +150,11 @@ \l Properties view to match the size of the images you plan to use. This specifies the initial size of the button component. - \li Drag-and-drop two \uicontrol {Border Image} components from + \li Drag two \uicontrol {Border Image} components from \uicontrol Components > \uicontrol {Default Components} > \uicontrol Basic to the root component in \uicontrol Navigator. - \li Drag-and-drop a \uicontrol Text component to the root component. - \li Drag-and-drop a \uicontrol {Mouse Area} to the root component. + \li Drag a \uicontrol Text component to the root component. + \li Drag a \uicontrol {Mouse Area} to the root component. \li Select a border image to edit the values of its properties: \list 1 \li In the \uicontrol Id field, enter an ID for the border @@ -238,7 +238,7 @@ When you work on other files in the project to create screens or other components for the UI, the button component appears in \uicontrol Components > \uicontrol {My Components}. - You can drag-and-drop it to the \uicontrol {2D} or + You can drag it to the \uicontrol {2D} or \uicontrol Navigator view to create button instances and modify the values of their properties to assign them useful IDs, change their appearance, and set the button text for each button instance, for example. diff --git a/doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc b/doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc index f3b0a19f072..38021acba7d 100644 --- a/doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc @@ -16,7 +16,7 @@ To create component instances and edit their properties: \list 1 - \li Drag-and-drop components from \uicontrol Components (1) to the + \li Drag components from \uicontrol Components (1) to the \l Navigator (2), \l {2D} (3), or \l {3D} view (4). This creates instances of the components in the current component file. diff --git a/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc b/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc index 5fe197502b1..757271b079f 100644 --- a/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc @@ -33,7 +33,7 @@ capital letter. \li Click \uicontrol Design to open the file in the \uicontrol {2D} view. - \li Drag-and-drop a component from \uicontrol Components to + \li Drag a component from \uicontrol Components to \uicontrol Navigator or the \uicontrol {2D} view. \li Edit component properties in the \uicontrol Properties view. The available properties depend on the component type. You can diff --git a/doc/qtdesignstudio/src/components/qtquick-controls.qdoc b/doc/qtdesignstudio/src/components/qtquick-controls.qdoc index 85b8b98378e..2f89d55d34d 100644 --- a/doc/qtdesignstudio/src/components/qtquick-controls.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-controls.qdoc @@ -124,7 +124,7 @@ \section3 Flat buttons A flat button typically does not draw a background unless it is pressed or - checked. To create a flat button, select the \uicontrol Flat check box in + selected. To create a flat button, select the \uicontrol Flat check box in the \uicontrol Button section. The following image shows an example of a flat button: @@ -134,7 +134,7 @@ \section3 Icon buttons To create a button that contains an icon, use the wizard template to - \l{Creating Custom Controls}{create a custom button} and drag-and-drop + \l{Creating Custom Controls}{create a custom button} and drag the icon to the button background component. For an example of using the wizard template, see \l{Creating a Push Button}. diff --git a/doc/qtdesignstudio/src/components/qtquick-images.qdoc b/doc/qtdesignstudio/src/components/qtquick-images.qdoc index 989015bd17f..6528388f1ae 100644 --- a/doc/qtdesignstudio/src/components/qtquick-images.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-images.qdoc @@ -27,7 +27,7 @@ \image qtquick-designer-image-type.png "Image component in different views" - When you drag-and-drop an image file from \uicontrol Assets to \l Navigator + When you drag an image file from \uicontrol Assets to \l Navigator or the \l {2D} view, \QDS automatically creates an instance of the Image component for you with the path to the image file set as the value of the \uicontrol Source field in @@ -181,7 +181,7 @@ (\uicontrol Paused) check box. When the \uicontrol Cache check box is selected, every frame of the - animation is cached. Deselect the check box if you are playing a long + animation is cached. Clear the check box if you are playing a long or large animation and you want to conserve memory. If the image data comes from a sequential device (such as a socket), diff --git a/doc/qtdesignstudio/src/components/qtquick-pathview-editor.qdocinc b/doc/qtdesignstudio/src/components/qtquick-pathview-editor.qdocinc index dd50cf67986..e1f6bc305f2 100644 --- a/doc/qtdesignstudio/src/components/qtquick-pathview-editor.qdocinc +++ b/doc/qtdesignstudio/src/components/qtquick-pathview-editor.qdocinc @@ -26,7 +26,7 @@ By default, the path is closed, which means that its start and end points are identical. To create separate start and end points for it, right-click - an edit point to open a context menu, and deselect \uicontrol {Closed Path}. + an edit point to open a context menu, and clear \uicontrol {Closed Path}. To add intermediary points to a curve segment, select \uicontrol {Split Segment} in the context menu. diff --git a/doc/qtdesignstudio/src/components/qtquick-user-interaction-methods.qdoc b/doc/qtdesignstudio/src/components/qtquick-user-interaction-methods.qdoc index 1cdc002f086..e8844c2ab0d 100644 --- a/doc/qtdesignstudio/src/components/qtquick-user-interaction-methods.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-user-interaction-methods.qdoc @@ -79,7 +79,7 @@ pressed. Even though \uicontrol {Mouse Area} is an invisible component, it has a - \uicontrol Visible property. Deselect the \uicontrol Visible check box in + \uicontrol Visible property. Clear the \uicontrol Visible check box in the \uicontrol Visibility section to make the mouse area transparent to mouse events. diff --git a/doc/qtdesignstudio/src/overviews/qtquick-export.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-export.qdoc index bd01ba56d7b..2acddf9562e 100644 --- a/doc/qtdesignstudio/src/overviews/qtquick-export.qdoc +++ b/doc/qtdesignstudio/src/overviews/qtquick-export.qdoc @@ -45,7 +45,7 @@ \list 1 \li In the \uicontrol {Export path} field, specify the path where the metadata file and assets are exported. - \li Deselect the \uicontrol {Export assets} check box to disable + \li Clear the \uicontrol {Export assets} check box to disable exporting assets and only generate the metadata file. \li Select the \uicontrol {Export components separately} check box to generate separate metadata files for each component. diff --git a/doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc index 7273f55ce50..9d8adb43bea 100644 --- a/doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc +++ b/doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc @@ -30,7 +30,7 @@ set of predefined properties, some of which control things that are visible to users, while others are used behind the scene. - You drag-and-drop the preset components from the \uicontrol Components view + You drag the preset components from the \uicontrol Components view to the \l {2D}, \l {3D}, or \l Navigator view to create instances of them. You then change the instances to your liking by modifying their properties in the \l Properties view. The application code is diff --git a/doc/qtdesignstudio/src/qtdesignstudio-importing-2d.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-importing-2d.qdoc index e187994d03c..4616d7bb948 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-importing-2d.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-importing-2d.qdoc @@ -11,12 +11,12 @@ You can import 2D assets, such as images, fonts, and sound files, to \QDS to use them in your projects. - To import an asset, drag-and-drop the external file containing the asset from, + To import an asset, drag the external file containing the asset from, for example, File Explorer on Windows, to the \uicontrol {2D}, \uicontrol Navigator, or \uicontrol {Code} view. Alternatively, select \uicontrol Assets > \imageplus and follow the instructions in the \uicontrol {Asset Import} dialog. You can - also multiselect several external asset files to drag-and-drop them to + also multiselect several external asset files to drag them to \QDS simultaneously. The imported images will appear in \uicontrol Assets. @@ -26,7 +26,7 @@ external font file to the \uicontrol {2D} view, it will be added to your project as a text component. Other imported assets, such as sound files, will only appear in \uicontrol Assets, and you can then - drag-and-drop them to a suitable view. + drag them to a suitable view. \section1 Importing designs from other design tools @@ -74,9 +74,9 @@ the image files to. \li Select the \uicontrol {Create sub directory} check box to import the assets in a sub directory inside \uicontrol {Export Paths}. - \li Deselect the \uicontrol {Import assets} check box if you only want + \li Clear the \uicontrol {Import assets} check box if you only want to create QML files. - \li Deselect the \uicontrol {Generate QML} check box if you only + \li Clear the \uicontrol {Generate QML} check box if you only want to import assets. \li Select the \uicontrol {Merge QML} check box if you have imported the assets before and want to merge the changes into existing QML files @@ -93,7 +93,7 @@ The components that you specified in the design tool are displayed in \uicontrol Components > \uicontrol {My Components} as well as in the \uicontrol Projects view as separate QML files. To use them, - drag-and-drop them from \uicontrol Components to the \uicontrol {2D} or + drag them from \uicontrol Components to the \uicontrol {2D} or \l Navigator view. If asset importer conflicts, warnings, and errors are displayed in the diff --git a/doc/qtdesignstudio/src/qtdesignstudio-simulink.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-simulink.qdoc index 67bbc421fb8..9faf43ad0e1 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-simulink.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-simulink.qdoc @@ -111,7 +111,7 @@ Double-click the \uicontrol {Qt/SML Send} or \uicontrol {Qt/QML Receive} block in Simulink to specify a property name. A pop-up for \uicontrol - {Block Parameters} appears. Type the name of the property in the \uicontrol + {Block Parameters} appears. Enter the name of the property in the \uicontrol {Qt Signal/Property Name} field and click \uicontrol OK. The name, for example speedProp, needs to match a \uicontrol signal or a \uicontrol property in \QDS. @@ -165,7 +165,7 @@ bind the root item property. Select the \imageactionicon (\uicontrol Actions) menu next to a property, and then select \uicontrol {Set Binding}. In the \uicontrol {Binding Editor}, select the - text field and type in \c {.}, for example + text field and enter \c {.}, for example \c rectangle.speedProp. For more information, see \l {Setting bindings}. \image studio-binding-editor.png "The Binding Editor window" diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc index 40e79f25084..9bb20c57634 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc @@ -268,7 +268,7 @@ component now appears in \uicontrol {My 3D Components}. \image exporting-from-qt3ds/33-see-qml-stream-component-in-myqmlcomponents.png "QML stream in My QML Components" - \li Drag-and-drop the QML stream component to MyOwnCluster in \uicontrol + \li Drag the QML stream component to MyOwnCluster in \uicontrol Navigator. \image exporting-from-qt3ds/34-drag-to-myowncluster-in-navigator.png "Drag the QML stream component to MyOwnCluster" diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-effects.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-effects.qdoc index 08f4bd5f0c7..4790d623301 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-effects.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-effects.qdoc @@ -9,7 +9,7 @@ \title 3D effects \QDS provides a set of 3D effects, which are visible in the \l {2D} view. - To apply a visual effect to a scene, drag-and-drop an effect from + To apply a visual effect to a scene, drag an effect from \uicontrol Components > \uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D Effects} to a \uicontrol SceneEnvironment component in \l Navigator. diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-group.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-group.qdoc index f335365f11a..2559de2982d 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-group.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-group.qdoc @@ -14,7 +14,7 @@ the \l Properties view simultaneously. To add a \uicontrol Group component - to your scene, drag-and-drop it from \uicontrol Components > + to your scene, drag it from \uicontrol Components > \uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D} to the \l {3D} view or to \l Navigator > \uicontrol View3D > \uicontrol {Scene Environment} > \uicontrol Scene. diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-instancing.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-instancing.qdoc index 940b5f007ec..759eb9ee1ed 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-instancing.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-instancing.qdoc @@ -47,7 +47,7 @@ \l{https://doc.qt.io/qt/qml-qtquick3d-fileinstancing.html}{FileInstancing} QML type. - To use the \uicontrol Instancing component, drag-and-drop it from + To use the \uicontrol Instancing component, drag it from \uicontrol Components to \uicontrol Scene in \uicontrol Navigator. \section2 Instancing properties @@ -84,11 +84,11 @@ To build an instance table: \list 1 - \li Drag-and-drop an \uicontrol {Instance List} component from + \li Drag an \uicontrol {Instance List} component from \uicontrol Components > \uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D} to \uicontrol Scene in \uicontrol Navigator. - \li Drag-and-drop \uicontrol {Instance List Entry} components to the + \li Drag \uicontrol {Instance List Entry} components to the \uicontrol {Instance List} component to create list items. \image studio-3d-instancing-instance-list.png "Instance List and Instance Entries in Navigator" diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials.qdoc index 522084183d7..9125fb9ecf7 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-materials.qdoc @@ -23,7 +23,7 @@ \uicontrol {Target Qt Version} when \l {Creating projects}{creating your project}. To apply a 3D material to a component, you should first delete the default - material and then drag-and-drop a new material from + material and then drag a new material from \uicontrol Components > \uicontrol {Qt Quick 3D Materials} > \uicontrol {Qt Quick 3D Materials} to a model component in \l Navigator. The materials you add to the model are listed in the model component's diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-morph-target.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-morph-target.qdoc index dc1f9206fa2..bd2b715dd8f 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-morph-target.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-morph-target.qdoc @@ -18,7 +18,7 @@ The normal workflow is to use an external content creation tool to create a mesh, which also contains morph targets, and import it to \QDS. - To add a morph target for a model in \QDS, drag-and-drop a + To add a morph target for a model in \QDS, drag a \uicontrol {Morph Target} component from \uicontrol Components > \uicontrol {Qt Quick 3D} > \uicontrol {Qt Quick 3D} to \uicontrol Scene in \l Navigator. Then select the model in \uicontrol Navigator, and in diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc index ded9fe4e52e..14cc442158e 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc @@ -386,7 +386,7 @@ when you select it again. To temporarily stop the simulation, select \uicontrol Paused. Particles - are not destroyed, and when you deselect the check box, the simulation + are not destroyed, and when you clear the check box, the simulation resumes from the point where you paused it. Select \uicontrol Logging to collect particle system statistics, such as @@ -1131,7 +1131,7 @@ them in \uicontrol Particles. Select \imageplus to add logical particles to the list. - Deselect \uicontrol Enabled to turn the affector off. Usually, this + Clear \uicontrol Enabled to turn the affector off. Usually, this property is used in code to conditionally turn affectors off and on. */ diff --git a/doc/qtdesignstudio/src/qtquickdesigner-components/qtdesignstudio-logic-helpers.qdoc b/doc/qtdesignstudio/src/qtquickdesigner-components/qtdesignstudio-logic-helpers.qdoc index 3fb609d1a54..e0b24f21772 100644 --- a/doc/qtdesignstudio/src/qtquickdesigner-components/qtdesignstudio-logic-helpers.qdoc +++ b/doc/qtdesignstudio/src/qtquickdesigner-components/qtdesignstudio-logic-helpers.qdoc @@ -22,7 +22,7 @@ Logic helpers are invisible components that you can use in connection with controls, such as a \l {slider-control}{Slider} or \l {Check Box}. - To use a logic helper, drag-and-drop it from \uicontrol Components > + To use a logic helper, drag it from \uicontrol Components > \uicontrol {Qt Quick Studio Logic Helper} to \l Navigator. If you cannot find the logic helpers in \uicontrol {Components}, you need to add the \uicontrol {Qt Quick Studio Logic Helper} module to your project, @@ -42,7 +42,7 @@ The output is evaluated as \c true if both inputs are \c true. For example, we could use the checked state of two check boxes to determine - the checked state of a third one. First, we drag-and-drop three instances of + the checked state of a third one. First, we drag three instances of the \uicontrol {Check Box} components and one instance of the \uicontrol {And Operator} component to \uicontrol Navigator (1). Then, we select the \uicontrol {And Operator} component instance (2) and set its @@ -81,7 +81,7 @@ condition is not met. For example, we could specify that if one check box is checked, another - one cannot be checked. First, we drag-and-drop two instances of the + one cannot be checked. First, we drag two instances of the \uicontrol {Check Box} component and one instance of the \uicontrol {Not Operator} component to \uicontrol Navigator. Then, we select the \uicontrol {Not Operator} component instance and set its properties in @@ -97,7 +97,7 @@ \image studio-logic-helper-not-check-box.png "Check box checked property bound to NOT operator output" - When we preview our UI, the second check box is initially checked. However, + When we preview our UI, the second check box is initially selected. However, when we select the first check box, the second one is automatically cleared. \image studio-logic-helper-not-operator.gif "Previewing two check boxes bound with a NOT operator" @@ -110,7 +110,7 @@ a slider and checkbox. Typically, it is used to bind a backend value to a control, such as a slider. - For example, to synchronize the values of two sliders, we drag-and-drop two + For example, to synchronize the values of two sliders, we drag two instances of the \uicontrol Slider component and one instance of the \uicontrol {Bi Direct. Binding} component to the same parent component in \uicontrol Navigator. Then, we select the bi-directional binding instance @@ -140,7 +140,7 @@ the string. For example, to use a \l Text component to display the value of a - slider, we drag-and-drop \uicontrol Text, \uicontrol Slider, and + slider, we drag \uicontrol Text, \uicontrol Slider, and \uicontrol {String Mapper} components to the same parent component. Then, we select the \uicontrol {String Mapper} instance in \uicontrol Navigator to display its properties in \uicontrol Properties. There we bind the value @@ -175,7 +175,7 @@ For example, to restrict the maximum value of a slider to 0.60, regardless of the maximum value set in the slider properties, - we drag-and-drop a \uicontrol {Min Max Mapper} to our example + we drag a \uicontrol {Min Max Mapper} to our example above. We select it to display its properties in \uicontrol Properties. Then, we bind the value of the \uicontrol Input property of the mapper to the value of the \c value property of the slider and set the value diff --git a/doc/qtdesignstudio/src/views/qtquick-curve-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-curve-editor.qdoc index 0b77f83f900..3f2e4288942 100644 --- a/doc/qtdesignstudio/src/views/qtquick-curve-editor.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-curve-editor.qdoc @@ -47,11 +47,11 @@ in \l Navigator, you can select \imagelockon to unlock it. You can also lock individual easing curves for editing. - To lock an animation curve, hover the mouse over the property in the list, + To lock an animation curve, hover over the property in the list, and then select \imagelockoff . - To pin an animation curve, hover the mouse over the property in the list, + To pin an animation curve, hover over the property in the list, and then select \imagepin . diff --git a/doc/qtdesignstudio/src/views/qtquick-properties.qdoc b/doc/qtdesignstudio/src/views/qtquick-properties.qdoc index 1a64e5a0fed..a6a2d7f8a7e 100644 --- a/doc/qtdesignstudio/src/views/qtquick-properties.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-properties.qdoc @@ -125,7 +125,7 @@ \image qtquick-properties-visibility.png "Visibility properties" - Deselect the \uicontrol Visible check box to hide a component and all + Clear the \uicontrol Visible check box to hide a component and all its child components, unless they have explicitly been set to be visible. This might have surprise effects when using property bindings. In such cases, it may be better to use the \uicontrol Opacity property instead. diff --git a/doc/qtdesignstudio/src/views/qtquick-states.qdoc b/doc/qtdesignstudio/src/views/qtquick-states.qdoc index a16b5a7ce0f..be86ee511ec 100644 --- a/doc/qtdesignstudio/src/views/qtquick-states.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-states.qdoc @@ -147,7 +147,7 @@ not part of a view. \li In \uicontrol States, select the \uicontrol + symbol to create a new state and give it a name. For example, \c Normal. - \li In \l Properties (2), deselect the \uicontrol Visibility + \li In \l Properties (2), clear the \uicontrol Visibility check box or set \uicontrol Opacity to 0 for each component that is not needed in this view. If you specify the setting for the parent component, all child components inherit it and are also From 4a191834f87975f7c56c6be7cc6862b7cd073eb4 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 9 Jan 2025 00:02:08 +0100 Subject: [PATCH 05/14] Sqlite: Fix warning Change-Id: I15e7459675908f935df7baf01c3707c7b56dde0c Reviewed-by: Tim Jenssen --- src/libs/sqlite/sqlitebasestatement.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/libs/sqlite/sqlitebasestatement.h b/src/libs/sqlite/sqlitebasestatement.h index 306f8bada3d..b11c6b04b53 100644 --- a/src/libs/sqlite/sqlitebasestatement.h +++ b/src/libs/sqlite/sqlitebasestatement.h @@ -411,10 +411,6 @@ public: BaseSqliteResultRange(BaseSqliteResultRange &) = delete; BaseSqliteResultRange &operator=(BaseSqliteResultRange &) = delete; - - BaseSqliteResultRange(BaseSqliteResultRange &&other) - : m_statement{std::move(other.resetter)} - {} BaseSqliteResultRange &operator=(BaseSqliteResultRange &&) = delete; iterator begin() & { return iterator{m_statement}; } From f1f43a4e0d17afffe67f9ca82a40d71c0cf3c730 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 31 Dec 2024 14:20:15 +0100 Subject: [PATCH 06/14] QmlDesigner: Improve tracing printing code The compiler seem not to determine if the code is side effect free. So it is even created as the nano tracing is disabled. Hopefully that simplification is enough. Change-Id: If6c5f2aac67df6e7c22345fc10f363be0f49eb42 Reviewed-by: Thomas Hartmann --- src/libs/sqlite/sqliteids.h | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/libs/sqlite/sqliteids.h b/src/libs/sqlite/sqliteids.h index 70bf23caafa..ccdb91414c2 100644 --- a/src/libs/sqlite/sqliteids.h +++ b/src/libs/sqlite/sqliteids.h @@ -77,10 +77,7 @@ public: template friend void convertToString(String &string, BasicId id) { - if (id.isNull()) - NanotraceHR::convertToString(string, "invalid null"); - else - NanotraceHR::convertToString(string, id.internalId()); + NanotraceHR::convertToString(string, id.id); } friend bool compareId(BasicId first, BasicId second) { return first.id == second.id; } @@ -146,8 +143,10 @@ public: template friend void convertToString(String &string, CompoundBasicId id) { - convertToString(string, id.mainId()); - convertToString(string, id.contextId()); + int mainId = id; + int contextId = id >> 32; + convertToString(string, mainId); + convertToString(string, contextId); } friend bool compareId(CompoundBasicId first, CompoundBasicId second) From 2ae3ed203bbf67057d419bee7a81456dbed084f2 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 24 Dec 2024 09:06:59 +0100 Subject: [PATCH 07/14] QmlDesigner: Catch exceptions for project storage updating An exception is a sign, that the data is not consistent. So we stop updating and wait for updated data. Change-Id: I1a4e796f585e1f3206c04779618413a9a6ab1af5 Reviewed-by: Thomas Hartmann --- .../projectstorage/directorypathcompressor.h | 32 +++++++++++++++---- .../projectstoragepathwatcher.h | 18 ++++------- .../qmldesigner/qmldesignerprojectmanager.cpp | 23 +++++++------ .../directorypathcompressor-test.cpp | 20 +++++++++--- 4 files changed, 62 insertions(+), 31 deletions(-) diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/directorypathcompressor.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/directorypathcompressor.h index b3cf1b0f755..a13debc8326 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/directorypathcompressor.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/directorypathcompressor.h @@ -15,12 +15,12 @@ namespace QmlDesigner { template -class DirectoryPathCompressor +class DirectoryPathCompressor final { public: DirectoryPathCompressor() { m_timer.setSingleShot(true); } - virtual ~DirectoryPathCompressor() = default; + ~DirectoryPathCompressor() = default; void addSourceContextId(SourceContextId sourceContextId) { @@ -34,12 +34,18 @@ public: restartTimer(); } - SourceContextIds takeSourceContextIds() { return std::move(m_sourceContextIds); } + const SourceContextIds &sourceContextIds() { return m_sourceContextIds; } - virtual void setCallback(std::function &&callback) + virtual void setCallback(std::function &&callback) { - QObject::connect(&m_timer, &Timer::timeout, [this, callback = std::move(callback)] { - callback(takeSourceContextIds()); + if (connection) + QObject::disconnect(connection); + connection = QObject::connect(&m_timer, &Timer::timeout, [this, callback = std::move(callback)] { + try { + callback(m_sourceContextIds); + m_sourceContextIds.clear(); + } catch (const std::exception &) { + } }); } @@ -53,8 +59,22 @@ public: return m_timer; } +private: + struct ConnectionGuard + { + ~ConnectionGuard() + { + if (connection) + QObject::disconnect(connection); + } + + QMetaObject::Connection &connection; + }; + private: SourceContextIds m_sourceContextIds; + QMetaObject::Connection connection; + ConnectionGuard connectionGuard{connection}; Timer m_timer; }; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcher.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcher.h index 0fe9040c4d4..d2b3a2535e1 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcher.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcher.h @@ -49,14 +49,10 @@ public: &FileSystemWatcher::directoryChanged, [&](const QString &path) { compressChangedDirectoryPath(path); }); - m_directoryPathCompressor.setCallback([&](QmlDesigner::SourceContextIds &&sourceContextIds) { - addChangedPathForFilePath(std::move(sourceContextIds)); - }); - } - - ~ProjectStoragePathWatcher() - { - m_directoryPathCompressor.setCallback([&](SourceContextIds &&) {}); + m_directoryPathCompressor.setCallback( + [&](const QmlDesigner::SourceContextIds &sourceContextIds) { + addChangedPathForFilePath(sourceContextIds); + }); } void updateIdPaths(const std::vector &idPaths) override @@ -324,7 +320,7 @@ public: m_pathCache.sourceContextId(Utils::PathString{path})); } - WatcherEntries watchedEntriesForPaths(QmlDesigner::SourceContextIds &&sourceContextIds) + WatcherEntries watchedEntriesForPaths(const QmlDesigner::SourceContextIds &sourceContextIds) { WatcherEntries foundEntries; foundEntries.reserve(m_watchedEntries.size()); @@ -375,10 +371,10 @@ public: return idPaths; } - void addChangedPathForFilePath(SourceContextIds &&sourceContextIds) + void addChangedPathForFilePath(const SourceContextIds &sourceContextIds) { if (m_notifier) { - WatcherEntries foundEntries = watchedEntriesForPaths(std::move(sourceContextIds)); + WatcherEntries foundEntries = watchedEntriesForPaths(sourceContextIds); SourceIds watchedSourceIds = watchedPaths(foundEntries); diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp index faf59f62c77..d3663cc4cfd 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp @@ -605,16 +605,19 @@ void QmlDesignerProjectManager::update() if (!m_projectData || !m_projectData->projectStorageData) return; - if constexpr (isUsingQmlDesignerLite()) { - m_projectData->projectStorageData->updater.update({directoriesForLiteDesigner(), - qmlTypesForLiteDesigner(), - propertyEditorResourcesPath(), - {qtCreatorItemLibraryPath()}}); - } else { - m_projectData->projectStorageData->updater.update({directories(m_projectData->activeTarget), - qmlTypes(m_projectData->activeTarget), - propertyEditorResourcesPath(), - {qtCreatorItemLibraryPath()}}); + try { + if constexpr (isUsingQmlDesignerLite()) { + m_projectData->projectStorageData->updater.update({directoriesForLiteDesigner(), + qmlTypesForLiteDesigner(), + propertyEditorResourcesPath(), + {qtCreatorItemLibraryPath()}}); + } else { + m_projectData->projectStorageData->updater.update({directories(m_projectData->activeTarget), + qmlTypes(m_projectData->activeTarget), + propertyEditorResourcesPath(), + {qtCreatorItemLibraryPath()}}); + } + } catch (const std::exception &) { } } diff --git a/tests/unit/tests/unittests/projectstorage/directorypathcompressor-test.cpp b/tests/unit/tests/unittests/projectstorage/directorypathcompressor-test.cpp index d86e2d28287..44ef11cbe4b 100644 --- a/tests/unit/tests/unittests/projectstorage/directorypathcompressor-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/directorypathcompressor-test.cpp @@ -8,6 +8,8 @@ #include +#include + namespace { using QmlDesigner::SourceContextId; @@ -30,16 +32,26 @@ TEST_F(DirectoryPathCompressor, add_file_path) { compressor.addSourceContextId(sourceContextId1); - ASSERT_THAT(compressor.takeSourceContextIds(), ElementsAre(sourceContextId1)); + ASSERT_THAT(compressor.sourceContextIds(), ElementsAre(sourceContextId1)); } -TEST_F(DirectoryPathCompressor, no_file_paths_afer_taken_them) +TEST_F(DirectoryPathCompressor, clear__after_calling_callback) { compressor.addSourceContextId(sourceContextId1); - compressor.takeSourceContextIds(); + compressor.timer().emitTimoutIfStarted(); - ASSERT_THAT(compressor.takeSourceContextIds(), IsEmpty()); + ASSERT_THAT(compressor.sourceContextIds(), IsEmpty()); +} + +TEST_F(DirectoryPathCompressor, dont_clear_for_thrown_exception) +{ + compressor.addSourceContextId(sourceContextId1); + compressor.setCallback([](const SourceContextIds &) { throw std::exception{}; }); + + compressor.timer().emitTimoutIfStarted(); + + ASSERT_THAT(compressor.sourceContextIds(), ElementsAre(sourceContextId1)); } TEST_F(DirectoryPathCompressor, call_restart_timer_after_adding_path) From c40f27dca5c5b931cd9e55eb45cc7162514aacc8 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Thu, 2 Jan 2025 10:53:28 +0100 Subject: [PATCH 08/14] QmlDesigner: Add MapUtils::find The std::map hint optimization can remove remove one lookup. https://devblogs.microsoft.com/oldnewthing/20230522-00/?p=108226 Change-Id: Iaf85b1820fe4df2c802ee54a71cae866c8ce3908 Reviewed-by: Thomas Hartmann --- .../libs/qmldesignerutils/CMakeLists.txt | 1 + .../libs/qmldesignerutils/maputils.h | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/plugins/qmldesigner/libs/qmldesignerutils/maputils.h diff --git a/src/plugins/qmldesigner/libs/qmldesignerutils/CMakeLists.txt b/src/plugins/qmldesigner/libs/qmldesignerutils/CMakeLists.txt index 4759aba5e5c..2684cb3d65e 100644 --- a/src/plugins/qmldesigner/libs/qmldesignerutils/CMakeLists.txt +++ b/src/plugins/qmldesigner/libs/qmldesignerutils/CMakeLists.txt @@ -15,6 +15,7 @@ add_qtc_library(QmlDesignerUtils STATIC imageutils.cpp imageutils.h qmldesignerutils_global.h version.cpp version.h + maputils.h ) extend_qtc_library(QmlDesignerUtils diff --git a/src/plugins/qmldesigner/libs/qmldesignerutils/maputils.h b/src/plugins/qmldesigner/libs/qmldesignerutils/maputils.h new file mode 100644 index 00000000000..3ad56259f62 --- /dev/null +++ b/src/plugins/qmldesigner/libs/qmldesignerutils/maputils.h @@ -0,0 +1,29 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace QmlDesigner { + +namespace MapUtils { +template +auto find(std::map &map, const Key &key) +{ + struct FoundIterator + { + typename std::map::iterator iterator; + bool found = false; + + explicit operator bool() const { return found; } + }; + + auto iterator = map.lower_bound(key); + bool found = iterator != map.end() && iterator->first == key; + + return FoundIterator{iterator, found}; +} +} // namespace MapUtils + +} // namespace QmlDesigner From 80dc1c8c0221e13e827211bdfbdcb6acb71f79b1 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Thu, 19 Dec 2024 18:26:23 +0100 Subject: [PATCH 09/14] QmlDesigner: Run button fixes and improvements * Add progress and error state to SplitButton * Add UI elements to show packing, sending and starting state * Enable cancelling of the device upload process * Disable menu button when not in NotRunning state * Fix alias renaming issue Task-number: QDS-14305 Task-number: QDS-14344 Task-number: QDS-14417 Change-Id: I0a4cc1b1b836baba4d4db7f51eecaabef55d552e Reviewed-by: Thomas Hartmann Reviewed-by: Burak Hancerli --- share/qtcreator/qmldesigner/toolbar/Main.qml | 5 +- .../qmldesigner/toolbar/SplitButton.qml | 179 +++++++++++++++--- .../components/runmanager/runmanager.cpp | 108 ++++++++++- .../components/runmanager/runmanager.h | 18 +- .../components/toolbar/toolbarbackend.cpp | 23 +++ .../components/toolbar/toolbarbackend.h | 7 + 6 files changed, 304 insertions(+), 36 deletions(-) diff --git a/share/qtcreator/qmldesigner/toolbar/Main.qml b/share/qtcreator/qmldesigner/toolbar/Main.qml index 782b5aeb6f6..b5f3145e192 100644 --- a/share/qtcreator/qmldesigner/toolbar/Main.qml +++ b/share/qtcreator/qmldesigner/toolbar/Main.qml @@ -118,12 +118,15 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter anchors.left: home.right anchors.leftMargin: 10 - width: 160 + width: 170 runTarget: backend?.runTargetIndex runManagerState: backend?.runManagerState + runManagerProgress: backend?.runManagerProgress + runManagerError: backend?.runManagerError onClicked: backend.toggleRunning() + onCancelClicked: backend.cancelRunning() onRunTargetSelected: function(targetName) { backend.selectRunTarget(targetName) } onOpenRunTargets: backend.openDeviceManager() } diff --git a/share/qtcreator/qmldesigner/toolbar/SplitButton.qml b/share/qtcreator/qmldesigner/toolbar/SplitButton.qml index 47228249baf..5268bf05a2f 100644 --- a/share/qtcreator/qmldesigner/toolbar/SplitButton.qml +++ b/share/qtcreator/qmldesigner/toolbar/SplitButton.qml @@ -2,6 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick +import QtQuick.Shapes +import QtQuick.Layouts import QtQuick.Templates as T import StudioTheme as StudioTheme @@ -17,11 +19,15 @@ Item { property bool hover: primaryButton.hover || menuButton.hover signal clicked() + signal cancelClicked() signal runTargetSelected(targetId: string) signal openRunTargets() - property int runTarget: 0 + property int runTarget: 0 // index + property string runTargetName property int runManagerState: RunManager.NotRunning + property int runManagerProgress: 0 + property string runManagerError property int menuWidth: Math.max(160, root.width) @@ -33,6 +39,11 @@ Item { return runManagerModel.data(modelIndex, RunManagerModel.Enabled) } + function getRunTargetName(index: int): string { + let modelIndex = runManagerModel.index(index, 0) + return runManagerModel.data(modelIndex, "targetName") + } + ToolTipArea { id: toolTipArea anchors.fill: parent @@ -42,16 +53,85 @@ Item { } onRunTargetChanged: { + root.runTargetName = root.getRunTargetName(root.runTarget) primaryButton.enabled = root.isRunTargetEnabled(root.runTarget) } + component ProgressCircle: Shape { + id: shape + + property real from: 0 + property real to: 100 + property bool indeterminate: false + property real value: 0.5 + + property int strokeWidth: 4 + + property int radiusX: (shape.width - shape.strokeWidth) / 2 + property int radiusY: (shape.height - shape.strokeWidth) / 2 + + width: 20 + height: 20 + preferredRendererType: Shape.CurveRenderer + + ShapePath { + id: background + strokeColor: "gray" + strokeWidth: shape.strokeWidth + fillColor: "transparent" + capStyle: ShapePath.FlatCap + + PathAngleArc { + radiusX: shape.radiusX + radiusY: shape.radiusY + centerX: shape.width / 2 + centerY: shape.height / 2 + startAngle: 0 + sweepAngle: 360 + } + } + + ShapePath { + id: foreground + strokeColor: StudioTheme.Values.themeInteraction + strokeWidth: shape.strokeWidth + fillColor: "transparent" + capStyle: ShapePath.FlatCap + + PathAngleArc { + radiusX: shape.radiusX + radiusY: shape.radiusY + centerX: shape.width / 2 + centerY: shape.height / 2 + startAngle: -90 + sweepAngle: shape.indeterminate ? 90 : 360 * shape.value + } + } + // Indeterminate rotation animation + RotationAnimation on rotation { + loops: Animation.Infinite + from: 0 + to: 360 + running: shape.indeterminate + duration: 2000 + + onStopped: shape.rotation = 0 + } + } + Connections { target: runManagerModel + function onModelReset() { + root.runTargetName = root.getRunTargetName(root.runTarget) primaryButton.enabled = root.isRunTargetEnabled(root.runTarget) } } + readonly property bool showProgress: root.runManagerState === RunManager.Packing + || root.runManagerState === RunManager.Sending + || root.runManagerState === RunManager.Starting + Row { T.AbstractButton { id: primaryButton @@ -94,47 +174,95 @@ Item { width: primaryButton.width height: primaryButton.height - Row { - anchors.verticalCenter: parent.verticalCenter + RowLayout { anchors.left: parent.left + anchors.right: parent.right anchors.leftMargin: 8 + anchors.rightMargin: 8 + anchors.verticalCenter: parent.verticalCenter spacing: 8 - T.Label { + Item { + width: 20 height: primaryButton.height - font.family: StudioTheme.Constants.iconFont.family - font.pixelSize: primaryButton.style.baseIconFontSize - verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter - color: { - if (root.runManagerState === RunManager.NotRunning) - return primaryButton.press ? primaryButton.style.text.idle - : primaryButton.hover ? "#2eff68" // running green - : "#649a5d" // idle green - else - return primaryButton.press ? primaryButton.style.text.idle - : primaryButton.hover ? "#cc3c34" // recording red - : "#6a4242" // idle red + + ProgressCircle { + anchors.centerIn: parent + visible: root.showProgress + indeterminate: root.runManagerState === RunManager.Packing + || root.runManagerState === RunManager.Starting + value: root.runManagerProgress / 100 } - text: { - if (root.runManagerState === RunManager.NotRunning) - return StudioTheme.Constants.playOutline_medium - else - return StudioTheme.Constants.stop_medium + T.Label { + visible: !root.showProgress + height: primaryButton.height + + font.family: StudioTheme.Constants.iconFont.family + font.pixelSize: primaryButton.style.baseIconFontSize + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + color: { + if (root.runManagerState === RunManager.NotRunning) + return primaryButton.press ? primaryButton.style.text.idle + : primaryButton.hover ? "#2eff68" // running green + : "#649a5d" // idle green + else + return primaryButton.press ? primaryButton.style.text.idle + : primaryButton.hover ? "#cc3c34" // recording red + : "#6a4242" // idle red + } + + text: { + if (root.runManagerState === RunManager.NotRunning) + return StudioTheme.Constants.playOutline_medium + else + return StudioTheme.Constants.stop_medium + } } } T.Label { + Layout.fillWidth: true height: primaryButton.height color: primaryButton.enabled ? primaryButton.style.text.idle : primaryButton.style.text.disabled font.pixelSize: primaryButton.style.baseFontSize verticalAlignment: Text.AlignVCenter - horizontalAlignment: Text.AlignHCenter + horizontalAlignment: Text.AlignLeft + elide: Text.ElideMiddle text: { - let index = runManagerModel.index(root.runTarget, 0) - return runManagerModel.data(index, "targetName") + if (root.runManagerState === RunManager.Packing) + return qsTr("Packing") + else if (root.runManagerState === RunManager.Sending) + return qsTr("Sending") + else if (root.runManagerState === RunManager.Starting) + return qsTr("Starting") + else + return root.runTargetName + } + } + + T.Label { + visible: root.showProgress || root.runManagerError + height: primaryButton.height + + font.family: StudioTheme.Constants.iconFont.family + font.pixelSize: StudioTheme.Values.mediumFontSize + verticalAlignment: Text.AlignVCenter + horizontalAlignment: Text.AlignHCenter + + color: root.runManagerError ? StudioTheme.Values.themeError + : primaryButton.style.text.idle + text: root.runManagerError ? StudioTheme.Constants.error_medium + : StudioTheme.Constants.close_small + + ToolTipArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton + tooltip: root.runManagerError + + onClicked: root.cancelClicked() } } } @@ -256,6 +384,7 @@ Item { checkable: false checked: window.visible + enabled: root.runManagerState === RunManager.NotRunning onClicked: { if (window.visible) { diff --git a/src/plugins/qmldesigner/components/runmanager/runmanager.cpp b/src/plugins/qmldesigner/components/runmanager/runmanager.cpp index 4ac1a9a56eb..3a4b5423acf 100644 --- a/src/plugins/qmldesigner/components/runmanager/runmanager.cpp +++ b/src/plugins/qmldesigner/components/runmanager/runmanager.cpp @@ -59,6 +59,49 @@ RunManager::RunManager(DeviceShare::DeviceManager &deviceManager) // TODO If device going offline is currently running force stop + // Packing + connect(&m_deviceManager, + &DeviceShare::DeviceManager::projectPacking, + this, + [this](const QString &deviceId) { + qCDebug(runManagerLog) << "Project packing." << deviceId; + setState(TargetState::Packing); + }); + connect(&m_deviceManager, + &DeviceShare::DeviceManager::projectPackingError, + this, + &RunManager::handleError); + + // Sending + connect(&m_deviceManager, + &DeviceShare::DeviceManager::projectSendingProgress, + this, + [this](const QString &deviceId, const int percentage) { + qCDebug(runManagerLog) << "Project sending." << deviceId << percentage; + setProgress(percentage); + setState(TargetState::Sending); + }); + connect(&m_deviceManager, + &DeviceShare::DeviceManager::projectSendingError, + this, + &RunManager::handleError); + + // Starting + connect(&m_deviceManager, + &DeviceShare::DeviceManager::projectStarting, + this, + [this](const QString &deviceId) { + qCDebug(runManagerLog) << "Project starting." << deviceId; + setState(TargetState::Starting); + }); + + connect(&m_deviceManager, + &DeviceShare::DeviceManager::projectStartingError, + this, + &RunManager::handleError); + + connect(&m_deviceManager, &DeviceShare::DeviceManager::internalError, this, &RunManager::handleError); + // Connect Android/Device run/stop project signals connect(&m_deviceManager, &DeviceShare::DeviceManager::projectStarted, @@ -68,8 +111,7 @@ RunManager::RunManager(DeviceShare::DeviceManager &deviceManager) m_runningTargets.append(deviceId); - m_state = TargetState::Running; - emit stateChanged(); + setState(TargetState::Running); }); connect(&m_deviceManager, &DeviceShare::DeviceManager::projectStopped, @@ -91,8 +133,7 @@ RunManager::RunManager(DeviceShare::DeviceManager &deviceManager) if (!m_runningTargets.isEmpty()) return; - m_state = TargetState::NotRunning; - emit stateChanged(); + setState(TargetState::NotRunning); }); // Connect Creator run/stop project signals @@ -105,8 +146,7 @@ RunManager::RunManager(DeviceShare::DeviceManager &deviceManager) m_runningTargets.append(QPointer(runControl)); - m_state = TargetState::Running; - emit stateChanged(); + setState(TargetState::Running); }); connect(projectExplorerPlugin, &ProjectExplorer::ProjectExplorerPlugin::runControlStoped, @@ -128,8 +168,7 @@ RunManager::RunManager(DeviceShare::DeviceManager &deviceManager) if (!m_runningTargets.isEmpty()) return; - m_state = TargetState::NotRunning; - emit stateChanged(); + setState(TargetState::NotRunning); }); udpateTargets(); @@ -192,9 +231,16 @@ void RunManager::toggleCurrentTarget() return; } + setError(""); + std::visit([&](const auto &arg) { arg.run(); }, *target); } +void RunManager::cancelCurrentTarget() +{ + deviceManager()->stopProject(); +} + int RunManager::currentTargetIndex() const { return runTargetIndex(m_currentTargetId); @@ -223,6 +269,45 @@ bool RunManager::selectRunTarget(const QString &targetName) return selectRunTarget(Utils::Id::fromString(targetName)); } +void RunManager::setState(TargetState state) +{ + if (state == m_state) + return; + + m_state = state; + emit stateChanged(); +} + +RunManager::TargetState RunManager::state() const +{ + return m_state; +} + +void RunManager::setProgress(int progress) +{ + m_progress = progress; + emit progressChanged(); +} + +int RunManager::progress() const +{ + return m_progress; +} + +void RunManager::setError(const QString &error) +{ + if (error == m_error) + return; + + m_error = error; + emit errorChanged(); +} + +const QString &RunManager::error() const +{ + return m_error; +} + std::optional RunManager::runTarget(Utils::Id targetId) const { auto find_id = [&](const auto &target) { @@ -253,6 +338,13 @@ int RunManager::runTargetIndex(Utils::Id targetId) const return -1; } +void RunManager::handleError(const QString &deviceId, const QString &error) +{ + qCDebug(runManagerLog) << "Error" << deviceId << error; + setError(error); + setState(TargetState::NotRunning); +} + QString NormalTarget::name() const { return "Default"; diff --git a/src/plugins/qmldesigner/components/runmanager/runmanager.h b/src/plugins/qmldesigner/components/runmanager/runmanager.h index 51b3fff555b..be58b0c3c05 100644 --- a/src/plugins/qmldesigner/components/runmanager/runmanager.h +++ b/src/plugins/qmldesigner/components/runmanager/runmanager.h @@ -54,7 +54,7 @@ class RunManager : public QObject public: explicit RunManager(DeviceShare::DeviceManager &deviceManager); - enum TargetState { Running, NotRunning }; + enum TargetState { Packing, Sending, Starting, Running, NotRunning }; Q_ENUM(TargetState) void udpateTargets(); @@ -62,18 +62,28 @@ public: const QList targets() const; void toggleCurrentTarget(); + void cancelCurrentTarget(); int currentTargetIndex() const; bool selectRunTarget(Utils::Id id); bool selectRunTarget(const QString &targetName); - TargetState state() const { return m_state; } + void setState(TargetState state); + TargetState state() const; + + void setProgress(int progress); + int progress() const; + + void setError(const QString &error); + const QString &error() const; private: std::optional runTarget(Utils::Id targetId) const; int runTargetIndex(Utils::Id targetId) const; + void handleError(const QString &deviceId, const QString &error); + DeviceShare::DeviceManager &m_deviceManager; QList m_targets; @@ -82,11 +92,15 @@ private: QList m_runningTargets; TargetState m_state = TargetState::NotRunning; + int m_progress = 0; + QString m_error; signals: void runTargetChanged(); void stateChanged(); void targetsChanged(); + void progressChanged(); + void errorChanged(); }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp index bc89b0412ff..703ae2b076d 100644 --- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp @@ -489,6 +489,14 @@ ToolBarBackend::ToolBarBackend(QObject *parent) &RunManager::stateChanged, this, &ToolBarBackend::runManagerStateChanged); + connect(&QmlDesignerPlugin::runManager(), + &RunManager::progressChanged, + this, + &ToolBarBackend::runManagerProgressChanged); + connect(&QmlDesignerPlugin::runManager(), + &RunManager::errorChanged, + this, + &ToolBarBackend::runManagerErrorChanged); } void ToolBarBackend::registerDeclarativeType() @@ -713,6 +721,11 @@ void ToolBarBackend::toggleRunning() QmlDesignerPlugin::runManager().toggleCurrentTarget(); } +void ToolBarBackend::cancelRunning() +{ + QmlDesignerPlugin::runManager().cancelCurrentTarget(); +} + bool ToolBarBackend::canGoBack() const { QTC_ASSERT(designModeWidget(), return false); @@ -901,6 +914,16 @@ int ToolBarBackend::runManagerState() const return QmlDesignerPlugin::runManager().state(); } +int ToolBarBackend::runManagerProgress() const +{ + return QmlDesignerPlugin::runManager().progress(); +} + +QString ToolBarBackend::runManagerError() const +{ + return QmlDesignerPlugin::runManager().error(); +} + #ifdef DVCONNECTOR_ENABLED DesignViewer::DVConnector *ToolBarBackend::designViewerConnector() { diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h index 5ab0a69f001..b3330a15eef 100644 --- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h @@ -128,6 +128,8 @@ class ToolBarBackend : public QObject Q_PROPERTY(int runTargetIndex READ runTargetIndex NOTIFY runTargetIndexChanged) Q_PROPERTY(int runManagerState READ runManagerState NOTIFY runManagerStateChanged) + Q_PROPERTY(int runManagerProgress READ runManagerProgress NOTIFY runManagerProgressChanged) + Q_PROPERTY(QString runManagerError READ runManagerError NOTIFY runManagerErrorChanged) #ifdef DVCONNECTOR_ENABLED Q_PROPERTY(DesignViewer::DVConnector *designViewerConnector READ designViewerConnector CONSTANT) @@ -155,6 +157,7 @@ public: Q_INVOKABLE void openDeviceManager(); Q_INVOKABLE void selectRunTarget(const QString &targetName); Q_INVOKABLE void toggleRunning(); + Q_INVOKABLE void cancelRunning(); bool canGoBack() const; bool canGoForward() const; @@ -190,6 +193,8 @@ public: int runTargetIndex() const; int runManagerState() const; + int runManagerProgress() const; + QString runManagerError() const; #ifdef DVCONNECTOR_ENABLED DesignViewer::DVConnector *designViewerConnector(); @@ -217,6 +222,8 @@ signals: void runTargetIndexChanged(); void runManagerStateChanged(); + void runManagerProgressChanged(); + void runManagerErrorChanged(); private: void setupWorkspaces(); From d0ba1324e5c4243eafbbfb7ba832558ed309576e Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Thu, 9 Jan 2025 12:50:40 +0100 Subject: [PATCH 10/14] QmlDesigner: Fix SplitButton state on app kill Fix the issue when a device disconnects while the app is running, the split button stays in 'Running' mode, and does return into the default state. Task-number: QDS-14304 Change-Id: I4d2a5e7fada13fd8e7c26333f3241ef1dd7b8ce7 Reviewed-by: Burak Hancerli Reviewed-by: Thomas Hartmann --- .../components/runmanager/runmanager.cpp | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmldesigner/components/runmanager/runmanager.cpp b/src/plugins/qmldesigner/components/runmanager/runmanager.cpp index 3a4b5423acf..ead3621f326 100644 --- a/src/plugins/qmldesigner/components/runmanager/runmanager.cpp +++ b/src/plugins/qmldesigner/components/runmanager/runmanager.cpp @@ -57,7 +57,32 @@ RunManager::RunManager(DeviceShare::DeviceManager &deviceManager) this, &RunManager::udpateTargets); - // TODO If device going offline is currently running force stop + // If device going offline is currently running force stop + connect(&m_deviceManager, + &DeviceShare::DeviceManager::deviceOffline, + this, + [this](const QString &deviceId) { + qCDebug(runManagerLog) << "Device offline." << deviceId; + + if (m_runningTargets.empty()) + return; + + auto findRunningTarget = [&](const auto &runningTarget) { + return std::visit(overloaded{[](const QPointer) { + return false; + }, + [&](const QString &arg) { return arg == deviceId; }}, + runningTarget); + }; + + const auto it = std::ranges::find_if(m_runningTargets, findRunningTarget); + + if (it != m_runningTargets.end()) { + std::visit(overloaded{[](const QPointer) {}, + [&](const QString &) { m_deviceManager.stopProject(); }}, + *it); + } + }); // Packing connect(&m_deviceManager, @@ -391,8 +416,8 @@ AndroidTarget::AndroidTarget(const QString &deviceId) QString AndroidTarget::name() const { - if (auto devcieSettings = deviceManager()->deviceSettings(m_deviceId)) - return devcieSettings->alias(); + if (auto deviceSettings = deviceManager()->deviceSettings(m_deviceId)) + return deviceSettings->alias(); return {}; } From 484cde1df8553342709444790b45abe1631d9ebe Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Wed, 8 Jan 2025 18:03:06 +0200 Subject: [PATCH 11/14] EffectComposer: Remove focus from the editing controls before accept Fixes: QDS-14467 Change-Id: I7f82f4c8769db2c2cbcbd31b5fa8f599b2c7501c Reviewed-by: Shrief Gabr Reviewed-by: Mahmoud Badri --- .../qmldesigner/effectComposerQmlSources/AddPropertyForm.qml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/AddPropertyForm.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/AddPropertyForm.qml index 47aae44ebe3..649412ba181 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/AddPropertyForm.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/AddPropertyForm.qml @@ -748,6 +748,10 @@ Item { enabled: !root.propNameError && !root.uniNameError onClicked: { + // Remove the focus from the editing control. It fixes a mac bug where a + // control's value doesn't get applied when the Apply button is clicked + acceptButton.forceActiveFocus() + root.accepted() root.visible = false } From da38404d72f3b3a2446f62593e43650095ce9d1c Mon Sep 17 00:00:00 2001 From: Burak Hancerli Date: Wed, 8 Jan 2025 12:27:26 +0100 Subject: [PATCH 12/14] DeviceManager: Break the websocket dependencies Task-number: QTCREATORBUG-32296 Change-Id: Ic9c80e3507a7dc8e666d740e0db72d2a5be12042 Reviewed-by: Eike Ziller --- src/plugins/qmldesigner/CMakeLists.txt | 9 +++- .../components/devicesharing/device.cpp | 3 +- .../components/devicesharing/device.h | 3 +- .../devicesharing/devicemanager.cpp | 3 +- .../components/devicesharing/devicemanager.h | 13 +++--- .../devicesharing/devicemanagermodel.cpp | 1 + .../components/devicesharing/websocketmock.h | 45 +++++++++++++++++++ .../components/runmanager/runmanager.cpp | 2 + 8 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 src/plugins/qmldesigner/components/devicesharing/websocketmock.h diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index f504dede055..dcaadba0c11 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -748,15 +748,22 @@ extend_qtc_plugin(QmlDesigner extend_qtc_plugin(QmlDesigner CONDITION TARGET Qt::WebSockets + DEFINES QT_WEBSOCKET_ENABLED + DEPENDS + Qt::WebSockets +) + +extend_qtc_plugin(QmlDesigner SOURCES_PREFIX components/devicesharing DEPENDS - QtCreator::QrCodeGenerator Qt::WebSockets + QtCreator::QrCodeGenerator SOURCES device.cpp device.h deviceinfo.cpp deviceinfo.h devicemanager.cpp devicemanager.h devicemanagermodel.cpp devicemanagermodel.h devicemanagerwidget.cpp devicemanagerwidget.h + websocketmock.h ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/components/devicesharing/device.cpp b/src/plugins/qmldesigner/components/devicesharing/device.cpp index b7a77a9d911..4cb7b61f536 100644 --- a/src/plugins/qmldesigner/components/devicesharing/device.cpp +++ b/src/plugins/qmldesigner/components/devicesharing/device.cpp @@ -5,7 +5,8 @@ #include #include -#include + +#include "websocketmock.h" namespace QmlDesigner::DeviceShare { diff --git a/src/plugins/qmldesigner/components/devicesharing/device.h b/src/plugins/qmldesigner/components/devicesharing/device.h index feae5b2bc71..be12febcb6e 100644 --- a/src/plugins/qmldesigner/components/devicesharing/device.h +++ b/src/plugins/qmldesigner/components/devicesharing/device.h @@ -3,14 +3,13 @@ #pragma once -#include #include -#include #include #include "deviceinfo.h" +class QWebSocket; namespace QmlDesigner::DeviceShare { class Device : public QObject diff --git a/src/plugins/qmldesigner/components/devicesharing/devicemanager.cpp b/src/plugins/qmldesigner/components/devicesharing/devicemanager.cpp index a57691aaa7a..6fbb110c025 100644 --- a/src/plugins/qmldesigner/components/devicesharing/devicemanager.cpp +++ b/src/plugins/qmldesigner/components/devicesharing/devicemanager.cpp @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "devicemanager.h" - +#include "device.h" #include "devicemanagerwidget.h" #include @@ -11,6 +11,7 @@ #include #include #include +#include #include #include diff --git a/src/plugins/qmldesigner/components/devicesharing/devicemanager.h b/src/plugins/qmldesigner/components/devicesharing/devicemanager.h index 9385d73b165..0e42c2ba2bb 100644 --- a/src/plugins/qmldesigner/components/devicesharing/devicemanager.h +++ b/src/plugins/qmldesigner/components/devicesharing/devicemanager.h @@ -3,16 +3,17 @@ #pragma once -#include -#include -#include - #include -#include "device.h" +#include "deviceinfo.h" +#include + +QT_BEGIN_NAMESPACE +class QUdpSocket; +QT_END_NAMESPACE namespace QmlDesigner::DeviceShare { - +class Device; class DeviceManagerWidget; class DeviceManager : public QObject diff --git a/src/plugins/qmldesigner/components/devicesharing/devicemanagermodel.cpp b/src/plugins/qmldesigner/components/devicesharing/devicemanagermodel.cpp index 11dad8e3064..54c678a17b4 100644 --- a/src/plugins/qmldesigner/components/devicesharing/devicemanagermodel.cpp +++ b/src/plugins/qmldesigner/components/devicesharing/devicemanagermodel.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "devicemanagermodel.h" +#include "device.h" #include "devicemanager.h" namespace QmlDesigner::DeviceShare { diff --git a/src/plugins/qmldesigner/components/devicesharing/websocketmock.h b/src/plugins/qmldesigner/components/devicesharing/websocketmock.h new file mode 100644 index 00000000000..974a8d6ac30 --- /dev/null +++ b/src/plugins/qmldesigner/components/devicesharing/websocketmock.h @@ -0,0 +1,45 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#ifdef QT_WEBSOCKET_ENABLED +#include +#else +#include + +// QWebSocket mock. +// It is used to avoid linking against QtWebSockets. +namespace QWebSocketProtocol { +enum CloseCode { CloseCodeNormal = 1000 }; +enum Version { Unknown = 0, Version13 = 13 }; +} // namespace QWebSocketProtocol + +class QWebSocket : public QObject +{ + Q_OBJECT +public: + QWebSocket() = default; + ~QWebSocket() = default; + + void setOutgoingFrameSize(int) {} + void setParent(QObject *) {} + void open(const QUrl &) {} + void close() {} + void close(QWebSocketProtocol::CloseCode, const QString &) {} + void abort() {} + void flush() {} + void ping() {} + bool isValid() {return true;} + QAbstractSocket::SocketState state() {return QAbstractSocket::ConnectedState;} + void sendTextMessage(const QString &){} + void sendBinaryMessage(const QByteArray &){} + +signals: + void pong(quint64, const QByteArray &); + void textMessageReceived(const QString &); + void disconnected(); + void connected(); +}; + +#endif // QT_WEBSOCKETS_LIB diff --git a/src/plugins/qmldesigner/components/runmanager/runmanager.cpp b/src/plugins/qmldesigner/components/runmanager/runmanager.cpp index ead3621f326..631db7f6eb7 100644 --- a/src/plugins/qmldesigner/components/runmanager/runmanager.cpp +++ b/src/plugins/qmldesigner/components/runmanager/runmanager.cpp @@ -8,6 +8,8 @@ #include +#include + namespace QmlDesigner { Q_LOGGING_CATEGORY(runManagerLog, "qtc.designer.runManager", QtWarningMsg) From 4789783d12bf094b7fae70ef5dc81593226e2648 Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Fri, 6 Dec 2024 13:39:55 +0200 Subject: [PATCH 13/14] DesignSystem: Enable setting a theme active A collection can have only one theme active. First theme added to an empty collection is made active by default Task-number: QDS-14261 Change-Id: Ibf9a697ae0a817c45c4bef1a6fb4a9bd28462491 Reviewed-by: Thomas Hartmann --- .../designsystemview/collectionmodel.cpp | 51 +++++++++++++++---- .../designsystemview/collectionmodel.h | 10 +++- .../libs/designsystem/dsthememanager.cpp | 25 ++++++++- .../libs/designsystem/dsthememanager.h | 6 +++ 4 files changed, 78 insertions(+), 14 deletions(-) diff --git a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp index 58077be2b05..8f0da771143 100644 --- a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp +++ b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp @@ -15,6 +15,21 @@ CollectionModel::CollectionModel(DSThemeManager *collection) updateCache(); } +QStringList CollectionModel::themeNameList() const +{ + QStringList themeNames(m_themeIdList.size()); + std::transform(m_themeIdList.begin(), m_themeIdList.end(), themeNames.begin(), [this](ThemeId id) { + return QString::fromLatin1(m_collection->themeName(id)); + }); + return themeNames; +} + +void CollectionModel::setActiveTheme(const QString &themeName) +{ + if (const auto themeId = m_collection->themeId(themeName.toLatin1())) + m_collection->setActiveTheme(*themeId); +} + int CollectionModel::columnCount(const QModelIndex &parent) const { return parent.isValid() ? 0 : static_cast(m_collection->themeCount()); @@ -39,6 +54,8 @@ QVariant CollectionModel::data(const QModelIndex &index, int role) const return QVariant::fromValue(groupType); case static_cast(Roles::BindingRole): return property->isBinding; + case static_cast(Roles::ActiveThemeRole): + return m_collection->activeTheme() == themeId; } return {}; @@ -64,8 +81,17 @@ int CollectionModel::rowCount(const QModelIndex &parent) const QVariant CollectionModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return QString::fromLatin1(m_collection->themeName(findThemeId(section))); + if (orientation == Qt::Horizontal) { + auto themeId = findThemeId(section); + switch (role) { + case Qt::DisplayRole: + return QString::fromLatin1(m_collection->themeName(themeId)); + case static_cast(Roles::ActiveThemeRole): + return m_collection->activeTheme() == themeId; + default: + break; + } + } if (orientation == Qt::Vertical) { if (auto propInfo = findPropertyName(section)) { @@ -75,7 +101,6 @@ QVariant CollectionModel::headerData(int section, Qt::Orientation orientation, i return QVariant::fromValue(propInfo->first); } } - return {}; } @@ -89,6 +114,7 @@ QHash CollectionModel::roleNames() const auto roles = QAbstractItemModel::roleNames(); roles.insert(static_cast(Roles::GroupRole), "group"); roles.insert(static_cast(Roles::BindingRole), "isBinding"); + roles.insert(static_cast(Roles::ActiveThemeRole), "isActive"); return roles; } @@ -106,6 +132,7 @@ bool CollectionModel::insertColumns([[maybe_unused]] int column, int count, cons beginResetModel(); updateCache(); endResetModel(); + emit themeNameChanged(); } return true; } @@ -122,6 +149,7 @@ bool CollectionModel::removeColumns(int column, int count, const QModelIndex &pa updateCache(); endResetModel(); + emit themeNameChanged(); return true; } @@ -190,25 +218,26 @@ bool CollectionModel::setHeaderData(int section, const QVariant &value, int role) { - if (role != Qt::EditRole) - return false; - - if (section < 0 || (orientation == Qt::Horizontal && section >= columnCount()) + if (role != Qt::EditRole || section < 0 + || (orientation == Qt::Horizontal && section >= columnCount()) || (orientation == Qt::Vertical && section >= rowCount())) { return false; // Out of bounds } const auto &newName = value.toString().toUtf8(); bool success = false; - if (orientation == Qt::Horizontal) { - // Theme - success = m_collection->renameTheme(findThemeId(section), newName); - } else { + if (orientation == Qt::Vertical) { // Property Name if (auto propInfo = findPropertyName(section)) { auto [groupType, propName] = *propInfo; success = m_collection->renameProperty(groupType, propName, newName); } + } else { + // Theme + const auto themeId = findThemeId(section); + success = m_collection->renameTheme(themeId, newName); + if (success) + emit themeNameChanged(); } if (success) { diff --git a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h index 3b7a6d0a0ab..3ab0250822b 100644 --- a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h +++ b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h @@ -17,10 +17,15 @@ class CollectionModel : public QAbstractItemModel Q_OBJECT public: - enum class Roles { GroupRole = Qt::UserRole + 1, BindingRole }; + enum class Roles { GroupRole = Qt::UserRole + 1, BindingRole, ActiveThemeRole }; + + Q_PROPERTY(QStringList themeNames READ themeNameList NOTIFY themeNameChanged FINAL) CollectionModel(DSThemeManager *collection); + QStringList themeNameList() const; + Q_INVOKABLE void setActiveTheme(const QString &themeName); + // QAbstractItemModel Interface int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; @@ -52,6 +57,9 @@ public: const QVariant &value, int role = Qt::EditRole) override; +signals: + void themeNameChanged(); + private: ThemeId findThemeId(int column) const; std::optional findPropertyName(int row) const; diff --git a/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp index 30e86ce95e8..08e430c77a3 100644 --- a/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp +++ b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp @@ -48,6 +48,9 @@ std::optional DSThemeManager::addTheme(const ThemeName &themeNameHint) if (!m_themes.try_emplace(newThemeId, assignedThemeName).second) return {}; + if (m_themes.size() == 1) // First theme. Make it active. + reviewActiveTheme(); + // Copy the new theme properties from an old theme(first one). if (m_themes.size() > 1) duplicateTheme(m_themes.begin()->first, newThemeId); @@ -101,6 +104,12 @@ const std::vector DSThemeManager::allThemeIds() const return ids; } +void DSThemeManager::setActiveTheme(ThemeId id) +{ + if (m_themes.contains(id)) + m_activeTheme = id; +} + void DSThemeManager::forAllGroups(std::function callback) const { if (!callback) @@ -131,7 +140,8 @@ void DSThemeManager::removeTheme(ThemeId id) for (auto &[gt, group] : m_groups) group->removeTheme(id); - m_themes.erase(id); + if (m_themes.erase(id)) + reviewActiveTheme(); } void DSThemeManager::duplicateTheme(ThemeId from, ThemeId to) @@ -217,7 +227,7 @@ void DSThemeManager::decorate(ModelNode rootNode, const QByteArray &nodeType, bo return; auto p = rootNode.bindingProperty("currentTheme"); - p.setDynamicTypeNameAndExpression(nodeType, QString::fromLatin1(m_themes.begin()->second)); + p.setDynamicTypeNameAndExpression(nodeType, QString::fromLatin1(m_themes.at(m_activeTheme))); if (!isMCU) addGroupAliases(rootNode); auto model = rootNode.model(); @@ -390,4 +400,15 @@ PropertyName DSThemeManager::uniquePropertyName(const PropertyName &hint) const }); return propName.toUtf8(); } + +void DSThemeManager::reviewActiveTheme() +{ + // Active theme removed. Make the first one active + if (!m_themes.contains(m_activeTheme)) { + if (m_themes.size() > 0) + setActiveTheme(m_themes.begin()->first); + else + m_activeTheme = static_cast(0); + } +} } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h index 1286aea72d3..c36bcfed831 100644 --- a/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h +++ b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h @@ -39,6 +39,9 @@ public: bool renameTheme(ThemeId id, const ThemeName &newName); const std::vector allThemeIds() const; + ThemeId activeTheme() const { return m_activeTheme; } + void setActiveTheme(ThemeId id); + void forAllGroups(std::function callback) const; void removeTheme(ThemeId id); @@ -70,9 +73,12 @@ private: ThemeName uniqueThemeName(const ThemeName &hint) const; PropertyName uniquePropertyName(const PropertyName &hint) const; + void reviewActiveTheme(); + private: std::map m_themes; std::map> m_groups; + ThemeId m_activeTheme = static_cast(0); }; using DSCollections = std::map; From 2a721d59375dff98cb07ece07e1a83537d8cd1bc Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Mon, 30 Dec 2024 00:04:03 +0100 Subject: [PATCH 14/14] DesignSystem: Resolve design system bindings Task-number: QDS-14261 Change-Id: I24215950c556f201bbfb53d043b63fd596ccc6aa Reviewed-by: Thomas Hartmann --- .../qmldesigner/designsystem/Main.qml | 9 +++--- .../designsystemview/collectionmodel.cpp | 32 +++++++++++++------ .../designsystemview/collectionmodel.h | 12 +++++-- .../designsysteminterface.cpp | 3 +- .../qmldesigner/libs/designsystem/dsstore.cpp | 22 +++++++++++++ .../qmldesigner/libs/designsystem/dsstore.h | 2 ++ .../libs/designsystem/dsthememanager.cpp | 9 ++++++ .../libs/designsystem/dsthememanager.h | 2 ++ 8 files changed, 74 insertions(+), 17 deletions(-) diff --git a/share/qtcreator/qmldesigner/designsystem/Main.qml b/share/qtcreator/qmldesigner/designsystem/Main.qml index 7033eda1f6d..7c444c44e4f 100644 --- a/share/qtcreator/qmldesigner/designsystem/Main.qml +++ b/share/qtcreator/qmldesigner/designsystem/Main.qml @@ -121,13 +121,14 @@ Rectangle { } component Cell: Rectangle { - required property string display + required property var display required property int row required property int column required property bool editing required property bool isBinding + required property var propertyValue color: root.backgroundColor implicitWidth: root.cellWidth @@ -227,7 +228,7 @@ Rectangle { anchors.fill: parent leftPadding: root.leftPadding - value: parseInt(numberDelegate.display) + value: numberDelegate.display from: -1000 // TODO define min/max to: 1000 editable: true @@ -261,7 +262,7 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter anchors.leftMargin: root.leftPadding - checked: flagDelegate.display === "true" + checked: flagDelegate.display text: flagDelegate.display onToggled: { @@ -328,7 +329,7 @@ Rectangle { height: parent.height verticalAlignment: Qt.AlignVCenter color: StudioTheme.Values.themeTextColor - text: colorDelegate.display + text: colorDelegate.propertyValue } } diff --git a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp index 8f0da771143..a9c4922caf4 100644 --- a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp +++ b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "collectionmodel.h" +#include #include #include @@ -9,8 +10,9 @@ namespace QmlDesigner { -CollectionModel::CollectionModel(DSThemeManager *collection) +CollectionModel::CollectionModel(DSThemeManager *collection, const DSStore *store) : m_collection(collection) + , m_store(store) { updateCache(); } @@ -47,14 +49,22 @@ QVariant CollectionModel::data(const QModelIndex &index, int role) const if (!property) return {}; + const QVariant propertyValue = property->value.toString(); + const QVariant displayValue = property->isBinding + ? m_store->resolvedDSBinding(propertyValue.toString()).value + : property->value; + switch (role) { case Qt::DisplayRole: - return property->value.toString(); - case static_cast(Roles::GroupRole): + case Roles::ResolvedValueRole: + return displayValue; + case Roles::PropertyValueRole: + return propertyValue; + case Roles::GroupRole: return QVariant::fromValue(groupType); - case static_cast(Roles::BindingRole): + case Roles::BindingRole: return property->isBinding; - case static_cast(Roles::ActiveThemeRole): + case Roles::ActiveThemeRole: return m_collection->activeTheme() == themeId; } @@ -86,7 +96,7 @@ QVariant CollectionModel::headerData(int section, Qt::Orientation orientation, i switch (role) { case Qt::DisplayRole: return QString::fromLatin1(m_collection->themeName(themeId)); - case static_cast(Roles::ActiveThemeRole): + case Roles::ActiveThemeRole: return m_collection->activeTheme() == themeId; default: break; @@ -97,7 +107,7 @@ QVariant CollectionModel::headerData(int section, Qt::Orientation orientation, i if (auto propInfo = findPropertyName(section)) { if (role == Qt::DisplayRole) return QString::fromLatin1(propInfo->second); - if (role == static_cast(Roles::GroupRole)) + if (role == Roles::GroupRole) return QVariant::fromValue(propInfo->first); } } @@ -112,9 +122,11 @@ Qt::ItemFlags CollectionModel::flags(const QModelIndex &index) const QHash CollectionModel::roleNames() const { auto roles = QAbstractItemModel::roleNames(); - roles.insert(static_cast(Roles::GroupRole), "group"); - roles.insert(static_cast(Roles::BindingRole), "isBinding"); - roles.insert(static_cast(Roles::ActiveThemeRole), "isActive"); + roles.insert(Roles::ResolvedValueRole, "resolvedValue"); + roles.insert(Roles::GroupRole, "group"); + roles.insert(Roles::BindingRole, "isBinding"); + roles.insert(Roles::ActiveThemeRole, "isActive"); + roles.insert(Roles::PropertyValueRole, "propertyValue"); return roles; } diff --git a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h index 3ab0250822b..c0b43500012 100644 --- a/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h +++ b/src/plugins/qmldesigner/components/designsystemview/collectionmodel.h @@ -10,6 +10,7 @@ namespace QmlDesigner { class DSThemeManager; +class DSStore; using PropInfo = std::pair; class CollectionModel : public QAbstractItemModel @@ -17,11 +18,17 @@ class CollectionModel : public QAbstractItemModel Q_OBJECT public: - enum class Roles { GroupRole = Qt::UserRole + 1, BindingRole, ActiveThemeRole }; + enum Roles { + GroupRole = Qt::UserRole + 1, + BindingRole, + ActiveThemeRole, + ResolvedValueRole, + PropertyValueRole + }; Q_PROPERTY(QStringList themeNames READ themeNameList NOTIFY themeNameChanged FINAL) - CollectionModel(DSThemeManager *collection); + CollectionModel(DSThemeManager *collection, const DSStore *store); QStringList themeNameList() const; Q_INVOKABLE void setActiveTheme(const QString &themeName); @@ -66,6 +73,7 @@ private: private: DSThemeManager *m_collection = nullptr; + const DSStore *m_store; // cache std::vector m_themeIdList; diff --git a/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.cpp b/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.cpp index 987d30e7263..e7f07cbf9a1 100644 --- a/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.cpp +++ b/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.cpp @@ -74,7 +74,8 @@ QStringList DesignSystemInterface::collections() const CollectionModel *DesignSystemInterface::createModel(const QString &typeName, DSThemeManager *collection) { auto [newItr, success] = m_models.try_emplace(typeName, - std::make_unique(collection)); + std::make_unique(collection, + m_store)); if (success) { // Otherwise the model will be deleted by the QML engine. QQmlEngine::setObjectOwnership(newItr->second.get(), QQmlEngine::CppOwnership); diff --git a/src/plugins/qmldesigner/libs/designsystem/dsstore.cpp b/src/plugins/qmldesigner/libs/designsystem/dsstore.cpp index ffa4050c9d5..143ba6f262b 100644 --- a/src/plugins/qmldesigner/libs/designsystem/dsstore.cpp +++ b/src/plugins/qmldesigner/libs/designsystem/dsstore.cpp @@ -248,6 +248,28 @@ QStringList DSStore::collectionNames() const return names; } +ThemeProperty DSStore::resolvedDSBinding(QStringView binding) const +{ + const auto parts = binding.split('.', Qt::SkipEmptyParts); + if (parts.size() != 3) + return {}; + + const auto &collectionName = parts[0]; + auto itr = m_collections.find(collectionName.toString()); + if (itr == m_collections.end()) + return {}; + + const DSThemeManager &boundCollection = itr->second; + const auto &propertyName = parts[2].toLatin1(); + if (const auto group = boundCollection.groupType(propertyName)) { + auto property = boundCollection.property(boundCollection.activeTheme(), *group, propertyName); + if (property) + return property->isBinding ? resolvedDSBinding(property->value.toString()) : *property; + } + + return {}; +} + QString DSStore::uniqueCollectionName(const QString &hint) const { return UniqueName::generateTypeName(hint, "Collection", [this](const QString &t) { diff --git a/src/plugins/qmldesigner/libs/designsystem/dsstore.h b/src/plugins/qmldesigner/libs/designsystem/dsstore.h index 9708587821a..f51794edcf8 100644 --- a/src/plugins/qmldesigner/libs/designsystem/dsstore.h +++ b/src/plugins/qmldesigner/libs/designsystem/dsstore.h @@ -38,6 +38,8 @@ public: std::optional moduleDirPath() const; QStringList collectionNames() const; + ThemeProperty resolvedDSBinding(QStringView binding) const; + private: QString uniqueCollectionName(const QString &hint) const; std::optional loadCollection(const QString &typeName, const Utils::FilePath &qmlFilePath); diff --git a/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp index 08e430c77a3..d891ba7b153 100644 --- a/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp +++ b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp @@ -150,6 +150,15 @@ void DSThemeManager::duplicateTheme(ThemeId from, ThemeId to) group->duplicateValues(from, to); } +std::optional DSThemeManager::groupType(const PropertyName &name) const +{ + for (const auto &[gt, group] : m_groups) { + if (group->hasProperty(name)) + return gt; + } + return {}; +} + std::optional DSThemeManager::property(ThemeId themeId, GroupType gType, const PropertyName &name) const diff --git a/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h index c36bcfed831..27556292a6d 100644 --- a/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h +++ b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h @@ -50,6 +50,8 @@ public: void duplicateTheme(ThemeId from, ThemeId to); + std::optional groupType(const PropertyName &name) const; + bool addProperty(GroupType gType, const ThemeProperty &p); std::optional property(ThemeId themeId, GroupType gType,