From 856608a511e70455b6fd578d9583b0b8180a696e Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 24 Sep 2024 17:12:58 +0200 Subject: [PATCH 01/44] QmlDesigner: Add ifdef for QDS_USE_PROJECTSTORAGE Change-Id: I902203d8c747ea85cbba5f7c5351c3f8f8127afb Reviewed-by: Marco Bubke --- .../libs/designercore/rewriter/texttomodelmerger.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp b/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp index b61330aa5ec..27e9fb0102c 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp @@ -1432,8 +1432,13 @@ QmlDesigner::PropertyName TextToModelMerger::syncScriptBinding(ModelNode &modelN prefix, script->qualifiedId, astValue); + +#ifndef QDS_USE_PROJECTSTORAGE // Can happen if the type was just created and was not fully processed yet const bool newlyCreatedTypeCase = !modelNode.metaInfo().properties().size(); +#else + const bool newlyCreatedTypeCase = false; +#endif if (enumValue.isValid()) { // It is a qualified enum: AbstractProperty modelProperty = modelNode.property(astPropertyName.toUtf8()); From 72fb8971f775f6c2d37b5d98564f669dbd2ae353 Mon Sep 17 00:00:00 2001 From: Vikas Pachdha Date: Wed, 18 Sep 2024 13:44:00 +0200 Subject: [PATCH 02/44] Move design system to designer/libs Change-Id: I966603f66c3fafba9892e6f0915694e9019b80ef Reviewed-by: Marco Bubke --- src/plugins/qmldesigner/CMakeLists.txt | 10 +--------- src/plugins/qmldesigner/libs/CMakeLists.txt | 1 + .../qmldesigner/libs/designsystem/CMakeLists.txt | 16 ++++++++++++++++ .../libs/designsystem/designsystem_global.h | 14 ++++++++++++++ .../designsystem/dsconstants.h | 0 .../designsystem/dsthemegroup.cpp | 0 .../designsystem/dsthemegroup.h | 4 ++-- .../designsystem/dsthememanager.cpp | 0 .../designsystem/dsthememanager.h | 5 +++-- 9 files changed, 37 insertions(+), 13 deletions(-) create mode 100644 src/plugins/qmldesigner/libs/designsystem/CMakeLists.txt create mode 100644 src/plugins/qmldesigner/libs/designsystem/designsystem_global.h rename src/plugins/qmldesigner/{components => libs}/designsystem/dsconstants.h (100%) rename src/plugins/qmldesigner/{components => libs}/designsystem/dsthemegroup.cpp (100%) rename src/plugins/qmldesigner/{components => libs}/designsystem/dsthemegroup.h (94%) rename src/plugins/qmldesigner/{components => libs}/designsystem/dsthememanager.cpp (100%) rename src/plugins/qmldesigner/{components => libs}/designsystem/dsthememanager.h (94%) diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 6ec60cc2159..3a005e763b5 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -52,7 +52,7 @@ add_qtc_plugin(QmlDesigner QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem Qt::QuickWidgets Qt::CorePrivate Qt::Xml Qt::Svg Sqlite Zip Qt::GuiPrivate PUBLIC_DEPENDS - QmlDesignerUtils QmlPuppetCommunication QmlDesignerCore + QmlDesignerUtils QmlPuppetCommunication QmlDesignerCore DesignSystem DEFINES IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\" SHARE_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/../../../share/qtcreator/qmldesigner" @@ -727,14 +727,6 @@ extend_qtc_plugin(QmlDesigner messagemodel.h ) -extend_qtc_plugin(QmlDesigner - SOURCES_PREFIX components/designsystem - SOURCES - dsconstants.h - dsthememanager.h dsthememanager.cpp - dsthemegroup.cpp dsthemegroup.h -) - add_qtc_plugin(assetexporterplugin PLUGIN_CLASS AssetExporterPlugin CONDITION TARGET QmlDesigner diff --git a/src/plugins/qmldesigner/libs/CMakeLists.txt b/src/plugins/qmldesigner/libs/CMakeLists.txt index 7cac0a93a3d..be2d12733cb 100644 --- a/src/plugins/qmldesigner/libs/CMakeLists.txt +++ b/src/plugins/qmldesigner/libs/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(designercore) add_subdirectory(qmldesignerutils) +add_subdirectory(designsystem) diff --git a/src/plugins/qmldesigner/libs/designsystem/CMakeLists.txt b/src/plugins/qmldesigner/libs/designsystem/CMakeLists.txt new file mode 100644 index 00000000000..8830807ce08 --- /dev/null +++ b/src/plugins/qmldesigner/libs/designsystem/CMakeLists.txt @@ -0,0 +1,16 @@ +add_qtc_library(DesignSystem STATIC + PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR} + DEPENDS + Qt::Core QmlDesignerCore + SOURCES + dsconstants.h + dsthemegroup.h dsthemegroup.cpp + dsthememanager.h dsthememanager.cpp +) + +extend_qtc_library(DesignSystem + CONDITION ENABLE_COMPILE_WARNING_AS_ERROR + PROPERTIES COMPILE_WARNING_AS_ERROR ON + PUBLIC_COMPILE_OPTIONS + $<$:-Wno-error=maybe-uninitialized> +) diff --git a/src/plugins/qmldesigner/libs/designsystem/designsystem_global.h b/src/plugins/qmldesigner/libs/designsystem/designsystem_global.h new file mode 100644 index 00000000000..835c8b0ad3d --- /dev/null +++ b/src/plugins/qmldesigner/libs/designsystem/designsystem_global.h @@ -0,0 +1,14 @@ +// 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 + +#if defined(DESIGNSYSTEM_LIBRARY) +# define DESIGNSYSTEM_EXPORT Q_DECL_EXPORT +#elif defined(DESIGNSYSTEM_STATIC_LIBRARY) +# define DESIGNSYSTEM_EXPORT +#else +# define DESIGNSYSTEM_EXPORT Q_DECL_IMPORT +#endif diff --git a/src/plugins/qmldesigner/components/designsystem/dsconstants.h b/src/plugins/qmldesigner/libs/designsystem/dsconstants.h similarity index 100% rename from src/plugins/qmldesigner/components/designsystem/dsconstants.h rename to src/plugins/qmldesigner/libs/designsystem/dsconstants.h diff --git a/src/plugins/qmldesigner/components/designsystem/dsthemegroup.cpp b/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.cpp similarity index 100% rename from src/plugins/qmldesigner/components/designsystem/dsthemegroup.cpp rename to src/plugins/qmldesigner/libs/designsystem/dsthemegroup.cpp diff --git a/src/plugins/qmldesigner/components/designsystem/dsthemegroup.h b/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.h similarity index 94% rename from src/plugins/qmldesigner/components/designsystem/dsthemegroup.h rename to src/plugins/qmldesigner/libs/designsystem/dsthemegroup.h index b76e2f3d504..e61a915623e 100644 --- a/src/plugins/qmldesigner/components/designsystem/dsthemegroup.h +++ b/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.h @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once -#include "qmldesignercomponents_global.h" +#include "designsystem_global.h" #include "dsconstants.h" #include "nodeinstanceglobal.h" @@ -18,7 +18,7 @@ enum class DECORATION_CONTEXT { COMPONENT_THEME, }; -class QMLDESIGNERCOMPONENTS_EXPORT DSThemeGroup +class DESIGNSYSTEM_EXPORT DSThemeGroup { struct PropertyData { diff --git a/src/plugins/qmldesigner/components/designsystem/dsthememanager.cpp b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp similarity index 100% rename from src/plugins/qmldesigner/components/designsystem/dsthememanager.cpp rename to src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp diff --git a/src/plugins/qmldesigner/components/designsystem/dsthememanager.h b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h similarity index 94% rename from src/plugins/qmldesigner/components/designsystem/dsthememanager.h rename to src/plugins/qmldesigner/libs/designsystem/dsthememanager.h index e3ac9e2e4c9..0972dcd7893 100644 --- a/src/plugins/qmldesigner/components/designsystem/dsthememanager.h +++ b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h @@ -3,7 +3,7 @@ #pragma once -#include "qmldesignercomponents_global.h" +#include "designsystem_global.h" #include "dsconstants.h" #include "dsthemegroup.h" @@ -15,7 +15,8 @@ namespace QmlDesigner { using ThemeName = PropertyName; class DSTheme; -class QMLDESIGNERCOMPONENTS_EXPORT DSThemeManager + +class DESIGNSYSTEM_EXPORT DSThemeManager { public: From dfbe3e72b4f4b0169cf4c468e5b7c9d9af76d2f9 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Wed, 25 Sep 2024 11:10:39 +0200 Subject: [PATCH 03/44] qds: add git plugin Change-Id: Icbecb0a2de95ed6b9633c554e107506291c86014 Reviewed-by: Thomas Hartmann --- dist/branding/qtdesignstudio/QtCreatorIDEBranding.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/dist/branding/qtdesignstudio/QtCreatorIDEBranding.cmake b/dist/branding/qtdesignstudio/QtCreatorIDEBranding.cmake index 456815ba389..59b57f98404 100644 --- a/dist/branding/qtdesignstudio/QtCreatorIDEBranding.cmake +++ b/dist/branding/qtdesignstudio/QtCreatorIDEBranding.cmake @@ -31,6 +31,7 @@ set(DESIGNSTUDIO_PLUGINS DiffEditor EffectComposer FakeVim + Git Help Insight LanguageClient From 1917842ba159a743d07b71ff3ec8556adf6cbafd Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Wed, 25 Sep 2024 09:49:48 +0300 Subject: [PATCH 04/44] Doc: Fix course links Task-number: QDS-13732 Change-Id: I6e594838376ab7d86275452357d7749aa37b4cf1 Reviewed-by: Tim Jenssen Reviewed-by: Pranta Ghosh Dastider --- doc/qtdesignstudio/src/qtdesignstudio.qdoc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/doc/qtdesignstudio/src/qtdesignstudio.qdoc b/doc/qtdesignstudio/src/qtdesignstudio.qdoc index e90e733c631..42c826a4325 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio.qdoc @@ -87,11 +87,11 @@ \endlist \li Online Courses \list - \li \l{https://qurious.qt.io/enrollments/197683855/details}{Getting Started} - \li \l{https://qurious.qt.io/catalog/courses/3910783}{Creating Your First App} - \li \l{https://qurious.qt.io/enrollments/154647839/details}{Introduction to 2D UI Design} - \li \l{https://qurious.qt.io/enrollments/167005403/details}{Introduction to 3D Design} - \li \l{https://qurious.qt.io/catalog/courses/3910791}{Using Qt Bridge for Figma} + \li \l{https://www.qt.io/academy/course-catalog#getting-started-with-qt-design-studio}{Getting Started} + \li \l{https://www.qt.io/academy/course-catalog#creating-your-first-app-with-qt-design-studio}{Creating Your First App} + \li \l{https://www.qt.io/academy/course-catalog#2d-with-qt-design-studio}{2D with Qt Design Studio} + \li \l{https://www.qt.io/academy/course-catalog#3d-with-qt-design-studio}{3D with Qt Design Studio} + \li \l{https://www.qt.io/academy/course-catalog#qt-design-studio:-blur-effect}{Creating a Blur Effect} \endlist \endtable \enddiv From b37b6b4335785ee78d5dd5e3c8c7e94e91fb09f6 Mon Sep 17 00:00:00 2001 From: Teea Poldsam Date: Wed, 25 Sep 2024 12:39:17 +0300 Subject: [PATCH 05/44] Doc: Hide SDK Tool docs Change-Id: I8b709c7984ebe26ac38b805756e1354239d1bfc6 Reviewed-by: Mats Honkamaa --- doc/qtdesignstudio/config/qtdesignstudio.qdocconf | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/qtdesignstudio/config/qtdesignstudio.qdocconf b/doc/qtdesignstudio/config/qtdesignstudio.qdocconf index 0ab6506489c..395eea6ca67 100644 --- a/doc/qtdesignstudio/config/qtdesignstudio.qdocconf +++ b/doc/qtdesignstudio/config/qtdesignstudio.qdocconf @@ -55,6 +55,7 @@ excludedirs += ../../qtcreator/examples/accelbubble \ ../../qtcreator/src/python \ ../../qtcreator/src/qnx \ ../../qtcreator/src/qtquick/creator-only \ + ../../qtcreator/src/reference \ ../../qtcreator/src/user-interface/creator-only \ ../../qtcreator/src/vcs/creator-only \ ../../qtcreator/src/widgets \ From 4323f41adb8d8fe2c43c2fcf320d9284bc884a74 Mon Sep 17 00:00:00 2001 From: Johanna Vanhatapio Date: Wed, 25 Sep 2024 13:52:54 +0300 Subject: [PATCH 06/44] Doc: Fix a grammar issue Change-Id: I33149176ffd944e80a88acb2579ebb6c48c00a1a Reviewed-by: Mats Honkamaa --- doc/qtdesignstudio/src/qtdesignstudio.qdoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/qtdesignstudio/src/qtdesignstudio.qdoc b/doc/qtdesignstudio/src/qtdesignstudio.qdoc index 42c826a4325..cedc8b80460 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio.qdoc @@ -48,8 +48,8 @@ click-through mockup. Test, preview, and fine-tune your designs to pixel-perfection, live on target devices. - A single unified framework, one common language, fewer feedback loops, and faster iterations, - \QDS closes the gap between designers and developers. + With a single unified framework, one common language, fewer feedback loops, and faster + iterations, \QDS closes the gap between designers and developers. \b {LEARN MORE} From 53dc4f1cf084603673a428e15721c624c6a8f759 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 25 Sep 2024 16:08:07 +0200 Subject: [PATCH 07/44] QmlDesigner: Fix precompiled header Change-Id: Id50b44b5d67f7226738b315a3205626d6af5b3a2 Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/libs/designsystem/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/libs/designsystem/CMakeLists.txt b/src/plugins/qmldesigner/libs/designsystem/CMakeLists.txt index 8830807ce08..05fde136802 100644 --- a/src/plugins/qmldesigner/libs/designsystem/CMakeLists.txt +++ b/src/plugins/qmldesigner/libs/designsystem/CMakeLists.txt @@ -1,7 +1,7 @@ add_qtc_library(DesignSystem STATIC PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR} DEPENDS - Qt::Core QmlDesignerCore + Qt::Core Qt::Widgets QmlDesignerCore SOURCES dsconstants.h dsthemegroup.h dsthemegroup.cpp From d93dd5678bdd375bcbbb1aec1ad63269e19c6c8f Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Thu, 15 Aug 2024 12:02:07 +0300 Subject: [PATCH 08/44] Doc: Update left-side menu MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QDS-13381 Change-Id: I7c4eb1111ab398a29a2c891e905ddcad7fd9f5a4 Reviewed-by: Teea Põldsam Reviewed-by: Johanna Vanhatapio Reviewed-by: Leena Miettinen --- .../config/style/qt5-sidebar.html | 513 +++++++++++++++--- 1 file changed, 429 insertions(+), 84 deletions(-) diff --git a/doc/qtdesignstudio/config/style/qt5-sidebar.html b/doc/qtdesignstudio/config/style/qt5-sidebar.html index 7ca7d5b1e65..e88ece7b7ae 100644 --- a/doc/qtdesignstudio/config/style/qt5-sidebar.html +++ b/doc/qtdesignstudio/config/style/qt5-sidebar.html @@ -12,103 +12,448 @@

Getting Started

- + - - -
-
-

Implementing Applications

-
- -
-
-
-

Advanced Designer Topics

-
- -
- +
-

Help

+

Working with

+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + \ No newline at end of file From 3886205424463735b7ff5893f5757fca4d101cd8 Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Wed, 25 Sep 2024 15:11:33 +0300 Subject: [PATCH 09/44] Doc: Add link to 4.6 release blog post MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I9c51b1147545884563b8ffae06080fc845d93492 Reviewed-by: Johanna Vanhatapio Reviewed-by: Teea Põldsam --- .../src/external-resources/external-resources-qds.qdoc | 4 ++++ doc/qtdesignstudio/src/whats new/qds-releases.qdoc | 1 + 2 files changed, 5 insertions(+) diff --git a/doc/qtcreator/src/external-resources/external-resources-qds.qdoc b/doc/qtcreator/src/external-resources/external-resources-qds.qdoc index c46066168e8..1cd90ae903f 100644 --- a/doc/qtcreator/src/external-resources/external-resources-qds.qdoc +++ b/doc/qtcreator/src/external-resources/external-resources-qds.qdoc @@ -105,6 +105,10 @@ \externalpage https://doc.qt.io/qt/linguist-id-based-i18n.html \title Text ID based translations */ +/*! + \externalpage https://www.qt.io/blog/qt-design-studio-4.6-released + \title Qt Design Studio 4.6 released +*/ /*! \externalpage https://www.qt.io/blog/qt-design-studio-4.5.1-released \title Qt Design Studio 4.5.1 released diff --git a/doc/qtdesignstudio/src/whats new/qds-releases.qdoc b/doc/qtdesignstudio/src/whats new/qds-releases.qdoc index ee792775f82..c21baef03ba 100644 --- a/doc/qtdesignstudio/src/whats new/qds-releases.qdoc +++ b/doc/qtdesignstudio/src/whats new/qds-releases.qdoc @@ -14,6 +14,7 @@ \section2 \QDS 4 \list + \li \l{Qt Design Studio 4.6 released} \li \l{Qt Design Studio 4.5.1 released} \li \l{Qt Design Studio 4.5 released} \li \l{Qt Design Studio 4.4 released} From 3ba561e6f8d99c703ff87cc61fc7ebe2919c289c Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Thu, 26 Sep 2024 11:10:07 +0300 Subject: [PATCH 10/44] QmlDesigner: Unify texture creation Textures should be created only by CreateTexture. Fixes: QDS-13739 Change-Id: I82b2b3a1cdbdb711e1a4b69493e12252d40ff2f8 Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../componentcore/modelnodeoperations.cpp | 102 +++++------------- .../componentcore/modelnodeoperations.h | 1 - .../navigator/navigatortreemodel.cpp | 48 ++------- .../components/navigator/navigatortreemodel.h | 8 +- .../texteditor/texteditorwidget.cpp | 1 - 5 files changed, 38 insertions(+), 122 deletions(-) diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index db23abc4697..dcf690e74a1 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -6,6 +6,7 @@ #include "addimagesdialog.h" #include "addsignalhandlerdialog.h" #include "componentcore_constants.h" +#include "createtexture.h" #include "findimplementation.h" #include "layoutingridlayout.h" #include "modelnodecontextmenu_helper.h" @@ -87,11 +88,14 @@ Utils::SmallString auxPropertyString(Utils::SmallStringView name) { return auxDataString + name; } -} // namespace -inline static void reparentTo(const ModelNode &node, const QmlItemNode &parent) +QString relativePathToQmlFile(const QString &absolutePath) { + return DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(absolutePath); +} +inline void reparentTo(const ModelNode &node, const QmlItemNode &parent) +{ if (parent.isValid() && node.isValid()) { NodeAbstractProperty parentProperty; @@ -104,7 +108,7 @@ inline static void reparentTo(const ModelNode &node, const QmlItemNode &parent) } } -inline static QPointF getUpperLeftPosition(const QList &modelNodeList) +inline QPointF getUpperLeftPosition(const QList &modelNodeList) { QPointF postion(std::numeric_limits::max(), std::numeric_limits::max()); for (const ModelNode &modelNode : modelNodeList) { @@ -120,13 +124,15 @@ inline static QPointF getUpperLeftPosition(const QList &modelNodeList return postion; } -static void setUpperLeftPostionToNode(const ModelNode &layoutNode, const QList &modelNodeList) +void setUpperLeftPostionToNode(const ModelNode &layoutNode, const QList &modelNodeList) { QPointF upperLeftPosition = getUpperLeftPosition(modelNodeList); layoutNode.variantProperty("x").setValue(qRound(upperLeftPosition.x())); layoutNode.variantProperty("y") .setValue(qRound(upperLeftPosition.y())); } +} // namespace + namespace ModelNodeOperations { bool goIntoComponent(const ModelNode &modelNode) @@ -1905,41 +1911,17 @@ static bool moveNodeToParent(const NodeAbstractProperty &targetProperty, const M return false; } -ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath) +ModelNode createTextureNode(AbstractView *view, const QString &imagePath) { - AbstractView *view = targetProp.view(); QTC_ASSERT(view, return {}); - if (targetProp.isValid()) { - // create a texture item lib - ItemLibraryEntry itemLibraryEntry; - itemLibraryEntry.setName("Texture"); - itemLibraryEntry.setType("QtQuick3D.Texture", 1, 0); - - // set texture source - PropertyName prop = "source"; - QString type = "QUrl"; - QVariant val = imagePath; - itemLibraryEntry.addProperty(prop, type, val); - - // create a texture - ModelNode newModelNode = QmlItemNode::createQmlObjectNode(view, - itemLibraryEntry, - {}, - targetProp, - false); - - // Rename the node based on source image - QFileInfo fi(imagePath); - newModelNode.setIdWithoutRefactoring( - view->model()->generateNewId(fi.baseName(), "textureImage")); - return newModelNode; - } - return {}; + auto textureCreator = new CreateTexture(view); + ModelNode texture = textureCreator->execute(imagePath, AddTextureMode::Texture); + textureCreator->deleteLater(); + return texture; } bool dropAsImage3dTexture(const ModelNode &targetNode, - const NodeAbstractProperty &targetProp, const QString &imagePath, ModelNode &newNode, bool &outMoveNodesAfter) @@ -1949,16 +1931,11 @@ bool dropAsImage3dTexture(const ModelNode &targetNode, auto bindToProperty = [&](const PropertyName &propName) { view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] { - newNode = createTextureNode(targetProp, imagePath); + newNode = createTextureNode(view, imagePath); if (newNode.isValid()) { BindingProperty bindProp = targetNode.bindingProperty(propName); bindProp.setExpression(newNode.validId()); - ModelNode matLib = Utils3D::materialLibraryNode(view); - if (matLib.isValid()) { - NodeAbstractProperty matLibProp = matLib.defaultNodeAbstractProperty(); - matLibProp.reparentHere(newNode); - outMoveNodesAfter = false; - } + outMoveNodesAfter = false; } }); }; @@ -1979,7 +1956,7 @@ bool dropAsImage3dTexture(const ModelNode &targetNode, if (dialog->result() == QDialog::Accepted) { view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] { - newNode = createTextureNode(targetProp, imagePath); + newNode = createTextureNode(view, imagePath); if (newNode.isValid()) // Automatically set the texture to selected property targetNode.bindingProperty(dialog->selectedProperty()) .setExpression(newNode.validId()); @@ -1999,10 +1976,11 @@ bool dropAsImage3dTexture(const ModelNode &targetNode, return newNode.isValid(); } else if (targetNode.metaInfo().isQtQuick3DTexture()) { // if dropping an image on an existing texture, set the source - targetNode.variantProperty("source").setValue(imagePath); + targetNode.variantProperty("source").setValue(relativePathToQmlFile(imagePath)); return true; } else if (targetNode.metaInfo().isQtQuick3DModel()) { - QTimer::singleShot(0, view, [targetNode, imagePath, view]() { + const QString relImagePath = relativePathToQmlFile(imagePath); + QTimer::singleShot(0, view, [targetNode, relImagePath, view]() { if (view && targetNode.isValid()) { // To MaterialBrowserView. Done async to avoid custom notification in transaction QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialBrowser"); @@ -2010,7 +1988,7 @@ bool dropAsImage3dTexture(const ModelNode &targetNode, {targetNode}, {DocumentManager::currentFilePath() .absolutePath() - .pathAppended(imagePath) + .pathAppended(relImagePath) .cleanPath() .toString()}); } @@ -2102,20 +2080,12 @@ ModelNode handleItemLibraryImageDrop(const QString &imagePath, AbstractView *view = targetNode.view(); QTC_ASSERT(view, return {}); - const QString imagePathRelative - = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath( - imagePath); // relative to .ui.qml file - ModelNode newModelNode; - if (!dropAsImage3dTexture(targetNode, - targetProperty, - imagePathRelative, - newModelNode, - outMoveNodesAfter)) { + if (!dropAsImage3dTexture(targetNode, imagePath, newModelNode, outMoveNodesAfter)) { if (targetNode.metaInfo().isQtQuickImage() || targetNode.metaInfo().isQtQuickBorderImage()) { // if dropping an image on an existing image, set the source - targetNode.variantProperty("source").setValue(imagePathRelative); + targetNode.variantProperty("source").setValue(relativePathToQmlFile(imagePath)); } else { // create an image QmlItemNode newItemNode = QmlItemNode::createQmlItemNodeFromImage(view, @@ -2176,8 +2146,7 @@ ModelNode handleItemLibraryShaderDrop(const QString &shaderPath, ModelNode newModelNode; - const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath( - shaderPath); + const QString relPath = relativePathToQmlFile(shaderPath); if (targetNode.metaInfo().isQtQuick3DShader()) { // if dropping into an existing Shader, update @@ -2233,8 +2202,7 @@ ModelNode handleItemLibrarySoundDrop(const QString &soundPath, ModelNode newModelNode; - const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath( - soundPath); + const QString relPath = relativePathToQmlFile(soundPath); if (targetNode.metaInfo().isQtMultimediaSoundEffect()) { // if dropping into on an existing SoundEffect, update @@ -2268,7 +2236,6 @@ ModelNode handleItemLibrarySoundDrop(const QString &soundPath, } ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath, - NodeAbstractProperty targetProperty, const ModelNode &targetNode, bool &outMoveNodesAfter) { @@ -2279,24 +2246,9 @@ ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath, if (!view->model()->hasImport(import, true, true)) return {}; - const QString imagePath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath( - tex3DPath); // relative to qml file - ModelNode newModelNode; - if (!dropAsImage3dTexture(targetNode, - targetProperty, - imagePath, - newModelNode, - outMoveNodesAfter)) { - view->executeInTransaction("NavigatorTreeModel::handleItemLibraryTexture3dDrop", [&] { - // create a standalone Texture3D at drop location - newModelNode = createTextureNode(targetProperty, imagePath); - if (!NodeHints::fromModelNode(targetProperty.parentModelNode()) - .canBeContainerFor(newModelNode)) - newModelNode.destroy(); - }); - } + dropAsImage3dTexture(targetNode, tex3DPath, newModelNode, outMoveNodesAfter); return newModelNode; } diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h index d8cf8fe6230..8b3d411c05f 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -160,7 +160,6 @@ ModelNode handleItemLibrarySoundDrop(const QString &soundPath, NodeAbstractProperty targetProperty, const ModelNode &targetNode); ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath, - NodeAbstractProperty targetProperty, const ModelNode &targetNode, bool &outMoveNodesAfter); diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 341f3694857..8e5a279ea03 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -177,8 +177,8 @@ static void reparentModelNodeToNodeProperty(NodeAbstractProperty &parentProperty } } -NavigatorTreeModel::NavigatorTreeModel(QObject *parent) : QAbstractItemModel(parent) - , m_createTextures(Utils::makeUniqueObjectPtr(m_view)) +NavigatorTreeModel::NavigatorTreeModel(QObject *parent) + : QAbstractItemModel(parent) { m_actionManager = &QmlDesignerPlugin::instance()->viewManager().designerActionManager(); } @@ -583,17 +583,10 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, bool moveNodesAfter = false; m_view->executeInTransaction(__FUNCTION__, [&] { - m_createTextures->execute(QStringList{texturePath}, - AddTextureMode::Image, - Utils3D::active3DSceneId(m_view->model())); - QString textureName = Utils::FilePath::fromString(texturePath).fileName(); - QString textureAbsolutePath = DocumentManager::currentResourcePath() - .pathAppended("images/" + textureName).toString(); - ModelNodeOperations::handleItemLibraryImageDrop(textureAbsolutePath, - targetProperty, - modelNodeForIndex( - rowModelIndex), - moveNodesAfter); + ModelNodeOperations::handleItemLibraryTexture3dDrop(texturePath, + modelNodeForIndex( + rowModelIndex), + moveNodesAfter); }); } } @@ -664,7 +657,6 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, } else if (assetType == Constants::MIME_TYPE_ASSET_TEXTURE3D) { currNode = ModelNodeOperations::handleItemLibraryTexture3dDrop( assetPath, - targetProperty, modelNodeForIndex(rowModelIndex), moveNodesAfter); } else if (assetType == Constants::MIME_TYPE_ASSET_EFFECT) { @@ -853,34 +845,6 @@ bool QmlDesigner::NavigatorTreeModel::moveNodeToParent(const NodeAbstractPropert return false; } -ModelNode NavigatorTreeModel::createTextureNode(const NodeAbstractProperty &targetProp, - const QString &imagePath) -{ - if (targetProp.isValid()) { - // create a texture item lib - ItemLibraryEntry itemLibraryEntry; - itemLibraryEntry.setName("Texture"); - itemLibraryEntry.setType("QtQuick3D.Texture", 1, 0); - - // set texture source - PropertyName prop = "source"; - QString type = "QUrl"; - QVariant val = imagePath; - itemLibraryEntry.addProperty(prop, type, val); - - // create a texture - ModelNode newModelNode = QmlItemNode::createQmlObjectNode(m_view, itemLibraryEntry, {}, - targetProp, false); - - // Rename the node based on source image - QFileInfo fi(imagePath); - newModelNode.setIdWithoutRefactoring( - m_view->model()->generateNewId(fi.baseName(), "textureImage")); - return newModelNode; - } - return {}; -} - namespace { NodeMetaInfo propertyType(const NodeAbstractProperty &property) { diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h index 7e6df8b2ec1..6674397c77a 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h @@ -96,9 +96,11 @@ private: void handleInternalDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); void handleItemLibraryItemDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); - bool dropAsImage3dTexture(const ModelNode &targetNode, const NodeAbstractProperty &targetProp, - const QString &imagePath, ModelNode &newNode, bool &outMoveNodesAfter); - ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath); + bool dropAsImage3dTexture(const ModelNode &targetNode, + const NodeAbstractProperty &targetProp, + const QString &imagePath, + ModelNode &newNode, + bool &outMoveNodesAfter); QList nodesToPersistentIndex(const QList &modelNodes); void addImport(const QString &importName); QList filteredList(const NodeListProperty &property, bool filter, bool reverseOrder) const; diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp index 96b518fab35..08cad3b0182 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp +++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp @@ -341,7 +341,6 @@ void TextEditorWidget::dropEvent(QDropEvent *dropEvent) targetNode); } else if (assetType == Constants::MIME_TYPE_ASSET_TEXTURE3D) { newModelNode = ModelNodeOperations::handleItemLibraryTexture3dDrop(assetPath, - targetProperty, targetNode, moveNodesAfter); } else if (assetType == Constants::MIME_TYPE_ASSET_EFFECT) { From d0b97d91fc0f2a661fef0d034483aad8d7f35f63 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Thu, 26 Sep 2024 12:02:24 +0300 Subject: [PATCH 11/44] QmlDesigner: Cleanup CreateTexture CreateTexture doesn't need to be a QObject. It is easier to take care of its destruction if it is not a QObject. Also there were a couple of non-related methods, that can be placed in Utils3D. Change-Id: Ie0aaf372d5572ac1a2d437f05bdd866bc705e861 Reviewed-by: Mahmoud Badri Reviewed-by: Miikka Heikkinen --- .../assetslibrary/assetslibrarywidget.cpp | 21 ++++--- .../assetslibrary/assetslibrarywidget.h | 2 - .../componentcore/createtexture.cpp | 56 +++---------------- .../components/componentcore/createtexture.h | 16 +----- .../componentcore/modelnodeoperations.cpp | 6 +- .../components/componentcore/utils3d.cpp | 37 ++++++++++++ .../components/componentcore/utils3d.h | 4 ++ .../contentlibrary/contentlibraryview.cpp | 17 +++--- .../contentlibrary/contentlibraryview.h | 1 - .../materialbrowser/materialbrowserview.cpp | 27 ++++----- .../materialbrowser/materialbrowserwidget.cpp | 18 ++---- .../components/navigator/navigatortreemodel.h | 4 +- .../propertyeditor/propertyeditorvalue.cpp | 5 +- .../textureeditor/textureeditorview.cpp | 5 +- .../textureeditor/textureeditorview.h | 2 - 15 files changed, 98 insertions(+), 123 deletions(-) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 50dbbc878e1..e7d1e431633 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -7,6 +7,7 @@ #include "assetslibrarymodel.h" #include "assetslibraryview.h" +#include #include #include #include @@ -100,7 +101,6 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFon , m_assetsIconProvider{new AssetsLibraryIconProvider(synchronousFontImageCache)} , m_assetsModel{new AssetsLibraryModel(this)} , m_assetsView{view} - , m_createTextures{view} , m_assetsWidget{Utils::makeUniqueObjectPtr(this)} { setWindowTitle(tr("Assets Library", "Title of assets library widget")); @@ -231,18 +231,20 @@ int AssetsLibraryWidget::qtVersion() const void AssetsLibraryWidget::addTextures(const QStringList &filePaths) { m_assetsView->executeInTransaction(__FUNCTION__, [&] { - m_createTextures.execute(filePaths, - AddTextureMode::Texture, - Utils3D::active3DSceneId(m_assetsView->model())); + CreateTexture(m_assetsView) + .execute(filePaths, + AddTextureMode::Texture, + Utils3D::active3DSceneId(m_assetsView->model())); }); } void AssetsLibraryWidget::addLightProbe(const QString &filePath) { m_assetsView->executeInTransaction(__FUNCTION__, [&] { - m_createTextures.execute({filePath}, - AddTextureMode::LightProbe, - Utils3D::active3DSceneId(m_assetsView->model())); + CreateTexture(m_assetsView) + .execute(filePath, + AddTextureMode::LightProbe, + Utils3D::active3DSceneId(m_assetsView->model())); }); } @@ -251,8 +253,9 @@ void AssetsLibraryWidget::updateContextMenuActionsEnableState() setHasMaterialLibrary(Utils3D::materialLibraryNode(m_assetsView).isValid() && m_assetsView->model()->hasImport("QtQuick3D")); - ModelNode activeSceneEnv = m_createTextures.resolveSceneEnv( - Utils3D::active3DSceneId(m_assetsView->model())); + ModelNode activeSceneEnv = Utils3D::resolveSceneEnv(m_assetsView, + Utils3D::active3DSceneId( + m_assetsView->model())); setHasSceneEnv(activeSceneEnv.isValid()); } diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h index 79deeb9efd3..5456fb139b4 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h @@ -3,7 +3,6 @@ #pragma once -#include "createtexture.h" #include "previewtooltipbackend.h" #include @@ -135,7 +134,6 @@ private: AssetsLibraryIconProvider *m_assetsIconProvider = nullptr; AssetsLibraryModel *m_assetsModel = nullptr; AssetsLibraryView *m_assetsView = nullptr; - CreateTextures m_createTextures = nullptr; Utils::UniqueObjectPtr m_assetsWidget; std::unique_ptr m_fontPreviewTooltipBackend; diff --git a/src/plugins/qmldesigner/components/componentcore/createtexture.cpp b/src/plugins/qmldesigner/components/componentcore/createtexture.cpp index f595e0e47e7..cd8ea6cfd78 100644 --- a/src/plugins/qmldesigner/components/componentcore/createtexture.cpp +++ b/src/plugins/qmldesigner/components/componentcore/createtexture.cpp @@ -114,10 +114,10 @@ ModelNode CreateTexture::execute(const QString &filePath, AddTextureMode mode, i return {}; if (mode == AddTextureMode::LightProbe && sceneId != -1) - assignTextureAsLightProbe(texture, sceneId); + Utils3D::assignTextureAsLightProbe(m_view, texture, sceneId); - QTimer::singleShot(0, m_view, [this, texture]() { - if (m_view->model() && texture.isValid()) { + QTimer::singleShot(0, m_view, [view = m_view, texture]() { + if (view && view->model() && texture.isValid()) { QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialBrowser"); Utils3D::selectTexture(texture); } @@ -210,6 +210,12 @@ ModelNode CreateTexture::execute(const ModelNode &texture) return duplicateTextureNode; } +void CreateTexture::execute(const QStringList &filePaths, AddTextureMode mode, int sceneId) +{ + for (const QString &path : filePaths) + execute(path, mode, sceneId); +} + bool CreateTexture::addFileToProject(const QString &filePath) { AddFilesResult result = ModelNodeOperations::addImageToProject( @@ -260,48 +266,4 @@ ModelNode CreateTexture::createTextureFromImage(const Utils::FilePath &assetPat return newTexNode; } -void CreateTexture::assignTextureAsLightProbe(const ModelNode &texture, int sceneId) -{ - ModelNode sceneEnvNode = resolveSceneEnv(sceneId); - QmlObjectNode sceneEnv = sceneEnvNode; - if (sceneEnv.isValid()) { - sceneEnv.setBindingProperty("lightProbe", texture.id()); - sceneEnv.setVariantProperty("backgroundMode", - QVariant::fromValue(Enumeration("SceneEnvironment", - "SkyBox"))); - } -} - -ModelNode CreateTexture::resolveSceneEnv(int sceneId) -{ - ModelNode activeSceneEnv; - ModelNode selectedNode = m_view->firstSelectedModelNode(); - - if (selectedNode.metaInfo().isQtQuick3DSceneEnvironment()) { - activeSceneEnv = selectedNode; - } else if (sceneId != -1) { - ModelNode activeScene = Utils3D::active3DSceneNode(m_view); - if (activeScene.isValid()) { - QmlObjectNode view3D; - if (activeScene.metaInfo().isQtQuick3DView3D()) { - view3D = activeScene; - } else { - ModelNode sceneParent = activeScene.parentProperty().parentModelNode(); - if (sceneParent.metaInfo().isQtQuick3DView3D()) - view3D = sceneParent; - } - if (view3D.isValid()) - activeSceneEnv = m_view->modelNodeForId(view3D.expression("environment")); - } - } - - return activeSceneEnv; -} - -void CreateTextures::execute(const QStringList &filePaths, AddTextureMode mode, int sceneId) -{ - for (const QString &path : filePaths) - CreateTexture::execute(path, mode, sceneId); -} - } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/createtexture.h b/src/plugins/qmldesigner/components/componentcore/createtexture.h index 450a7f7a0db..57ef9893cc0 100644 --- a/src/plugins/qmldesigner/components/componentcore/createtexture.h +++ b/src/plugins/qmldesigner/components/componentcore/createtexture.h @@ -3,7 +3,7 @@ #pragma once -#include +#include namespace Utils { class FilePath; @@ -16,10 +16,8 @@ class ModelNode; enum class AddTextureMode { Image, Texture, LightProbe }; -class CreateTexture : public QObject +class CreateTexture { - Q_OBJECT - public: CreateTexture(AbstractView *view); @@ -28,8 +26,7 @@ public: AddTextureMode mode = AddTextureMode::Texture, int sceneId = -1); ModelNode execute(const ModelNode &texture); - ModelNode resolveSceneEnv(int sceneId); - void assignTextureAsLightProbe(const ModelNode &texture, int sceneId); + void execute(const QStringList &filePaths, AddTextureMode mode, int sceneId = -1); private: bool addFileToProject(const QString &filePath); @@ -38,11 +35,4 @@ private: AbstractView *m_view = nullptr; }; -class CreateTextures : public CreateTexture -{ -public: - using CreateTexture::CreateTexture; - void execute(const QStringList &filePaths, AddTextureMode mode, int sceneId = -1); -}; - } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index dcf690e74a1..4f5bdab700d 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -1915,10 +1915,8 @@ ModelNode createTextureNode(AbstractView *view, const QString &imagePath) { QTC_ASSERT(view, return {}); - auto textureCreator = new CreateTexture(view); - ModelNode texture = textureCreator->execute(imagePath, AddTextureMode::Texture); - textureCreator->deleteLater(); - return texture; + CreateTexture textureCreator(view); + return textureCreator.execute(imagePath, AddTextureMode::Texture); } bool dropAsImage3dTexture(const ModelNode &targetNode, diff --git a/src/plugins/qmldesigner/components/componentcore/utils3d.cpp b/src/plugins/qmldesigner/components/componentcore/utils3d.cpp index 7ddd0997cdf..e38fd544084 100644 --- a/src/plugins/qmldesigner/components/componentcore/utils3d.cpp +++ b/src/plugins/qmldesigner/components/componentcore/utils3d.cpp @@ -252,6 +252,43 @@ void applyMaterialToModels(AbstractView *view, const ModelNode &material, }); } +ModelNode resolveSceneEnv(AbstractView *view, int sceneId) +{ + ModelNode activeSceneEnv; + ModelNode selectedNode = view->firstSelectedModelNode(); + + if (selectedNode.metaInfo().isQtQuick3DSceneEnvironment()) { + activeSceneEnv = selectedNode; + } else if (sceneId != -1) { + ModelNode activeScene = Utils3D::active3DSceneNode(view); + if (activeScene.isValid()) { + QmlObjectNode view3D; + if (activeScene.metaInfo().isQtQuick3DView3D()) { + view3D = activeScene; + } else { + ModelNode sceneParent = activeScene.parentProperty().parentModelNode(); + if (sceneParent.metaInfo().isQtQuick3DView3D()) + view3D = sceneParent; + } + if (view3D.isValid()) + activeSceneEnv = view->modelNodeForId(view3D.expression("environment")); + } + } + + return activeSceneEnv; +} + +void assignTextureAsLightProbe(AbstractView *view, const ModelNode &texture, int sceneId) +{ + ModelNode sceneEnvNode = resolveSceneEnv(view, sceneId); + QmlObjectNode sceneEnv = sceneEnvNode; + if (sceneEnv.isValid()) { + sceneEnv.setBindingProperty("lightProbe", texture.id()); + sceneEnv.setVariantProperty("backgroundMode", + QVariant::fromValue(Enumeration("SceneEnvironment", "SkyBox"))); + } +} + // This method should be executed within a transaction as it performs multiple modifications to the model #ifdef QDS_USE_PROJECTSTORAGE ModelNode createMaterial(AbstractView *view, const TypeName &typeName) diff --git a/src/plugins/qmldesigner/components/componentcore/utils3d.h b/src/plugins/qmldesigner/components/componentcore/utils3d.h index 546c90f8e70..6a7899589c3 100644 --- a/src/plugins/qmldesigner/components/componentcore/utils3d.h +++ b/src/plugins/qmldesigner/components/componentcore/utils3d.h @@ -40,10 +40,14 @@ void selectTexture(const ModelNode &texture); ModelNode selectedMaterial(AbstractView *view); ModelNode selectedTexture(AbstractView *view); +ModelNode resolveSceneEnv(AbstractView *view, int sceneId); + QList getSelectedModels(AbstractView *view); void applyMaterialToModels(AbstractView *view, const ModelNode &material, const QList &models, bool add = false); +void assignTextureAsLightProbe(AbstractView *view, const ModelNode &texture, int sceneId); + #ifdef QDS_USE_PROJECTSTORAGE ModelNode createMaterial(AbstractView *view, const TypeName &typeName); #else diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp index 4bcf9e7fd9e..55c96dd9b4b 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp @@ -57,7 +57,6 @@ ContentLibraryView::ContentLibraryView(AsynchronousImageCache &imageCache, ExternalDependenciesInterface &externalDependencies) : AbstractView(externalDependencies) , m_imageCache(imageCache) - , m_createTexture(this) {} ContentLibraryView::~ContentLibraryView() @@ -88,15 +87,17 @@ WidgetInfo ContentLibraryView::widgetInfo() m_draggedBundleItem = item; }); - connect(m_widget, &ContentLibraryWidget::addTextureRequested, this, - [&] (const QString &texPath, AddTextureMode mode) { - executeInTransaction("ContentLibraryView::widgetInfo", [&]() { - m_createTexture.execute(texPath, mode, m_sceneId); - }); - }); + connect(m_widget, + &ContentLibraryWidget::addTextureRequested, + this, + [&](const QString &texPath, AddTextureMode mode) { + executeInTransaction("ContentLibraryView::widgetInfo", [&]() { + CreateTexture(this).execute(texPath, mode, m_sceneId); + }); + }); connect(m_widget, &ContentLibraryWidget::updateSceneEnvStateRequested, this, [&]() { - ModelNode activeSceneEnv = m_createTexture.resolveSceneEnv(m_sceneId); + ModelNode activeSceneEnv = Utils3D::resolveSceneEnv(this, m_sceneId); const bool sceneEnvExists = activeSceneEnv.isValid(); m_widget->texturesModel()->setHasSceneEnv(sceneEnvExists); m_widget->environmentsModel()->setHasSceneEnv(sceneEnvExists); diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h index deba7b93a61..f42423fd7d2 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h @@ -90,7 +90,6 @@ private: bool m_bundleMaterialAddToSelected = false; bool m_hasQuick3DImport = false; qint32 m_sceneId = -1; - CreateTexture m_createTexture; Utils::FilePath m_iconSavePath; QString m_generatedFolderName; QString m_bundleId; diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 8d28cea7ca3..e736427139f 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -210,7 +210,7 @@ WidgetInfo MaterialBrowserView::widgetInfo() }); connect(texturesModel, &MaterialBrowserTexturesModel::updateSceneEnvStateRequested, this, [&]() { - ModelNode activeSceneEnv = CreateTexture(this).resolveSceneEnv(m_sceneId); + ModelNode activeSceneEnv = Utils3D::resolveSceneEnv(this, m_sceneId); const bool sceneEnvExists = activeSceneEnv.isValid(); m_widget->materialBrowserTexturesModel()->setHasSceneEnv(sceneEnvExists); }); @@ -223,12 +223,14 @@ WidgetInfo MaterialBrowserView::widgetInfo() m_widget->materialBrowserTexturesModel()->setHasSingleModelSelection(hasModel); }); - connect(texturesModel, &MaterialBrowserTexturesModel::applyAsLightProbeRequested, this, - [&] (const ModelNode &texture) { - executeInTransaction(__FUNCTION__, [&] { - CreateTexture(this).assignTextureAsLightProbe(texture, m_sceneId); - }); - }); + connect(texturesModel, + &MaterialBrowserTexturesModel::applyAsLightProbeRequested, + this, + [&](const ModelNode &texture) { + executeInTransaction(__FUNCTION__, [&] { + Utils3D::assignTextureAsLightProbe(this, texture, m_sceneId); + }); + }); } return createWidgetInfo(m_widget.data(), @@ -240,13 +242,9 @@ WidgetInfo MaterialBrowserView::widgetInfo() void MaterialBrowserView::createTextures(const QStringList &assetPaths) { - auto *create = new CreateTextures(this); - executeInTransaction("MaterialBrowserView::createTextures", [&]() { - create->execute(assetPaths, AddTextureMode::Texture, m_sceneId); + CreateTexture(this).execute(assetPaths, AddTextureMode::Texture, m_sceneId); }); - - create->deleteLater(); } void MaterialBrowserView::modelAttached(Model *model) @@ -741,11 +739,10 @@ void MaterialBrowserView::applyTextureToProperty(const QString &matId, const QSt { executeInTransaction(__FUNCTION__, [&] { if (m_appliedTextureId.isEmpty() && !m_appliedTexturePath.isEmpty()) { - auto texCreator = new CreateTexture(this); - ModelNode tex = texCreator->execute(m_appliedTexturePath, AddTextureMode::Texture); + CreateTexture texCreator(this); + ModelNode tex = texCreator.execute(m_appliedTexturePath, AddTextureMode::Texture); m_appliedTextureId = tex.id(); m_appliedTexturePath.clear(); - texCreator->deleteLater(); } QTC_ASSERT(!m_appliedTextureId.isEmpty(), return); diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp index a97bf591459..54aff337002 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp @@ -300,10 +300,8 @@ void MaterialBrowserWidget::acceptBundleTextureDropOnMaterial(int matIndex, cons ModelNode mat = m_materialBrowserModel->materialAt(matIndex); QTC_ASSERT(mat.isValid(), return); - auto *creator = new CreateTexture(m_materialBrowserView); - m_materialBrowserView->executeInTransaction(__FUNCTION__, [&] { - ModelNode tex = creator->execute(bundleTexPath.toLocalFile()); + ModelNode tex = CreateTexture(m_materialBrowserView).execute(bundleTexPath.toLocalFile()); QTC_ASSERT(tex.isValid(), return); m_materialBrowserModel->selectMaterial(matIndex); @@ -312,8 +310,6 @@ void MaterialBrowserWidget::acceptBundleTextureDropOnMaterial(int matIndex, cons if (m_materialBrowserView->model()) m_materialBrowserView->model()->endDrag(); - - creator->deleteLater(); } void MaterialBrowserWidget::acceptAssetsDrop(const QList &urls) @@ -329,14 +325,12 @@ void MaterialBrowserWidget::acceptAssetsDropOnMaterial(int matIndex, const QList ModelNode mat = m_materialBrowserModel->materialAt(matIndex); QTC_ASSERT(mat.isValid(), return); - auto *creator = new CreateTexture(m_materialBrowserView); - - QString imageSrc = Utils::findOrDefault(urls, [] (const QUrl &url) { - return Asset(url.toLocalFile()).isValidTextureSource(); - }).toLocalFile(); + QString imageSrc = Utils::findOrDefault(urls, [](const QUrl &url) { + return Asset(url.toLocalFile()).isValidTextureSource(); + }).toLocalFile(); m_materialBrowserView->executeInTransaction(__FUNCTION__, [&] { - ModelNode tex = creator->execute(imageSrc); + ModelNode tex = CreateTexture(m_materialBrowserView).execute(imageSrc); QTC_ASSERT(tex.isValid(), return); m_materialBrowserModel->selectMaterial(matIndex); @@ -345,8 +339,6 @@ void MaterialBrowserWidget::acceptAssetsDropOnMaterial(int matIndex, const QList if (m_materialBrowserView->model()) m_materialBrowserView->model()->endDrag(); - - creator->deleteLater(); } void MaterialBrowserWidget::acceptTextureDropOnMaterial(int matIndex, const QString &texId) diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h index 6674397c77a..350b72dd608 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h @@ -17,7 +17,6 @@ QT_FORWARD_DECLARE_CLASS(QPixmap) namespace QmlDesigner { -class CreateTextures; class DesignerActionManager; class Model; class ModelNode; @@ -88,7 +87,7 @@ public: void updateToolTipPixmap(const ModelNode &node, const QPixmap &pixmap); signals: - void toolTipPixmapUpdated(const QString &id, const QPixmap &pixmap) const; + void toolTipPixmapUpdated(const QString &id, const QPixmap &pixmap); private: void moveNodesInteractive(NodeAbstractProperty &parentProperty, const QList &modelNodes, @@ -107,7 +106,6 @@ private: bool moveNodeToParent(const NodeAbstractProperty &targetProperty, const ModelNode &newModelNode); QPointer m_view; - Utils::UniqueObjectPtr m_createTextures; mutable QHash m_nodeIndexHash; mutable QHash > m_rowCache; bool m_showOnlyVisibleItems = true; diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp index 767d97be673..74c1ba65a60 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp @@ -521,9 +521,8 @@ void PropertyEditorValue::commitDrop(const QString &dropData) m_modelNode.view()->executeInTransaction(__FUNCTION__, [&] { ModelNode texture = m_modelNode.view()->modelNodeForInternalId(dropData.toInt()); if (!texture || !texture.metaInfo().isQtQuick3DTexture()) { - auto texCreator = new CreateTexture(m_modelNode.view()); - texture = texCreator->execute(dropData, AddTextureMode::Texture); - texCreator->deleteLater(); + CreateTexture texCreator(m_modelNode.view()); + texture = texCreator.execute(dropData, AddTextureMode::Texture); } // assign the texture to the property diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp index 94c150626d6..64b1523303e 100644 --- a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp +++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp @@ -58,7 +58,6 @@ TextureEditorView::TextureEditorView(AsynchronousImageCache &imageCache, : AbstractView{externalDependencies} , m_imageCache(imageCache) , m_stackedWidget(new QStackedWidget) - , m_createTexture(new CreateTexture(this)) , m_dynamicPropertiesModel(new DynamicPropertiesModel(true, this)) { m_updateShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_F12), m_stackedWidget); @@ -399,7 +398,7 @@ void TextureEditorView::handleToolBarAction(int action) case TextureEditorContextObject::AddNewTexture: { if (!model()) break; - m_createTexture->execute(); + CreateTexture(this).execute(); break; } @@ -845,7 +844,7 @@ void TextureEditorView::importsChanged([[maybe_unused]] const Imports &addedImpo void TextureEditorView::duplicateTexture(const ModelNode &texture) { QTC_ASSERT(texture.isValid(), return); - m_createTexture->execute(texture); + CreateTexture(this).execute(texture); } void TextureEditorView::customNotification([[maybe_unused]] const AbstractView *view, diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h index 5611cf3ab6b..00336998b6c 100644 --- a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h +++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h @@ -18,7 +18,6 @@ QT_END_NAMESPACE namespace QmlDesigner { -class CreateTexture; class DynamicPropertiesModel; class ModelNode; class QmlObjectNode; @@ -126,7 +125,6 @@ private: bool m_selectedTextureChanged = false; QPointer m_colorDialog; - QPointer m_createTexture; DynamicPropertiesModel *m_dynamicPropertiesModel = nullptr; }; From 5b67904e9ffebddbe4d4b86223706f3a5c7170f3 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 20 Sep 2024 13:55:43 +0200 Subject: [PATCH 12/44] QmlDesigner: Add JavaScript files for content dir Task-number: QDS-12652 Change-Id: I780cf813a5292a76b9877ca024af2e29b8968ddb Reviewed-by: Thomas Hartmann --- .../studio_templates/projects/common/app.qmlproject.tpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl index 58afba69c34..7e4e70fb9b9 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl @@ -22,7 +22,7 @@ Project { } JavaScriptFiles { - directory: "%{ProjectName}" + directory: "%{ContentDir}" } ImageFiles { From 684e5d05286b7a1608ed95a6a2635d28069ed227 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 27 Sep 2024 13:42:05 +0200 Subject: [PATCH 13/44] QmlDesigner: Add QTC_CHECK if those fail we also want console output in release builds. Change-Id: If0c913ae9f0999219ba933675f794319c1930eec Reviewed-by: Thomas Hartmann --- .../libs/designercore/rewriter/texttomodelmerger.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp b/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp index 27e9fb0102c..c4bfd576291 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp @@ -1810,6 +1810,7 @@ void ModelValidator::shouldBeVariantProperty([[maybe_unused]] AbstractProperty & const QVariant & /*qmlVariantValue*/, const TypeName & /*dynamicTypeName*/) { + QTC_CHECK(modelProperty.isVariantProperty()); Q_ASSERT(modelProperty.isVariantProperty()); Q_ASSERT(0); } @@ -1871,6 +1872,7 @@ void ModelValidator::propertyAbsentFromQml([[maybe_unused]] AbstractProperty &mo { Q_ASSERT(!modelProperty.isValid()); Q_ASSERT(0); + QTC_CHECK(!modelProperty.isValid()); } void ModelValidator::idsDiffer([[maybe_unused]] ModelNode &modelNode, From d0099404ec67c1434671342ef7b46b6629a9b099 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 27 Sep 2024 13:37:15 +0200 Subject: [PATCH 14/44] QmlDesigner: Add checks for lite designer to brand bar Change-Id: I61df5f21c88bfe898d0f3befa37a6a60c9ec48ed Reviewed-by: Thomas Hartmann --- .../qmldesigner/welcomepage/BrandBar.qml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml b/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml index 721e2b06dd9..d57d35ecb20 100644 --- a/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml +++ b/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml @@ -32,6 +32,7 @@ Item { } Text { + visible: !Constants.projectModel.liteDesignerEnabled id: brandLabel color: Constants.currentBrand text: qsTr("Qt Design Studio") @@ -44,6 +45,20 @@ Item { } Text { + visible: Constants.projectModel.liteDesignerEnabled + id: brandLabelLite + color: Constants.currentBrand + text: qsTr("Lite QML Designer") + anchors.verticalCenter: parent.verticalCenter + anchors.left: welcomeTo.right + anchors.leftMargin: 8 + verticalAlignment: Text.AlignVCenter + font.pixelSize: 36 + font.family: "titillium web" + } + + Text { + visible: !Constants.projectModel.liteDesignerEnabled width: 291 height: 55 color: Constants.currentGlobalText From 6820b892276c4fedaf67453d0d69c5e5a299be28 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Wed, 18 Sep 2024 12:45:41 +0200 Subject: [PATCH 15/44] QmlDesigner: More integration cleanup Instead of a warning we now provide different functions for the project storage. Should give better errors. Change-Id: I48cea16482950c2b3c5eea3e72d4e9c40b9e75b2 Reviewed-by: Thomas Hartmann --- src/plugins/insight/insightmodel.cpp | 27 +- src/plugins/insight/insightmodel.h | 5 +- src/plugins/insight/insightplugin.cpp | 3 +- src/plugins/insight/insightview.cpp | 5 +- src/plugins/insight/insightview.h | 4 +- src/plugins/qmldesigner/CMakeLists.txt | 3 +- .../assetexporterplugin/assetexporter.cpp | 23 +- .../assetexporterplugin/assetexporter.h | 6 +- .../assetexporterplugin.cpp | 9 +- .../assetexporterplugin/assetexporterplugin.h | 1 + .../assetexporterplugin/componentexporter.cpp | 16 +- .../assetexporterplugin/componentexporter.h | 6 +- .../dumpers/assetnodedumper.cpp | 12 +- .../dumpers/assetnodedumper.h | 2 +- .../dumpers/itemnodedumper.cpp | 8 +- .../dumpers/itemnodedumper.h | 2 +- .../dumpers/nodedumper.cpp | 9 +- .../assetexporterplugin/dumpers/nodedumper.h | 9 +- .../dumpers/textnodedumper.cpp | 14 +- .../dumpers/textnodedumper.h | 2 +- .../itemlibrary/itemlibrarymodel.cpp | 9 +- .../libs/designercore/include/model.h | 48 +- .../libs/designercore/include/nodemetainfo.h | 45 +- .../designercore/metainfo/nodemetainfo.cpp | 799 +++++++++--------- .../libs/designercore/model/model.cpp | 42 +- .../libs/designercore/model/modelnode.cpp | 16 +- .../projectstorage/commontypecache.h | 2 + src/plugins/qmldesigner/qmldesignerplugin.cpp | 5 + src/plugins/qmldesigner/qmldesignerplugin.h | 2 + .../qmldesigner/qmldesignerprojectmanager.h | 3 +- 30 files changed, 600 insertions(+), 537 deletions(-) diff --git a/src/plugins/insight/insightmodel.cpp b/src/plugins/insight/insightmodel.cpp index 50474ffecff..3a4d03124ce 100644 --- a/src/plugins/insight/insightmodel.cpp +++ b/src/plugins/insight/insightmodel.cpp @@ -7,9 +7,10 @@ #include #include #include +#include +#include #include #include -#include #include #include @@ -192,7 +193,9 @@ Qt::CheckState checkState(const std::vector &a, const std::vectorsetCheckLinkErrors(false); rewriter->setTextModifier(modifier.get()); +#ifdef QDS_USE_PROJECTSTORAGE + model = QmlDesigner::Model::create(projectStorageDependencies, + "Item", + {Import::createLibraryImport("QtQuick")}, + filePath); +#else model = QmlDesigner::Model::create("QtQuick.Item", 2, 1); +#endif model->setRewriterView(rewriter.get()); } @@ -221,9 +231,12 @@ struct ModelBuilder } // namespace -InsightModel::InsightModel(InsightView *view, ExternalDependenciesInterface &externalDependencies) +InsightModel::InsightModel(InsightView *view, + ExternalDependenciesInterface &externalDependencies, + QmlDesignerProjectManager &projectManager) : m_insightView(view) , m_externalDependencies(externalDependencies) + , m_projectManager(projectManager) , m_fileSystemWatcher(new Utils::FileSystemWatcher(this)) { QObject::connect(ProjectExplorer::ProjectManager::instance(), @@ -446,7 +459,9 @@ void InsightModel::setEnabled(bool value) return; } - ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(), m_externalDependencies); + ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(), + m_externalDependencies, + m_projectManager.projectStorageDependencies()); if (!builder.model) { qWarning() << "Could not create model" << m_mainQmlInfo.absoluteFilePath(); @@ -613,7 +628,9 @@ int InsightModel::devicePixelRatio() void InsightModel::parseMainQml() { - ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(), m_externalDependencies); + ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(), + m_externalDependencies, + m_projectManager.projectStorageDependencies()); if (!builder.model) return; diff --git a/src/plugins/insight/insightmodel.h b/src/plugins/insight/insightmodel.h index b21d7e36205..302d79e25b4 100644 --- a/src/plugins/insight/insightmodel.h +++ b/src/plugins/insight/insightmodel.h @@ -39,7 +39,9 @@ class InsightModel : public QAbstractListModel }; public: - InsightModel(InsightView *view, class ExternalDependenciesInterface &externalDependencies); + InsightModel(InsightView *view, + class ExternalDependenciesInterface &externalDependencies, + class QmlDesignerProjectManager &projectManager); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; @@ -109,6 +111,7 @@ private: private: QPointer m_insightView; ExternalDependenciesInterface &m_externalDependencies; + QmlDesignerProjectManager &m_projectManager; Utils::FileSystemWatcher *m_fileSystemWatcher; diff --git a/src/plugins/insight/insightplugin.cpp b/src/plugins/insight/insightplugin.cpp index f3bbcf5fa5c..a7172d807cf 100644 --- a/src/plugins/insight/insightplugin.cpp +++ b/src/plugins/insight/insightplugin.cpp @@ -20,7 +20,8 @@ class InsightPlugin final : public ExtensionSystem::IPlugin auto *designerPlugin = QmlDesignerPlugin::instance(); auto &viewManager = designerPlugin->viewManager(); viewManager.registerView(std::make_unique( - QmlDesignerPlugin::externalDependenciesForPluginInitializationOnly())); + QmlDesignerPlugin::externalDependenciesForPluginInitializationOnly(), + QmlDesignerPlugin::projectManagerForPluginInitializationOnly())); return true; } diff --git a/src/plugins/insight/insightview.cpp b/src/plugins/insight/insightview.cpp index 28101dc94e3..8a4dd5d19ec 100644 --- a/src/plugins/insight/insightview.cpp +++ b/src/plugins/insight/insightview.cpp @@ -14,9 +14,10 @@ namespace QmlDesigner { -InsightView::InsightView(ExternalDependenciesInterface &externalDependencies) +InsightView::InsightView(ExternalDependenciesInterface &externalDependencies, + QmlDesignerProjectManager &projectManager) : AbstractView(externalDependencies) - , m_insightModel(std::make_unique(this, externalDependencies)) + , m_insightModel(std::make_unique(this, externalDependencies, projectManager)) { Q_ASSERT(m_insightModel); } diff --git a/src/plugins/insight/insightview.h b/src/plugins/insight/insightview.h index e39f34239c2..00f2877d234 100644 --- a/src/plugins/insight/insightview.h +++ b/src/plugins/insight/insightview.h @@ -15,13 +15,15 @@ namespace QmlDesigner { class InsightModel; class InsightWidget; +class QmlDesignerProjectManager; class InsightView : public AbstractView { Q_OBJECT public: - explicit InsightView(ExternalDependenciesInterface &externalDependencies); + explicit InsightView(ExternalDependenciesInterface &externalDependencies, + QmlDesignerProjectManager &projectManager); ~InsightView() override; // AbstractView diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 3a005e763b5..4ee17a05dff 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -56,9 +56,10 @@ add_qtc_plugin(QmlDesigner DEFINES IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\" SHARE_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/../../../share/qtcreator/qmldesigner" - $<$:QDS_USE_PROJECTSTORAGE> $<$:QTC_USE_QML_DESIGNER_LITE> $<$:DETACH_DISABLED_VIEWS> + PUBLIC_DEFINES + $<$:QDS_USE_PROJECTSTORAGE> INCLUDES ${CMAKE_CURRENT_LIST_DIR}/libs ${CMAKE_CURRENT_LIST_DIR}/components diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp index 8caf85e36c6..286f5a111df 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp @@ -81,13 +81,13 @@ private: std::atomic m_quitDumper; }; - - -AssetExporter::AssetExporter(AssetExporterView *view, ProjectExplorer::Project *project, QObject *parent) : - QObject(parent), - m_currentState(*this), - m_project(project), - m_view(view) +AssetExporter::AssetExporter(AssetExporterView *view, + ProjectExplorer::Project *project, + ProjectStorageDependencies projectStorageDependencies) + : m_currentState(*this) + , m_project(project) + , m_view(view) + , m_projectStorageDependencies{projectStorageDependencies} { connect(m_view, &AssetExporterView::loadingFinished, this, &AssetExporter::onQmlFileLoaded); connect(m_view, &AssetExporterView::loadingError, this, &AssetExporter::notifyLoadError); @@ -257,7 +257,14 @@ void AssetExporter::preprocessQmlFile(const Utils::FilePath &path) { // Load the QML file and assign UUIDs to items having none. // Meanwhile cache the Component UUIDs as well - ModelPointer model(Model::create("Item", 2, 7)); +#ifdef QDS_USE_PROJECTSTORAGE + ModelPointer model = Model::create(m_projectStorageDependencies, + "Item", + {Import::createLibraryImport("QtQuick")}, + path.path()); +#else + ModelPointer model = Model::create("Item", 2, 7); +#endif Utils::FileReader reader; if (!reader.fetch(path)) { ExportNotification::addError(tr("Cannot preprocess file: %1. Error %2") diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h index 7ced4f0ef3b..f8c3c034224 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h @@ -39,8 +39,9 @@ public: ExportingDone }; - AssetExporter(AssetExporterView *view, ProjectExplorer::Project *project, - QObject *parent = nullptr); + AssetExporter(AssetExporterView *view, + ProjectExplorer::Project *project, + ProjectStorageDependencies projectStorageDependencies); ~AssetExporter(); void exportQml(const Utils::FilePaths &qmlFiles, const Utils::FilePath &exportPath, @@ -96,6 +97,7 @@ private: QHash m_componentUuidCache; QSet m_usedHashes; QHash m_assets; + ProjectStorageDependencies m_projectStorageDependencies; std::unique_ptr m_assetDumper; bool m_cancelled = false; }; diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.cpp index ea0899d07c6..6246e0ed36f 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.cpp @@ -3,12 +3,13 @@ #include "assetexporterplugin.h" -#include "assetexportpluginconstants.h" #include "assetexportdialog.h" #include "assetexporter.h" #include "assetexporterview.h" -#include "filepathmodel.h" +#include "assetexportpluginconstants.h" #include "componentexporter.h" +#include "filepathmodel.h" +#include #include "dumpers/itemnodedumper.h" #include "dumpers/textnodedumper.h" @@ -37,6 +38,7 @@ namespace QmlDesigner { AssetExporterPlugin::AssetExporterPlugin() + : m_projectManager{QmlDesigner::QmlDesignerPlugin::projectManagerForPluginInitializationOnly()} { ProjectExplorer::TaskHub::addCategory({Constants::TASK_CATEGORY_ASSET_EXPORT, tr("Asset Export"), @@ -44,6 +46,7 @@ AssetExporterPlugin::AssetExporterPlugin() false}); auto *designerPlugin = QmlDesigner::QmlDesignerPlugin::instance(); + auto &viewManager = designerPlugin->viewManager(); m_view = viewManager.registerView(std::make_unique( designerPlugin->externalDependenciesForPluginInitializationOnly())); @@ -79,7 +82,7 @@ void AssetExporterPlugin::onExport() if (!exportDir.parentDir().isEmpty()) exportDir = exportDir.parentDir(); exportDir = exportDir.pathAppended(startupProject->displayName() + "_export"); - AssetExporter assetExporter(m_view, startupProject); + AssetExporter assetExporter(m_view, startupProject, m_projectManager.projectStorageDependencies()); AssetExportDialog assetExporterDialog(exportDir, assetExporter, model); assetExporterDialog.exec(); } diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.h b/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.h index 9261b4601f8..1c2b779138e 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.h +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.h @@ -29,6 +29,7 @@ private: void updateActions(); AssetExporterView *m_view = nullptr; + class QmlDesignerProjectManager &m_projectManager; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp index 701e9fdd244..5979ea2f657 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp @@ -21,19 +21,6 @@ namespace { Q_LOGGING_CATEGORY(loggerInfo, "qtc.designer.assetExportPlugin.modelExporter", QtInfoMsg) - -static QByteArrayList populateLineage(const QmlDesigner::ModelNode &node) -{ - QByteArrayList lineage; - if (!node.isValid() || node.type().isEmpty()) - return {}; - - for (auto &info : node.metaInfo().prototypes()) - lineage.append(info.typeName()); - - return lineage; -} - } namespace QmlDesigner { @@ -78,10 +65,9 @@ const QString &Component::name() const NodeDumper *Component::createNodeDumper(const ModelNode &node) const { - QByteArrayList lineage = populateLineage(node); std::unique_ptr reader; for (auto &dumperCreator: m_readers) { - std::unique_ptr r(dumperCreator->instance(lineage, node)); + std::unique_ptr r(dumperCreator->instance(node)); if (r->isExportable()) { if (reader) { if (reader->priority() < r->priority()) diff --git a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h index cf816c748c9..59ee8a2e677 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h +++ b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h @@ -27,7 +27,7 @@ class NodeDumperCreatorBase public: virtual ~NodeDumperCreatorBase() {} protected: - virtual NodeDumper *instance(const QByteArrayList &, const ModelNode &) const = 0; + virtual NodeDumper *instance(const ModelNode &) const = 0; friend Component; }; @@ -39,9 +39,7 @@ public: ~NodeDumperCreator() = default; protected: - NodeDumper *instance(const QByteArrayList &lineage, const ModelNode &node) const { - return new T(lineage, node); - } + NodeDumper *instance(const ModelNode &node) const { return new T(node); } }; } //Internal diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.cpp b/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.cpp index fea0f19c801..3fd6cbb333f 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.cpp @@ -14,18 +14,18 @@ namespace QmlDesigner { using namespace Constants; -AssetNodeDumper::AssetNodeDumper(const QByteArrayList &lineage, const ModelNode &node) : - ItemNodeDumper(lineage, node) + +AssetNodeDumper::AssetNodeDumper(const ModelNode &node) + : ItemNodeDumper(node) { } bool AssetNodeDumper::isExportable() const { - auto hasType = [this](const QByteArray &type) { - return lineage().contains(type); - }; - return hasType("QtQuick.Image") || hasType("QtQuick.Rectangle"); + auto qtQuickImageMetaInfo = model()->qtQuickImageMetaInfo(); + auto qtQuickRectangleMetaInfo = model()->qtQuickRectangleMetaInfo(); + return metaInfo().isBasedOn(qtQuickImageMetaInfo, qtQuickRectangleMetaInfo); } QJsonObject AssetNodeDumper::json(Component &component) const diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.h b/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.h index c7bba0b3720..1a5449efafc 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.h +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.h @@ -10,7 +10,7 @@ class Component; class AssetNodeDumper : public ItemNodeDumper { public: - AssetNodeDumper(const QByteArrayList &lineage, const ModelNode &node); + AssetNodeDumper(const ModelNode &node); ~AssetNodeDumper() override = default; bool isExportable() const override; diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.cpp b/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.cpp index 3f5fc4a50c8..e7159d76626 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.cpp @@ -22,16 +22,16 @@ static QString capitalize(const QString &str) namespace QmlDesigner { using namespace Constants; -ItemNodeDumper::ItemNodeDumper(const QByteArrayList &lineage, - const ModelNode &node) : - NodeDumper(lineage, node) + +ItemNodeDumper::ItemNodeDumper(const ModelNode &node) + : NodeDumper(node) { } bool QmlDesigner::ItemNodeDumper::isExportable() const { - return lineage().contains("QtQuick.Item"); + return metaInfo().isQtQuickItem(); } QJsonObject QmlDesigner::ItemNodeDumper::json([[maybe_unused]] QmlDesigner::Component &component) const diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.h b/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.h index 25576bb4067..9752d37caef 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.h +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.h @@ -11,7 +11,7 @@ class Component; class ItemNodeDumper : public NodeDumper { public: - ItemNodeDumper(const QByteArrayList &lineage, const ModelNode &node); + ItemNodeDumper(const ModelNode &node); ~ItemNodeDumper() override = default; diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.cpp b/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.cpp index 390b0684c8c..521180f2f28 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.cpp @@ -6,10 +6,11 @@ #include namespace QmlDesigner { -NodeDumper::NodeDumper(const QByteArrayList &lineage, const ModelNode &node) : - m_node(node), - m_objectNode(node), - m_lineage(lineage) +NodeDumper::NodeDumper(const ModelNode &node) + : m_node(node) + , m_objectNode(node) + , m_metaInfo(node.metaInfo()) + , m_model{node.model()} { } diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.h b/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.h index f735884e5d0..17bace9ad61 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.h +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.h @@ -14,7 +14,7 @@ class ModelNode; class NodeDumper { public: - NodeDumper(const QByteArrayList &lineage, const ModelNode &node); + NodeDumper(const ModelNode &node); virtual ~NodeDumper() = default; @@ -22,16 +22,19 @@ public: virtual bool isExportable() const = 0; virtual QJsonObject json(Component& component) const = 0; - const QByteArrayList& lineage() const { return m_lineage; } + const NodeMetaInfo &metaInfo() const { return m_metaInfo; } const QmlObjectNode& objectNode() const { return m_objectNode; } QVariant propertyValue(const PropertyName &name) const; QString uuid() const; + Model *model() const { return m_model; } + protected: const ModelNode &m_node; private: QmlObjectNode m_objectNode; - QByteArrayList m_lineage; + NodeMetaInfo m_metaInfo; + Model *m_model = nullptr; }; } diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.cpp b/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.cpp index aaf87af73ba..5f96d3e2175 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.cpp @@ -4,6 +4,8 @@ #include "textnodedumper.h" #include "assetexportpluginconstants.h" +#include + #include #include #include @@ -35,18 +37,18 @@ QString toJsonAlignEnum(QString value) { namespace QmlDesigner { using namespace Constants; -TextNodeDumper::TextNodeDumper(const QByteArrayList &lineage, const ModelNode &node) : - ItemNodeDumper(lineage, node) + +TextNodeDumper::TextNodeDumper(const ModelNode &node) + : ItemNodeDumper(node) { } bool TextNodeDumper::isExportable() const { - const QByteArrayList &baseClasses = lineage(); - return std::any_of(baseClasses.cbegin(), baseClasses.cend(), [](const QByteArray &type) { - return type == "QtQuick.Text" || type == "QtQuick.Controls.Label"; - }); + auto qtQuickTextMetaInfo = model()->qtQuickTextMetaInfo(); + auto qtQuickControlsLabelMetaInfo = model()->qtQuickControlsLabelMetaInfo(); + return metaInfo().isBasedOn(qtQuickTextMetaInfo, qtQuickControlsLabelMetaInfo); } QJsonObject TextNodeDumper::json([[maybe_unused]] Component &component) const diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.h b/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.h index efd2ea5ca47..b084bdae48c 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.h +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.h @@ -10,7 +10,7 @@ class Component; class TextNodeDumper : public ItemNodeDumper { public: - TextNodeDumper(const QByteArrayList &lineage, const ModelNode &node); + TextNodeDumper(const ModelNode &node); ~TextNodeDumper() override = default; bool isExportable() const override; diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index 1d9bbf5cd34..0997d06853e 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -376,10 +376,11 @@ void ItemLibraryModel::update(Model *model) for (const ItemLibraryEntry &entry : itemLibEntries) { NodeMetaInfo metaInfo; - if constexpr (useProjectStorage()) - metaInfo = NodeMetaInfo{entry.typeId(), model->projectStorage()}; - else - metaInfo = model->metaInfo(entry.typeName()); +#ifdef QDS_USE_PROJECTSTORAGE + metaInfo = NodeMetaInfo{entry.typeId(), model->projectStorage()}; +#else + metaInfo = model->metaInfo(entry.typeName()); +#endif #ifdef QDS_USE_PROJECTSTORAGE bool valid = metaInfo.isValid(); diff --git a/src/plugins/qmldesigner/libs/designercore/include/model.h b/src/plugins/qmldesigner/libs/designercore/include/model.h index 48ec5c7c4c0..d671c8edbba 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/model.h +++ b/src/plugins/qmldesigner/libs/designercore/include/model.h @@ -24,13 +24,6 @@ #include -#ifdef QDS_USE_PROJECTSTORAGE -# define DEPRECATED_OLD_CREATE_MODELNODE \ - [[deprecated("Use unqualified type names and no versions!")]] -#else -# define DEPRECATED_OLD_CREATE_MODELNODE -#endif - QT_BEGIN_NAMESPACE class QPixmap; class QUrl; @@ -91,31 +84,32 @@ public: Imports imports, const QUrl &fileUrl, std::unique_ptr resourceManagement = {}); +#ifndef QDS_USE_PROJECTSTORAGE Model(const TypeName &typeName, int major = 1, int minor = 1, Model *metaInfoProxyModel = nullptr, std::unique_ptr resourceManagement = {}); - +#endif ~Model(); - DEPRECATED_OLD_CREATE_MODELNODE static ModelPointer create( - const TypeName &typeName, - int major = 1, - int minor = 1, - Model *metaInfoProxyModel = nullptr, - std::unique_ptr resourceManagement = {}) +#ifndef QDS_USE_PROJECTSTORAGE + static ModelPointer create(const TypeName &typeName, + int major = 1, + int minor = 1, + Model *metaInfoProxyModel = nullptr, + std::unique_ptr resourceManagement = {}) { return ModelPointer( new Model(typeName, major, minor, metaInfoProxyModel, std::move(resourceManagement))); } +#endif - static ModelPointer create( - ProjectStorageDependencies projectStorageDependencies, - Utils::SmallStringView typeName, - Imports imports, - const QUrl &fileUrl, - std::unique_ptr resourceManagement = {}) + static ModelPointer create(ProjectStorageDependencies projectStorageDependencies, + Utils::SmallStringView typeName, + Imports imports, + const QUrl &fileUrl, + std::unique_ptr resourceManagement = {}) { return ModelPointer(new Model(projectStorageDependencies, typeName, @@ -124,12 +118,12 @@ public: std::move(resourceManagement))); } - DEPRECATED_OLD_CREATE_MODELNODE static ModelPointer create( - ProjectStorageDependencies projectStorageDependencies, - const TypeName &typeName, - int major = 1, - int minor = 1, - std::unique_ptr resourceManagement = {}) +#ifndef QDS_USE_PROJECTSTORAGE + static ModelPointer create(ProjectStorageDependencies projectStorageDependencies, + const TypeName &typeName, + int major = 1, + int minor = 1, + std::unique_ptr resourceManagement = {}) { return ModelPointer(new Model(projectStorageDependencies, typeName, @@ -138,6 +132,7 @@ public: nullptr, std::move(resourceManagement))); } +#endif ModelPointer createModel(const TypeName &typeName, std::unique_ptr resourceManagement = {}); @@ -188,6 +183,7 @@ public: NodeMetaInfo qtQuick3DTextureMetaInfo() const; NodeMetaInfo qtQuick3DTextureInputMetaInfo() const; NodeMetaInfo qtQuickBorderImageMetaInfo() const; + NodeMetaInfo qtQuickControlsLabelMetaInfo() const; NodeMetaInfo qtQuickControlsTextAreaMetaInfo() const; NodeMetaInfo qtQuickImageMetaInfo() const; NodeMetaInfo qtQuickItemMetaInfo() const; diff --git a/src/plugins/qmldesigner/libs/designercore/include/nodemetainfo.h b/src/plugins/qmldesigner/libs/designercore/include/nodemetainfo.h index fdb29cb10f3..ea01e9438b6 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/nodemetainfo.h +++ b/src/plugins/qmldesigner/libs/designercore/include/nodemetainfo.h @@ -23,22 +23,6 @@ QT_BEGIN_NAMESPACE class QDeclarativeContext; QT_END_NAMESPACE -#ifdef QDS_USE_PROJECTSTORAGE -# define DEPRECATED_TYPENAME [[deprecated("Don't use string based types anymore!")]] -# define DEPRECATED_VERSION_NUMBER \ - [[deprecated( \ - "In most cases you don't need them anymore because the import is setting them!")]] -# define DEPRECATED_COMPONENT_FILE_NAME [[deprecated("Use sourceId() instead.")]] -# define DEPRECATED_IMPORT_DIRECTORY_PATH [[deprecated("Use allExportedTypeNames().")]] -# define DEPRECATED_REQUIRED_IMPORT_STRING [[deprecated("Use allExportedTypeNames().")]] -#else -# define DEPRECATED_TYPENAME -# define DEPRECATED_VERSION_NUMBER -# define DEPRECATED_COMPONENT_FILE_NAME -# define DEPRECATED_IMPORT_DIRECTORY_PATH -# define DEPRECATED_REQUIRED_IMPORT_STRING -#endif - namespace QmlDesigner { class MetaInfo; @@ -54,7 +38,9 @@ class QMLDESIGNERCORE_EXPORT NodeMetaInfo public: NodeMetaInfo(); +#ifndef QDS_USE_PROJECTSTORAGE NodeMetaInfo(Model *model, const TypeName &typeName, int majorVersion, int minorVersion); +#else NodeMetaInfo(TypeId typeId, NotNullPointer projectStorage) : m_typeId{typeId} , m_projectStorage{projectStorage} @@ -62,6 +48,7 @@ public: NodeMetaInfo(NotNullPointer projectStorage) : m_projectStorage{projectStorage} {} +#endif NodeMetaInfo(const NodeMetaInfo &); NodeMetaInfo &operator=(const NodeMetaInfo &); @@ -69,6 +56,7 @@ public: NodeMetaInfo &operator=(NodeMetaInfo &&); ~NodeMetaInfo(); +#ifdef QDS_USE_PROJECTSTORAGE static NodeMetaInfo create(NotNullPointer projectStorage, TypeId typeId) { return {typeId, projectStorage}; @@ -78,6 +66,7 @@ public: { return std::bind_front(&NodeMetaInfo::create, projectStorage); } +#endif bool isValid() const; explicit operator bool() const { return isValid(); } @@ -118,11 +107,12 @@ public: bool defaultPropertyIsComponent() const; QString displayName() const; - DEPRECATED_TYPENAME TypeName typeName() const; - DEPRECATED_TYPENAME TypeName simplifiedTypeName() const; - DEPRECATED_VERSION_NUMBER int majorVersion() const; - DEPRECATED_VERSION_NUMBER int minorVersion() const; - +#ifndef QDS_USE_PROJECTSTORAGE + TypeName typeName() const; + TypeName simplifiedTypeName() const; + int majorVersion() const; + int minorVersion() const; +#endif Storage::Info::ExportedTypeNames allExportedTypeNames() const; Storage::Info::ExportedTypeNames exportedTypeNamesForSourceId(SourceId sourceId) const; @@ -131,7 +121,9 @@ public: Storage::Info::ItemLibraryEntries itemLibrariesEntries() const; SourceId sourceId() const; - DEPRECATED_COMPONENT_FILE_NAME QString componentFileName() const; +#ifndef QDS_USE_PROJECTSTORAGE + QString componentFileName() const; +#endif bool isBasedOn(const NodeMetaInfo &metaInfo) const; bool isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo2) const; @@ -214,6 +206,7 @@ public: bool isQtQuick3DCubeMapTexture() const; bool isQtQuick3DView3D() const; bool isQtQuickBorderImage() const; + bool isQtQuickControlsLabel() const; bool isQtQuickControlsSwipeView() const; bool isQtQuickControlsTabBar() const; bool isQtQuickExtrasPicture() const; @@ -226,6 +219,7 @@ public: bool isQtQuickPositioner() const; bool isQtQuickPropertyAnimation() const; bool isQtQuickPropertyChanges() const; + bool isQtQuickRectangle() const; bool isQtQuickRepeater() const; bool isQtQuickState() const; bool isQtQuickStateOperation() const; @@ -251,9 +245,10 @@ public: bool usesCustomParser() const; bool isEnumeration() const; - DEPRECATED_IMPORT_DIRECTORY_PATH QString importDirectoryPath() const; - DEPRECATED_REQUIRED_IMPORT_STRING QString requiredImportString() const; - +#ifndef QDS_USE_PROJECTSTORAGE + QString importDirectoryPath() const; + QString requiredImportString() const; +#endif friend bool operator==(const NodeMetaInfo &first, const NodeMetaInfo &second) { if constexpr (useProjectStorage()) diff --git a/src/plugins/qmldesigner/libs/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/libs/designercore/metainfo/nodemetainfo.cpp index e340bc2c357..47943e096e9 100644 --- a/src/plugins/qmldesigner/libs/designercore/metainfo/nodemetainfo.cpp +++ b/src/plugins/qmldesigner/libs/designercore/metainfo/nodemetainfo.cpp @@ -614,8 +614,9 @@ public: const TypeName &propertyType(const PropertyName &propertyName) const; void setupPrototypes(); +#ifndef QDS_USE_PROJECTSTORAGE QList prototypes() const; - +#endif bool isPropertyWritable(const PropertyName &propertyName) const; bool isPropertyPointer(const PropertyName &propertyName) const; bool isPropertyList(const PropertyName &propertyName) const; @@ -1429,10 +1430,12 @@ void NodeMetaInfoPrivate::setupPrototypes() } } +#ifndef QDS_USE_PROJECTSTORAGE QList NodeMetaInfoPrivate::prototypes() const { return m_prototypes; } +#endif const CppComponentValue *NodeMetaInfoPrivate::getNearestCppComponentValue() const { @@ -1478,10 +1481,13 @@ NodeMetaInfo &NodeMetaInfo::operator=(const NodeMetaInfo &) = default; NodeMetaInfo::NodeMetaInfo(NodeMetaInfo &&) = default; NodeMetaInfo &NodeMetaInfo::operator=(NodeMetaInfo &&) = default; +#ifndef QDS_USE_PROJECTSTORAGE + NodeMetaInfo::NodeMetaInfo(Model *model, const TypeName &type, int maj, int min) : m_privateData(NodeMetaInfoPrivate::create(model, type, maj, min)) { } +#endif NodeMetaInfo::~NodeMetaInfo() = default; @@ -2024,28 +2030,26 @@ std::vector NodeMetaInfo::selfAndPrototypes() const if (!isValid()) return {}; - if constexpr (useProjectStorage()) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get self and prototypes"_t, - category(), - keyValue("type id", m_typeId)}; +#ifdef QDS_USE_PROJECTSTORAGE + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get self and prototypes"_t, category(), keyValue("type id", m_typeId)}; - return Utils::transform(m_projectStorage->prototypeAndSelfIds(m_typeId), - NodeMetaInfo::bind(m_projectStorage)); - } else { - NodeMetaInfos hierarchy = {*this}; - Model *model = m_privateData->model(); - for (const TypeDescription &type : m_privateData->prototypes()) { - auto &last = hierarchy.emplace_back(model, - type.className.toUtf8(), - type.majorVersion, - type.minorVersion); - if (!last.isValid()) - hierarchy.pop_back(); - } - - return hierarchy; + return Utils::transform(m_projectStorage->prototypeAndSelfIds(m_typeId), + NodeMetaInfo::bind(m_projectStorage)); +#else + NodeMetaInfos hierarchy = {*this}; + Model *model = m_privateData->model(); + for (const TypeDescription &type : m_privateData->prototypes()) { + auto &last = hierarchy.emplace_back(model, + type.className.toUtf8(), + type.majorVersion, + type.minorVersion); + if (!last.isValid()) + hierarchy.pop_back(); } + + return hierarchy; +#endif } NodeMetaInfos NodeMetaInfo::prototypes() const @@ -2053,26 +2057,26 @@ NodeMetaInfos NodeMetaInfo::prototypes() const if (!isValid()) return {}; - if constexpr (useProjectStorage()) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get prototypes"_t, category(), keyValue("type id", m_typeId)}; - return Utils::transform(m_projectStorage->prototypeIds(m_typeId), - NodeMetaInfo::bind(m_projectStorage)); +#ifdef QDS_USE_PROJECTSTORAGE + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get prototypes"_t, category(), keyValue("type id", m_typeId)}; + return Utils::transform(m_projectStorage->prototypeIds(m_typeId), + NodeMetaInfo::bind(m_projectStorage)); - } else { - NodeMetaInfos hierarchy; - Model *model = m_privateData->model(); - for (const TypeDescription &type : m_privateData->prototypes()) { - auto &last = hierarchy.emplace_back(model, - type.className.toUtf8(), - type.majorVersion, - type.minorVersion); - if (!last.isValid()) - hierarchy.pop_back(); - } - - return hierarchy; +#else + NodeMetaInfos hierarchy; + Model *model = m_privateData->model(); + for (const TypeDescription &type : m_privateData->prototypes()) { + auto &last = hierarchy.emplace_back(model, + type.className.toUtf8(), + type.majorVersion, + type.minorVersion); + if (!last.isValid()) + hierarchy.pop_back(); } + + return hierarchy; +#endif } namespace { @@ -2111,6 +2115,7 @@ QString NodeMetaInfo::displayName() const return {}; } +#ifndef QDS_USE_PROJECTSTORAGE TypeName NodeMetaInfo::typeName() const { if (isValid()) @@ -2146,6 +2151,7 @@ int NodeMetaInfo::minorVersion() const return -1; } +#endif Storage::Info::ExportedTypeNames NodeMetaInfo::allExportedTypeNames() const { @@ -2260,6 +2266,7 @@ SourceId NodeMetaInfo::sourceId() const return SourceId{}; } +#ifndef QDS_USE_PROJECTSTORAGE QString NodeMetaInfo::componentFileName() const { if constexpr (!useProjectStorage()) { @@ -2295,6 +2302,7 @@ QString NodeMetaInfo::requiredImportString() const return {}; } +#endif SourceId NodeMetaInfo::propertyEditorPathId() const { @@ -2333,13 +2341,17 @@ PropertyDeclarationId NodeMetaInfo::defaultPropertyDeclarationId() const return *m_defaultPropertyId; } -bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int minorVersion) const +bool NodeMetaInfo::isSubclassOf([[maybe_unused]] const TypeName &type, + [[maybe_unused]] int majorVersion, + [[maybe_unused]] int minorVersion) const { if (!isValid()) { qWarning() << "NodeMetaInfo is invalid" << type; return false; } +#ifndef QDS_USE_PROJECTSTORAGE + if (typeName().isEmpty()) return false; @@ -2363,6 +2375,7 @@ bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int mino } } m_privateData->prototypeCacheNegatives().insert(stringIdentifier(type, majorVersion, minorVersion)); +#endif return false; } @@ -2402,75 +2415,73 @@ bool NodeMetaInfo::isSuitableForMouseAreaFill() const bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, - category(), - keyValue("type id", m_typeId), - keyValue("meta info type id", metaInfo.m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, + category(), + keyValue("type id", m_typeId), + keyValue("meta info type id", metaInfo.m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, metaInfo.m_typeId); - } else { - if (!isValid()) - return false; - if (majorVersion() == -1 && minorVersion() == -1) - return isSubclassOf(metaInfo.typeName()); - return isSubclassOf(metaInfo.typeName(), metaInfo.majorVersion(), metaInfo.minorVersion()); - } + return m_projectStorage->isBasedOn(m_typeId, metaInfo.m_typeId); +#else + if (!isValid()) + return false; + if (majorVersion() == -1 && minorVersion() == -1) + return isSubclassOf(metaInfo.typeName()); + return isSubclassOf(metaInfo.typeName(), metaInfo.majorVersion(), metaInfo.minorVersion()); +#endif } bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo2) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, metaInfo1.m_typeId, metaInfo2.m_typeId); - } else { - if (!isValid()) - return false; - if (majorVersion() == -1 && minorVersion() == -1) - return (isSubclassOf(metaInfo1.typeName()) || isSubclassOf(metaInfo2.typeName())); + return m_projectStorage->isBasedOn(m_typeId, metaInfo1.m_typeId, metaInfo2.m_typeId); +#else + if (!isValid()) + return false; + if (majorVersion() == -1 && minorVersion() == -1) + return (isSubclassOf(metaInfo1.typeName()) || isSubclassOf(metaInfo2.typeName())); - return ( - isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) + return (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) || isSubclassOf(metaInfo2.typeName(), metaInfo2.majorVersion(), metaInfo2.minorVersion())); - } +#endif } bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo2, const NodeMetaInfo &metaInfo3) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, - metaInfo1.m_typeId, - metaInfo2.m_typeId, - metaInfo3.m_typeId); - } else { - if (!isValid()) - return false; - if (majorVersion() == -1 && minorVersion() == -1) - return (isSubclassOf(metaInfo1.typeName()) || isSubclassOf(metaInfo2.typeName()) - || isSubclassOf(metaInfo3.typeName())); + return m_projectStorage->isBasedOn(m_typeId, + metaInfo1.m_typeId, + metaInfo2.m_typeId, + metaInfo3.m_typeId); +#else + if (!isValid()) + return false; + if (majorVersion() == -1 && minorVersion() == -1) + return (isSubclassOf(metaInfo1.typeName()) || isSubclassOf(metaInfo2.typeName()) + || isSubclassOf(metaInfo3.typeName())); - return ( - isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) + return (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) || isSubclassOf(metaInfo2.typeName(), metaInfo2.majorVersion(), metaInfo2.minorVersion()) || isSubclassOf(metaInfo3.typeName(), metaInfo3.majorVersion(), metaInfo3.minorVersion())); - } +#endif } bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, @@ -2478,31 +2489,27 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo3, const NodeMetaInfo &metaInfo4) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, - metaInfo1.m_typeId, - metaInfo2.m_typeId, - metaInfo3.m_typeId, - metaInfo4.m_typeId); - } else { - return isValid() - && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) - || isSubclassOf(metaInfo2.typeName(), - metaInfo2.majorVersion(), - metaInfo2.minorVersion()) - || isSubclassOf(metaInfo3.typeName(), - metaInfo3.majorVersion(), - metaInfo3.minorVersion()) - || isSubclassOf(metaInfo4.typeName(), - metaInfo4.majorVersion(), - metaInfo4.minorVersion())); - } + return m_projectStorage->isBasedOn(m_typeId, + metaInfo1.m_typeId, + metaInfo2.m_typeId, + metaInfo3.m_typeId, + metaInfo4.m_typeId); +#else + return isValid() + && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) + || isSubclassOf(metaInfo2.typeName(), metaInfo2.majorVersion(), metaInfo2.minorVersion()) + || isSubclassOf(metaInfo3.typeName(), metaInfo3.majorVersion(), metaInfo3.minorVersion()) + || isSubclassOf(metaInfo4.typeName(), + metaInfo4.majorVersion(), + metaInfo4.minorVersion())); +#endif } bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, @@ -2511,35 +2518,29 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo4, const NodeMetaInfo &metaInfo5) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, - metaInfo1.m_typeId, - metaInfo2.m_typeId, - metaInfo3.m_typeId, - metaInfo4.m_typeId, - metaInfo5.m_typeId); - } else { - return isValid() - && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) - || isSubclassOf(metaInfo2.typeName(), - metaInfo2.majorVersion(), - metaInfo2.minorVersion()) - || isSubclassOf(metaInfo3.typeName(), - metaInfo3.majorVersion(), - metaInfo3.minorVersion()) - || isSubclassOf(metaInfo4.typeName(), - metaInfo4.majorVersion(), - metaInfo4.minorVersion()) - || isSubclassOf(metaInfo5.typeName(), - metaInfo5.majorVersion(), - metaInfo5.minorVersion())); - } + return m_projectStorage->isBasedOn(m_typeId, + metaInfo1.m_typeId, + metaInfo2.m_typeId, + metaInfo3.m_typeId, + metaInfo4.m_typeId, + metaInfo5.m_typeId); +#else + return isValid() + && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) + || isSubclassOf(metaInfo2.typeName(), metaInfo2.majorVersion(), metaInfo2.minorVersion()) + || isSubclassOf(metaInfo3.typeName(), metaInfo3.majorVersion(), metaInfo3.minorVersion()) + || isSubclassOf(metaInfo4.typeName(), metaInfo4.majorVersion(), metaInfo4.minorVersion()) + || isSubclassOf(metaInfo5.typeName(), + metaInfo5.majorVersion(), + metaInfo5.minorVersion())); +#endif } bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, @@ -2549,39 +2550,31 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo5, const NodeMetaInfo &metaInfo6) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, - metaInfo1.m_typeId, - metaInfo2.m_typeId, - metaInfo3.m_typeId, - metaInfo4.m_typeId, - metaInfo5.m_typeId, - metaInfo6.m_typeId); - } else { - return isValid() - && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) - || isSubclassOf(metaInfo2.typeName(), - metaInfo2.majorVersion(), - metaInfo2.minorVersion()) - || isSubclassOf(metaInfo3.typeName(), - metaInfo3.majorVersion(), - metaInfo3.minorVersion()) - || isSubclassOf(metaInfo4.typeName(), - metaInfo4.majorVersion(), - metaInfo4.minorVersion()) - || isSubclassOf(metaInfo5.typeName(), - metaInfo5.majorVersion(), - metaInfo5.minorVersion()) - || isSubclassOf(metaInfo6.typeName(), - metaInfo6.majorVersion(), - metaInfo6.minorVersion())); - } + return m_projectStorage->isBasedOn(m_typeId, + metaInfo1.m_typeId, + metaInfo2.m_typeId, + metaInfo3.m_typeId, + metaInfo4.m_typeId, + metaInfo5.m_typeId, + metaInfo6.m_typeId); +#else + return isValid() + && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) + || isSubclassOf(metaInfo2.typeName(), metaInfo2.majorVersion(), metaInfo2.minorVersion()) + || isSubclassOf(metaInfo3.typeName(), metaInfo3.majorVersion(), metaInfo3.minorVersion()) + || isSubclassOf(metaInfo4.typeName(), metaInfo4.majorVersion(), metaInfo4.minorVersion()) + || isSubclassOf(metaInfo5.typeName(), metaInfo5.majorVersion(), metaInfo5.minorVersion()) + || isSubclassOf(metaInfo6.typeName(), + metaInfo6.majorVersion(), + metaInfo6.minorVersion())); +#endif } bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, @@ -2592,43 +2585,33 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo6, const NodeMetaInfo &metaInfo7) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, - metaInfo1.m_typeId, - metaInfo2.m_typeId, - metaInfo3.m_typeId, - metaInfo4.m_typeId, - metaInfo5.m_typeId, - metaInfo6.m_typeId, - metaInfo7.m_typeId); - } else { - return isValid() - && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) - || isSubclassOf(metaInfo2.typeName(), - metaInfo2.majorVersion(), - metaInfo2.minorVersion()) - || isSubclassOf(metaInfo3.typeName(), - metaInfo3.majorVersion(), - metaInfo3.minorVersion()) - || isSubclassOf(metaInfo4.typeName(), - metaInfo4.majorVersion(), - metaInfo4.minorVersion()) - || isSubclassOf(metaInfo5.typeName(), - metaInfo5.majorVersion(), - metaInfo5.minorVersion()) - || isSubclassOf(metaInfo6.typeName(), - metaInfo6.majorVersion(), - metaInfo6.minorVersion()) - || isSubclassOf(metaInfo7.typeName(), - metaInfo7.majorVersion(), - metaInfo7.minorVersion())); - } + return m_projectStorage->isBasedOn(m_typeId, + metaInfo1.m_typeId, + metaInfo2.m_typeId, + metaInfo3.m_typeId, + metaInfo4.m_typeId, + metaInfo5.m_typeId, + metaInfo6.m_typeId, + metaInfo7.m_typeId); +#else + return isValid() + && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) + || isSubclassOf(metaInfo2.typeName(), metaInfo2.majorVersion(), metaInfo2.minorVersion()) + || isSubclassOf(metaInfo3.typeName(), metaInfo3.majorVersion(), metaInfo3.minorVersion()) + || isSubclassOf(metaInfo4.typeName(), metaInfo4.majorVersion(), metaInfo4.minorVersion()) + || isSubclassOf(metaInfo5.typeName(), metaInfo5.majorVersion(), metaInfo5.minorVersion()) + || isSubclassOf(metaInfo6.typeName(), metaInfo6.majorVersion(), metaInfo6.minorVersion()) + || isSubclassOf(metaInfo7.typeName(), + metaInfo7.majorVersion(), + metaInfo7.minorVersion())); +#endif } bool NodeMetaInfo::isGraphicalItem() const @@ -2673,20 +2656,18 @@ bool NodeMetaInfo::isQtObject() const bool NodeMetaInfo::isQtQmlConnections() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is Qt Qml connections"_t, - category(), - keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is Qt Qml connections"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isBasedOnCommonType(m_projectStorage, m_typeId); - } else { - return isValid() && simplifiedTypeName() == "Connections"; - } + using namespace Storage::Info; + return isBasedOnCommonType(m_projectStorage, m_typeId); +#else + return isValid() && simplifiedTypeName() == "Connections"; +#endif } bool NodeMetaInfo::isLayoutable() const @@ -2753,22 +2734,22 @@ bool NodeMetaInfo::isView() const bool NodeMetaInfo::usesCustomParser() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"uses custom parser"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"uses custom parser"_t, category(), keyValue("type id", m_typeId)}; - return typeData().traits.usesCustomParser; - } else { - if (!isValid()) - return false; + return typeData().traits.usesCustomParser; +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); - return type == "VisualItemModel" || type == "VisualDataModel" || type == "ListModel" - || type == "XmlListModel"; - } + auto type = simplifiedTypeName(); + return type == "VisualItemModel" || type == "VisualDataModel" || type == "ListModel" + || type == "XmlListModel"; +#endif } namespace { @@ -3123,6 +3104,23 @@ bool NodeMetaInfo::isQtQuickPropertyAnimation() const } } +bool NodeMetaInfo::isQtQuickRectangle() const +{ +#ifdef QDS_USE_PROJECTSTORAGE + + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Rectange"_t, category(), keyValue("type id", m_typeId)}; + + using namespace Storage::Info; + return isBasedOnCommonType(m_projectStorage, m_typeId); +#else + return isValid() && isSubclassOf("QtQuick.Rectangle"); +#endif +} + bool NodeMetaInfo::isQtQuickRepeater() const { if constexpr (useProjectStorage()) { @@ -3157,6 +3155,24 @@ bool NodeMetaInfo::isQtQuickControlsTabBar() const } } +bool NodeMetaInfo::isQtQuickControlsLabel() const +{ +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Controls.SwipeView"_t, + category(), + keyValue("type id", m_typeId)}; + + using namespace Storage::Info; + return isBasedOnCommonType(m_projectStorage, m_typeId); +#else + return isValid() && isSubclassOf("QtQuick.Controls.Label"); +#endif +} + bool NodeMetaInfo::isQtQuickControlsSwipeView() const { if constexpr (useProjectStorage()) { @@ -3744,189 +3760,189 @@ bool NodeMetaInfo::isQtQuickStudioUtilsJsonListModel() const bool NodeMetaInfo::isQmlComponent() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is QML.Component"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QML.Component"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isBasedOnCommonType(m_projectStorage, m_typeId); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isBasedOnCommonType(m_projectStorage, m_typeId); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "Component" || type == "QQmlComponent"; - } + return type == "Component" || type == "QQmlComponent"; +#endif } bool NodeMetaInfo::isFont() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is font"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is font"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->commonTypeId()); - } else { - return isValid() && simplifiedTypeName() == "font"; - } + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->commonTypeId()); +#else + return isValid() && simplifiedTypeName() == "font"; +#endif } bool NodeMetaInfo::isColor() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is color"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is color"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "QColor" || type == "color" || type == "color"; - } + return type == "QColor" || type == "color" || type == "color"; +#endif } bool NodeMetaInfo::isBool() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is bool"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is bool"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "bool" || type == "boolean"; - } + return type == "bool" || type == "boolean"; +#endif } bool NodeMetaInfo::isInteger() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is integer"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is integer"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "int" || type == "integer" || type == "uint"; - } + return type == "int" || type == "integer" || type == "uint"; +#endif } bool NodeMetaInfo::isFloat() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is float"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is float"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - auto floatId = m_projectStorage->builtinTypeId(); - auto doubleId = m_projectStorage->builtinTypeId(); + using namespace Storage::Info; + auto floatId = m_projectStorage->builtinTypeId(); + auto doubleId = m_projectStorage->builtinTypeId(); - return isTypeId(m_typeId, floatId, doubleId); - } else { - if (!isValid()) - return false; + return isTypeId(m_typeId, floatId, doubleId); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "qreal" || type == "double" || type == "float" || type == "real"; - } + return type == "qreal" || type == "double" || type == "float" || type == "real"; +#endif } bool NodeMetaInfo::isVariant() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is variant"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is variant"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); +#else + if (!isValid()) + return false; - const auto type = simplifiedTypeName(); + const auto type = simplifiedTypeName(); - return type == "QVariant" || type == "var" || type == "variant"; - } + return type == "QVariant" || type == "var" || type == "variant"; +#endif } bool NodeMetaInfo::isString() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is string"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is string"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "string" || type == "QString"; - } + return type == "string" || type == "QString"; +#endif } bool NodeMetaInfo::isUrl() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is url"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is url"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "url" || type == "QUrl"; - } + return type == "url" || type == "QUrl"; +#endif } bool NodeMetaInfo::isQtQuick3DTexture() const @@ -4249,40 +4265,40 @@ PropertyMetaInfo::~PropertyMetaInfo() = default; NodeMetaInfo PropertyMetaInfo::propertyType() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return {}; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return {}; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get property type"_t, - category(), - keyValue("property declaration id", m_id)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property type"_t, + category(), + keyValue("property declaration id", m_id)}; - return {propertyData().propertyTypeId, m_projectStorage}; - } else { - if (isValid()) - return NodeMetaInfo{nodeMetaInfoPrivateData()->model(), - nodeMetaInfoPrivateData()->propertyType(propertyName()), - -1, - -1}; - } + return {propertyData().propertyTypeId, m_projectStorage}; +#else + if (isValid()) + return NodeMetaInfo{nodeMetaInfoPrivateData()->model(), + nodeMetaInfoPrivateData()->propertyType(propertyName()), + -1, + -1}; +#endif return {}; } NodeMetaInfo PropertyMetaInfo::type() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return {}; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return {}; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get property owner type "_t, - category(), - keyValue("property declaration id", m_id)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property owner type "_t, + category(), + keyValue("property declaration id", m_id)}; - return NodeMetaInfo(propertyData().typeId, m_projectStorage); - } + return NodeMetaInfo(propertyData().typeId, m_projectStorage); +#endif return {}; } @@ -4530,7 +4546,11 @@ const Storage::Info::PropertyDeclaration &PropertyMetaInfo::propertyData() const TypeName PropertyMetaInfo::propertyTypeName() const { +#ifndef QDS_USE_PROJECTSTORAGE return propertyType().typeName(); +#else + return {}; +#endif } const NodeMetaInfoPrivate *PropertyMetaInfo::nodeMetaInfoPrivateData() const @@ -4554,37 +4574,36 @@ const PropertyName &PropertyMetaInfo::propertyName() const NodeMetaInfo NodeMetaInfo::commonBase(const NodeMetaInfo &metaInfo) const { - if constexpr (useProjectStorage()) { - if (isValid() && metaInfo) { - const auto firstTypeIds = m_projectStorage->prototypeAndSelfIds(m_typeId); - const auto secondTypeIds = m_projectStorage->prototypeAndSelfIds(metaInfo.m_typeId); - auto found = std::ranges::find_if(firstTypeIds, [&](TypeId firstTypeId) { - return std::ranges::find(secondTypeIds, firstTypeId) != secondTypeIds.end(); - }); +#ifdef QDS_USE_PROJECTSTORAGE + if (isValid() && metaInfo) { + const auto firstTypeIds = m_projectStorage->prototypeAndSelfIds(m_typeId); + const auto secondTypeIds = m_projectStorage->prototypeAndSelfIds(metaInfo.m_typeId); + auto found = std::ranges::find_if(firstTypeIds, [&](TypeId firstTypeId) { + return std::ranges::find(secondTypeIds, firstTypeId) != secondTypeIds.end(); + }); - if (found != firstTypeIds.end()) { - return NodeMetaInfo{*found, m_projectStorage}; - } - } - } else { - for (const NodeMetaInfo &info : metaInfo.selfAndPrototypes()) { - if (isBasedOn(info)) { - return info; - } + if (found != firstTypeIds.end()) + return NodeMetaInfo{*found, m_projectStorage}; + } +#else + for (const NodeMetaInfo &info : metaInfo.selfAndPrototypes()) { + if (isBasedOn(info)) { + return info; } } +#endif return {}; } NodeMetaInfo::NodeMetaInfos NodeMetaInfo::heirs() const { - if constexpr (useProjectStorage()) { - if (isValid()) { - return Utils::transform(m_projectStorage->heirIds(m_typeId), - NodeMetaInfo::bind(m_projectStorage)); - } +#ifdef QDS_USE_PROJECTSTORAGE + if (isValid()) { + return Utils::transform(m_projectStorage->heirIds(m_typeId), + NodeMetaInfo::bind(m_projectStorage)); } +#endif return {}; } diff --git a/src/plugins/qmldesigner/libs/designercore/model/model.cpp b/src/plugins/qmldesigner/libs/designercore/model/model.cpp index d38040a62d6..cd29f942e18 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/libs/designercore/model/model.cpp @@ -1788,6 +1788,7 @@ Model::Model(ProjectStorageDependencies projectStorageDependencies, std::move(resourceManagement))) {} +#ifndef QDS_USE_PROJECTSTORAGE Model::Model(const TypeName &typeName, int major, int minor, @@ -1796,6 +1797,7 @@ Model::Model(const TypeName &typeName, : d(std::make_unique( this, typeName, major, minor, metaInfoProxyModel, std::move(resourceManagement))) {} +#endif ModelPointer Model::createModel(const TypeName &typeName, std::unique_ptr resourceManagement) @@ -2480,6 +2482,16 @@ NodeMetaInfo Model::qtQuickTextEditMetaInfo() const } } +NodeMetaInfo Model::qtQuickControlsLabelMetaInfo() const +{ +#ifdef QDS_USE_PROJECTSTORAGE + using namespace Storage::Info; + return createNodeMetaInfo(); +#else + return metaInfo("QtQuick.Controls.Label"); +#endif +} + NodeMetaInfo Model::qtQuickControlsTextAreaMetaInfo() const { if constexpr (useProjectStorage()) { @@ -2773,24 +2785,26 @@ namespace { } } // namespace -NodeMetaInfo Model::metaInfo(const TypeName &typeName, int majorVersion, int minorVersion) const +NodeMetaInfo Model::metaInfo(const TypeName &typeName, + [[maybe_unused]] int majorVersion, + [[maybe_unused]] int minorVersion) const { - if constexpr (useProjectStorage()) { - return NodeMetaInfo(d->projectStorage->typeId(d->importedTypeNameId(typeName)), - d->projectStorage); - } else { - return NodeMetaInfo(metaInfoProxyModel(), typeName, majorVersion, minorVersion); - } +#ifdef QDS_USE_PROJECTSTORAGE + return NodeMetaInfo(d->projectStorage->typeId(d->importedTypeNameId(typeName)), d->projectStorage); +#else + return NodeMetaInfo(metaInfoProxyModel(), typeName, majorVersion, minorVersion); +#endif } -NodeMetaInfo Model::metaInfo(Module module, Utils::SmallStringView typeName, Storage::Version version) const +NodeMetaInfo Model::metaInfo([[maybe_unused]] Module module, + [[maybe_unused]] Utils::SmallStringView typeName, + [[maybe_unused]] Storage::Version version) const { - if constexpr (useProjectStorage()) { - return NodeMetaInfo(d->projectStorage->typeId(module.id(), typeName, version), - d->projectStorage); - } else { - return {}; - } +#ifdef QDS_USE_PROJECTSTORAGE + return NodeMetaInfo(d->projectStorage->typeId(module.id(), typeName, version), d->projectStorage); +#else + return {}; +#endif } #ifndef QDS_USE_PROJECTSTORAGE diff --git a/src/plugins/qmldesigner/libs/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/libs/designercore/model/modelnode.cpp index 8eba7549bf5..0dc461159fc 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/modelnode.cpp +++ b/src/plugins/qmldesigner/libs/designercore/model/modelnode.cpp @@ -687,14 +687,14 @@ NodeMetaInfo ModelNode::metaInfo() const if (!isValid()) return {}; - if constexpr (useProjectStorage()) { - return NodeMetaInfo(m_internalNode->typeId, m_model->projectStorage()); - } else { - return NodeMetaInfo(m_model->metaInfoProxyModel(), - m_internalNode->typeName, - m_internalNode->majorVersion, - m_internalNode->minorVersion); - } +#ifdef QDS_USE_PROJECTSTORAGE + return NodeMetaInfo(m_internalNode->typeId, m_model->projectStorage()); +#else + return NodeMetaInfo(m_model->metaInfoProxyModel(), + m_internalNode->typeName, + m_internalNode->majorVersion, + m_internalNode->minorVersion); +#endif } bool ModelNode::hasMetaInfo() const diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/commontypecache.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/commontypecache.h index 76305b1fbee..618c9418c18 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/commontypecache.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/commontypecache.h @@ -58,6 +58,7 @@ inline constexpr char Item[] = "Item"; inline constexpr char JsonListModel[] = "JsonListModel"; inline constexpr char KeyframeGroup[] = "KeyframeGroup"; inline constexpr char Keyframe[] = "Keyframe"; +inline constexpr char Label[] = "Label"; inline constexpr char Layout[] = "Layout"; inline constexpr char Light[] = "Light"; inline constexpr char ListElement[] = "ListElement"; @@ -236,6 +237,7 @@ class CommonTypeCache CacheType, CacheType, CacheType, + CacheType, CacheType, CacheType, CacheType, diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index d9a510769cd..23f4120f3f4 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -705,6 +705,11 @@ Internal::DesignModeWidget *QmlDesignerPlugin::mainWidget() const return d ? &d->mainWidget : nullptr; } +QmlDesignerProjectManager &QmlDesignerPlugin::projectManagerForPluginInitializationOnly() +{ + return m_instance->d->projectManager; +} + QWidget *QmlDesignerPlugin::createProjectExplorerWidget(QWidget *parent) const { return Internal::DesignModeWidget::createProjectExplorerWidget(parent); diff --git a/src/plugins/qmldesigner/qmldesignerplugin.h b/src/plugins/qmldesigner/qmldesignerplugin.h index 7487420a1f8..33fecc7a574 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.h +++ b/src/plugins/qmldesigner/qmldesignerplugin.h @@ -60,6 +60,8 @@ public: DesignDocument *currentDesignDocument() const; Internal::DesignModeWidget *mainWidget() const; + static QmlDesignerProjectManager &projectManagerForPluginInitializationOnly(); + QWidget *createProjectExplorerWidget(QWidget *parent) const; void switchToTextModeDeferred(); diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.h b/src/plugins/qmldesigner/qmldesignerprojectmanager.h index 10c0bd42618..4947dbcd437 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.h +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.h @@ -5,6 +5,7 @@ #include "modelfwd.h" #include +#include #include #include @@ -28,7 +29,7 @@ namespace QmlDesigner { class ExternalDependenciesInterface; -class QmlDesignerProjectManager +class QMLDESIGNER_EXPORT QmlDesignerProjectManager { class QmlDesignerProjectManagerProjectData; class PreviewImageCacheData; From 469194a0820da7f42fe2f1e6a022959bba020a13 Mon Sep 17 00:00:00 2001 From: Burak Hancerli Date: Tue, 1 Oct 2024 17:13:46 +0200 Subject: [PATCH 16/44] DesignViewer: Add telemetry constants for Qt Design Viewer backend Change-Id: Ifd19f83a55a283ea3535cf11e0214f45b693aadd Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/qmldesignerconstants.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 116dc94dcca..8aef417b3bc 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -140,6 +140,18 @@ inline constexpr char EVENT_TOOLBAR_SET_CURRENT_WORKSPACE[] = "ToolBarSetCurrent inline constexpr char EVENT_TOOLBAR_EDIT_GLOBAL_ANNOTATION[] = "ToolBarEditGlobalAnnotation"; inline constexpr char EVENT_STATUSBAR_SHOW_ZOOM[] = "StatusBarShowZoomMenu"; inline constexpr char EVENT_STATUSBAR_SET_STYLE[] = "StatusBarSetCurrentStyle"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_UPLOADED[] = "DesignViewerProjectUploaded"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_DOWNLOADED[] = "DesignViewerProjectDownloaded"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_DELETED[] = "DesignViewerProjectDeleted"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_SHARED[] = "DesignViewerProjectShared"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_UNSHARED[] = "DesignViewerProjectUnshared"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_UNSHARED_ALL[] = "DesignViewerProjectUnsharedAll"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_THUMBNAIL_UPLOADED[] + = "DesignViewerProjectThumbnailUploaded"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_THUMBNAIL_DELETED[] + = "DesignViewerProjectThumbnailDeleted"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_THUMBNAIL_DOWNLOADED[] + = "DesignViewerProjectThumbnailDownloaded"; inline constexpr char PROPERTY_EDITOR_CLASSNAME_PROPERTY[] = "__classNamePrivateInternal"; From e64f3c270346bda5ab2e31a20f6348e9f7117899 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 1 Oct 2024 17:17:31 +0200 Subject: [PATCH 17/44] QmlDesigner: Improve support for project storage aliases Change-Id: I074aa01e2fc68dea01bece63d13e2688eadbea67 Reviewed-by: Thomas Hartmann --- .../qmldesigner/libs/designercore/CMakeLists.txt | 5 +++++ .../qmldesigner/libs/designercore/include/modelfwd.h | 3 ++- .../libs/designercore/projectstorage/filesystem.h | 7 ++++--- .../projectstorage/projectstorageinterface.h | 2 +- .../projectstorage/projectstorageupdater.h | 6 ++---- .../designercore/projectstorage/qmldocumentparser.cpp | 6 +++--- .../designercore/projectstorage/qmldocumentparser.h | 10 ++++------ src/plugins/qmldesigner/qmldesignerprojectmanager.cpp | 8 ++++---- tests/unit/tests/unittests/model/model-test.cpp | 2 +- 9 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt b/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt index 977bced8f23..1ebb8c48322 100644 --- a/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt +++ b/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt @@ -375,6 +375,11 @@ extend_qtc_library(QmlDesignerCore DEFINES QML_DOM_MSVC2019_COMPAT ) +extend_qtc_library(QmlDesignerCore + CONDITION WITH_TESTS + PUBLIC_DEFINES QDS_MODEL_USE_PROJECTSTORAGEINTERFACE +) + extend_qtc_library(QmlDesignerCore SOURCES_PREFIX projectstorage PUBLIC_INCLUDES projectstorage diff --git a/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h b/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h index 7cbfdba616a..a58e91a838c 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h +++ b/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h @@ -39,6 +39,8 @@ constexpr bool useProjectStorage() return false; #endif } +class SourcePathStorage; +using PathCache = SourcePathCache; #ifdef QDS_MODEL_USE_PROJECTSTORAGEINTERFACE using ProjectStorageType = ProjectStorageInterface; @@ -46,7 +48,6 @@ class SourcePathCacheInterface; using PathCacheType = SourcePathCacheInterface; #else using ProjectStorageType = ProjectStorage; -class SourcePathStorage; using PathCacheType = SourcePathCache; #endif diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.h index 8e83cd2ff04..ae58b229d82 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.h @@ -7,6 +7,8 @@ #include "filesysteminterface.h" #include "sourcepathstorage/nonlockingmutex.h" +#include + namespace QmlDesigner { class SourcePathStorage; @@ -16,10 +18,9 @@ class SourcePathCache; class QMLDESIGNERCORE_EXPORT FileSystem : public FileSystemInterface { - using PathCache = SourcePathCache; public: - FileSystem(PathCache &sourcePathCache) + FileSystem(PathCacheType &sourcePathCache) : m_sourcePathCache(sourcePathCache) {} @@ -33,7 +34,7 @@ public: void remove(const SourceIds &sourceIds) override; private: - PathCache &m_sourcePathCache; + PathCacheType &m_sourcePathCache; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h index 69674ffc8bf..9cf0daf4e8c 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h @@ -17,7 +17,7 @@ namespace QmlDesigner { class ProjectStorageInterface { - friend Storage::Info::CommonTypeCache; + friend Storage::Info::CommonTypeCache; public: ProjectStorageInterface(const ProjectStorageInterface &) = delete; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h index 344b0543a27..6c3353ff68a 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h @@ -41,12 +41,10 @@ class QMLDESIGNERCORE_EXPORT ProjectStorageUpdater final : public ProjectStoragePathWatcherNotifierInterface { public: - using PathCache = SourcePathCache; - ProjectStorageUpdater(FileSystemInterface &fileSystem, ProjectStorageType &projectStorage, FileStatusCache &fileStatusCache, - PathCache &pathCache, + PathCacheType &pathCache, QmlDocumentParserInterface &qmlDocumentParser, QmlTypesParserInterface &qmlTypesParser, class ProjectStoragePathWatcherInterface &pathWatcher, @@ -243,7 +241,7 @@ private: FileSystemInterface &m_fileSystem; ProjectStorageType &m_projectStorage; FileStatusCache &m_fileStatusCache; - PathCache &m_pathCache; + PathCacheType &m_pathCache; QmlDocumentParserInterface &m_qmlDocumentParser; QmlTypesParserInterface &m_qmlTypesParser; ProjectStoragePathWatcherInterface &m_pathWatcher; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.cpp index b571cebac3d..17aa8ca9617 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.cpp @@ -66,7 +66,7 @@ Utils::PathString createNormalizedPath(Utils::SmallStringView directoryPath, Storage::Import createImport(const QmlDom::Import &qmlImport, SourceId sourceId, Utils::SmallStringView directoryPath, - QmlDocumentParser::ProjectStorage &storage) + ProjectStorageType &storage) { using Storage::ModuleKind; using QmlUriKind = QQmlJS::Dom::QmlUri::Kind; @@ -99,7 +99,7 @@ Storage::Import createImport(const QmlDom::Import &qmlImport, QualifiedImports createQualifiedImports(const QList &qmlImports, SourceId sourceId, Utils::SmallStringView directoryPath, - QmlDocumentParser::ProjectStorage &storage) + ProjectStorageType &storage) { NanotraceHR::Tracer tracer{"create qualified imports"_t, category(), @@ -123,7 +123,7 @@ void addImports(Storage::Imports &imports, const QList &qmlImports, SourceId sourceId, Utils::SmallStringView directoryPath, - QmlDocumentParser::ProjectStorage &storage) + ProjectStorageType &storage) { int importCount = 0; for (const QmlDom::Import &qmlImport : qmlImports) { diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.h index 7b64322ab4f..af2dbbe99ca 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.h @@ -7,8 +7,8 @@ #include "qmldocumentparserinterface.h" #include "sourcepathstorage/nonlockingmutex.h" +#include #include - namespace QmlDesigner { template @@ -18,11 +18,9 @@ class SourcePathStorage; class QMLDESIGNERCORE_EXPORT QmlDocumentParser final : public QmlDocumentParserInterface { public: - using ProjectStorage = QmlDesigner::ProjectStorage; - using PathCache = QmlDesigner::SourcePathCache; #ifdef QDS_BUILD_QMLPARSER - QmlDocumentParser(ProjectStorage &storage, PathCache &pathCache) + QmlDocumentParser(ProjectStorageType &storage, PathCacheType &pathCache) : m_storage{storage} , m_pathCache{pathCache} {} @@ -39,8 +37,8 @@ public: private: // m_pathCache and m_storage are only used when compiled for QDS #ifdef QDS_BUILD_QMLPARSER - ProjectStorage &m_storage; - PathCache &m_pathCache; + ProjectStorageType &m_storage; + PathCacheType &m_pathCache; #endif }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp index 6bba6c12369..9c04f9b1bd3 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp @@ -202,7 +202,7 @@ public: FileStatusCache fileStatusCache{fileSystem}; QmlDocumentParser qmlDocumentParser; QmlTypesParser qmlTypesParser{storage}; - ProjectStoragePathWatcher pathWatcher; + ProjectStoragePathWatcher pathWatcher; ProjectPartId projectPartId; ProjectStorageUpdater updater; }; @@ -265,7 +265,7 @@ public: Sqlite::LockingMode::Normal}; QmlDesigner::SourcePathStorage sourcePathStorage{sourcePathDatabase, sourcePathDatabase.isInitialized()}; - PathCacheType pathCache{sourcePathStorage}; + PathCache pathCache{sourcePathStorage}; }; QmlDesignerProjectManager::QmlDesignerProjectManager(ExternalDependenciesInterface &externalDependencies) @@ -322,12 +322,12 @@ AsynchronousImageCache &QmlDesignerProjectManager::asynchronousImageCache() } namespace { -[[maybe_unused]] ProjectStorage *dummyProjectStorage() +[[maybe_unused]] ProjectStorageType *dummyProjectStorage() { return nullptr; } -[[maybe_unused]] ProjectStorageUpdater::PathCache *dummyPathCache() +[[maybe_unused]] PathCacheType *dummyPathCache() { return nullptr; } diff --git a/tests/unit/tests/unittests/model/model-test.cpp b/tests/unit/tests/unittests/model/model-test.cpp index b6d453e74de..a374eb321c7 100644 --- a/tests/unit/tests/unittests/model/model-test.cpp +++ b/tests/unit/tests/unittests/model/model-test.cpp @@ -1041,7 +1041,7 @@ TEST_F(Model_MetaInfo, get_meta_info_by_module) ASSERT_THAT(metaInfo, model.qmlQtObjectMetaInfo()); } -TEST_F(Model_MetaInfo, get_invalid_meta_info_by_module_for_wrong_name) +TEST_F(Model_MetaInfo, get_invalid_meta_info_by_module_and_name_for_wrong_name) { auto module = model.module("QML", ModuleKind::QmlLibrary); From 722d7511b2d528def21ae13d1019feeeb2f02e92 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Tue, 1 Oct 2024 12:49:06 +0200 Subject: [PATCH 18/44] Core: Fix warnings in setting dialog Change-Id: I1e531c78fda7eb8063ff3fb11631fec79573541f Reviewed-by: Eike Ziller --- src/plugins/coreplugin/dialogs/settingsdialog.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/src/plugins/coreplugin/dialogs/settingsdialog.cpp index 440912efdef..7bf67845996 100644 --- a/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -56,6 +56,8 @@ using namespace Utils; namespace Core { namespace Internal { +namespace { + bool optionsPageLessThan(const IOptionsPage *p1, const IOptionsPage *p2) { if (p1->category() != p2->category()) @@ -127,7 +129,7 @@ CategoryModel::~CategoryModel() int CategoryModel::rowCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : m_categories.size(); + return parent.isValid() ? 0 : static_cast(m_categories.size()); } QVariant CategoryModel::data(const QModelIndex &index, int role) const @@ -249,7 +251,7 @@ protected: bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; }; -static bool categoryVisible(const Id &id) +static bool categoryVisible([[maybe_unused]] const Id &id) { #ifdef QT_NO_DEBUG @@ -804,6 +806,8 @@ bool SettingsDialog::execDialog() return m_applied; } +} // namespace + bool executeSettingsDialog(QWidget *parent, Id initialPage) { if (!ExtensionSystem::PluginManager::isInitializationDone()) { From 072382a7a4884e4fc3856b62688406ada5d8f5c2 Mon Sep 17 00:00:00 2001 From: Shrief Gabr Date: Tue, 1 Oct 2024 14:29:46 +0300 Subject: [PATCH 19/44] QmlDesigner: Fix 3D asset update on overwrite Fixes: QDS-13384 Change-Id: Iacbce27edd525f3ade7fcd4fab27cfc252235b8e Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../qmldesigner/components/componentcore/bundlehelper.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp b/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp index cd1f84c62ea..5cae7b8d7c2 100644 --- a/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp +++ b/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp @@ -76,6 +76,7 @@ void BundleHelper::createImporter() newNode.simplifiedTypeName(), "node")); m_view->clearSelectedModelNodes(); m_view->selectModelNode(newNode); + m_view->resetPuppet(); }); } }); @@ -103,6 +104,7 @@ void BundleHelper::createImporter() newNode.simplifiedTypeName(), "node")); m_view->clearSelectedModelNodes(); m_view->selectModelNode(newNode); + m_view->resetPuppet(); }); } }); From 85b4cc88fc0b18022aa55bee335a3b327e9f5d58 Mon Sep 17 00:00:00 2001 From: Shrief Gabr Date: Wed, 18 Sep 2024 16:40:25 +0300 Subject: [PATCH 20/44] QmlDesigner: Enable drag & drop in EffectComposer image fields Fixes: QDS-13574 Change-Id: I2c5727f48306140f5d26ea21de51322b833b5c4b Reviewed-by: Marco Bubke Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../effectcomposer/effectcomposerview.cpp | 24 +++++++++++++++++++ .../effectcomposer/effectcomposerview.h | 5 ++++ src/plugins/effectcomposer/uniform.cpp | 8 +++++++ .../propertyeditor/propertyeditorvalue.cpp | 7 +++++- .../propertyeditor/propertyeditorvalue.h | 1 + .../libs/designercore/model/model.cpp | 3 +++ 6 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/plugins/effectcomposer/effectcomposerview.cpp b/src/plugins/effectcomposer/effectcomposerview.cpp index a9726f55182..76ff57d49d5 100644 --- a/src/plugins/effectcomposer/effectcomposerview.cpp +++ b/src/plugins/effectcomposer/effectcomposerview.cpp @@ -6,6 +6,7 @@ #include "effectcomposermodel.h" #include "effectcomposernodesmodel.h" #include "effectcomposerwidget.h" +#include "studioquickwidget.h" #include #include @@ -234,4 +235,27 @@ void EffectComposerView::removeUnusedEffectImports() } } +void EffectComposerView::highlightSupportedProperties(bool highlight, const QString &suffix) +{ + QQmlContext *ctxObj = m_widget->quickWidget()->rootContext(); + ctxObj->setContextProperty("activeDragSuffix", suffix); + ctxObj->setContextProperty("hasActiveDrag", highlight); +} + +void EffectComposerView::dragStarted(QMimeData *mimeData) +{ + if (mimeData->hasFormat(QmlDesigner::Constants::MIME_TYPE_ASSETS)) { + QString format = mimeData->formats()[0]; + const QString assetPath = QString::fromUtf8(mimeData->data(format)).split(',')[0]; + const QString suffix = "*." + assetPath.split('.').last().toLower(); + + highlightSupportedProperties(true, suffix); + } +} + +void EffectComposerView::dragEnded() +{ + highlightSupportedProperties(false); +} + } // namespace EffectComposer diff --git a/src/plugins/effectcomposer/effectcomposerview.h b/src/plugins/effectcomposer/effectcomposerview.h index b8b130f3de3..338960f1f08 100644 --- a/src/plugins/effectcomposer/effectcomposerview.h +++ b/src/plugins/effectcomposer/effectcomposerview.h @@ -41,6 +41,11 @@ public: const QList &lastSelectedNodeList) override; void nodeAboutToBeRemoved(const QmlDesigner::ModelNode &removedNode) override; + void dragStarted(QMimeData *mimeData) override; + void dragEnded() override; + + void highlightSupportedProperties(bool highlight, const QString &suffix = {}); + private: void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; diff --git a/src/plugins/effectcomposer/uniform.cpp b/src/plugins/effectcomposer/uniform.cpp index 590b38b423b..c42f11063d6 100644 --- a/src/plugins/effectcomposer/uniform.cpp +++ b/src/plugins/effectcomposer/uniform.cpp @@ -57,6 +57,14 @@ Uniform::Uniform(const QString &effectName, const QJsonObject &propObj, const QS m_backendValue = new QmlDesigner::PropertyEditorValue(this); m_backendValue->setValue(value); + + connect(m_backendValue, &QmlDesigner::PropertyEditorValue::dropCommitted, + this, [this](const QString &dropData) { + m_backendValue->setValue(dropData); + auto *model = QmlDesigner::QmlDesignerPlugin::instance() + ->currentDesignDocument()->currentModel(); + model->endDrag(); + }); } Uniform::Type Uniform::type() const diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp index 74c1ba65a60..0d85d3f36bb 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp @@ -530,7 +530,12 @@ void PropertyEditorValue::commitDrop(const QString &dropData) }); } - m_modelNode.view()->model()->endDrag(); + emit dropCommitted(dropData); + + if (!m_modelNode.model()) + return; + + m_modelNode.model()->endDrag(); } void PropertyEditorValue::openMaterialEditor(int idx) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h index 997640d377e..d8cee333cbb 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h @@ -200,6 +200,7 @@ signals: void isValidChanged(); void isExplicitChanged(); void hasActiveDragChanged(); + void dropCommitted(QString dropData); private: QStringList generateStringList(const QString &string) const; diff --git a/src/plugins/qmldesigner/libs/designercore/model/model.cpp b/src/plugins/qmldesigner/libs/designercore/model/model.cpp index cd29f942e18..b100cd678ab 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/libs/designercore/model/model.cpp @@ -1948,6 +1948,9 @@ void Model::startDrag(std::unique_ptr mimeData, const QPixmap &icon, void Model::endDrag() { + if (!d->drag) + return; + d->notifyDragEnded(); d->drag.reset(); } From 1050d00fb45d08ed3b3ed576a8dda7443f776dac Mon Sep 17 00:00:00 2001 From: Shrief Gabr Date: Wed, 2 Oct 2024 21:39:21 +0300 Subject: [PATCH 21/44] QmlDesigner: Import QtQuick3D on bundle import if missing Fixes: QDS-13374 Change-Id: Ia038e3eb6e49808da93c5cf3de7088dc40781c2d Reviewed-by: Ali Kianian Reviewed-by: Mahmoud Badri Reviewed-by: Miikka Heikkinen --- .../qmldesigner/components/componentcore/bundlehelper.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp b/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp index 5cae7b8d7c2..347c08330f2 100644 --- a/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp +++ b/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp @@ -136,8 +136,16 @@ void BundleHelper::importBundleToProject() " of Qt Design Studio")); return; } + QString bundleId = importedJsonObj.value("id").toString(); + bool hasQuick3DImport = m_view->model()->hasImport("QtQuick3D"); + + if (!hasQuick3DImport) { + Import import = Import::createLibraryImport("QtQuick3D"); + m_view->model()->changeImports({import}, {}); + } + QTemporaryDir tempDir; QTC_ASSERT(tempDir.isValid(), return); auto bundlePath = Utils::FilePath::fromString(tempDir.path()); From 173148995cd0b50cfa38cd3d7d8404d7d4b44331 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Fri, 4 Oct 2024 17:57:55 +0200 Subject: [PATCH 22/44] QmlDesigner: fix build for older Qt versions Change-Id: Ifca4aa284296718be359ec962408aba65d5463c1 Reviewed-by: Marco Bubke --- .../libs/designercore/projectstorage/qmldocumentparser.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.h index af2dbbe99ca..bdf50aac23e 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.h @@ -25,7 +25,7 @@ public: , m_pathCache{pathCache} {} #else - QmlDocumentParser(ProjectStorage &, PathCache &) + QmlDocumentParser(ProjectStorage &, PathCacheType &) {} #endif From 79ecc5e58c26e7b04d7e6947e2db48fb60a192d0 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Fri, 4 Oct 2024 17:59:13 +0200 Subject: [PATCH 23/44] QmlDesigner: increase QMLDESIGNER_QT6_REQUIRED_VERSION to 6.7.3 Change-Id: I58746dd96db8395f684c0c82c4db54684d0c6954 Reviewed-by: Marco Bubke --- cmake/Utils.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Utils.cmake b/cmake/Utils.cmake index eca19a7dd0b..64473a926c2 100644 --- a/cmake/Utils.cmake +++ b/cmake/Utils.cmake @@ -61,7 +61,7 @@ function(setup_dependencies_component) endfunction() function(configure_qml_designer Qt6_VERSION) - set(QMLDESIGNER_QT6_REQUIRED_VERSION 6.5.4) + set(QMLDESIGNER_QT6_REQUIRED_VERSION 6.7.3) set(QMLDESIGNER_GCC_REQUIRED_VERSION 10.0) set(QMLDESIGNER_CLANG_REQUIRED_VERSION 13.0) set(QMLDESIGNER_APPLECLANG_REQUIRED_VERSION 15.0) From 34f51df1ea2df8beb4091b48c0015771f02cf923 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Thu, 5 Sep 2024 17:46:26 +0300 Subject: [PATCH 24/44] QmlDesigner: Add code editor for Effect Composer Task-number: QDS-13443 Change-Id: I02c7a85336f283e0e55bab24459a91fa299abb40 Reviewed-by: Mahmoud Badri Reviewed-by: Miikka Heikkinen --- .../qtcreator/qmldesigner/designericons.json | 6 + .../EffectComposer.qml | 6 + .../EffectComposerTopBar.qml | 15 +- .../EffectCompositionNode.qml | 24 ++ .../imports/HelperWidgets/Section.qml | 9 + src/plugins/effectcomposer/CMakeLists.txt | 2 + .../effectcomposer/compositionnode.cpp | 67 +++++- src/plugins/effectcomposer/compositionnode.h | 21 ++ .../effectcomposer/effectcodeeditorwidget.cpp | 142 +++++++++++ .../effectcomposer/effectcodeeditorwidget.h | 63 +++++ .../effectcomposer/effectcomposermodel.cpp | 82 ++++++- .../effectcomposer/effectcomposermodel.h | 8 + .../effectshaderscodeeditor.cpp | 226 ++++++++++++++++++ .../effectcomposer/effectshaderscodeeditor.h | 61 +++++ .../bindingeditor/bindingeditorwidget.cpp | 1 - .../components/componentcore/designericons.h | 2 + .../componentcore/modelnodeoperations.cpp | 11 +- 17 files changed, 725 insertions(+), 21 deletions(-) create mode 100644 src/plugins/effectcomposer/effectcodeeditorwidget.cpp create mode 100644 src/plugins/effectcomposer/effectcodeeditorwidget.h create mode 100644 src/plugins/effectcomposer/effectshaderscodeeditor.cpp create mode 100644 src/plugins/effectcomposer/effectshaderscodeeditor.h diff --git a/share/qtcreator/qmldesigner/designericons.json b/share/qtcreator/qmldesigner/designericons.json index 005494b4715..f4f60b7412c 100644 --- a/share/qtcreator/qmldesigner/designericons.json +++ b/share/qtcreator/qmldesigner/designericons.json @@ -241,6 +241,9 @@ "LocalOrientIcon": { "iconName": "localOrient_medium" }, + "LiveUpdateIcon": { + "iconName": "restartParticles_medium" + }, "MoveToolIcon": { "iconName": "move_medium" }, @@ -276,6 +279,9 @@ "SplitViewIcon": { "iconName": "splitScreen_medium" }, + "SyncIcon": { + "iconName": "updateContent_medium" + }, "ToggleGroupIcon": { "Off": { "iconName": "selectOutline_medium" diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposer.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposer.qml index 16525678be8..81c01d5f54e 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposer.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposer.qml @@ -195,6 +195,10 @@ Item { onAssignToSelectedClicked: { root.backendModel.assignToSelected() } + + onOpenShadersCodeEditor: { + root.backendModel.openMainShadersCodeEditor() + } } SplitView { @@ -366,6 +370,8 @@ Item { expanded = wasExpanded dragAnimation.enabled = true } + + onOpenShadersCodeEditor: (idx) => root.backendModel.openShadersCodeEditor(idx) } } // Repeater } // Column diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerTopBar.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerTopBar.qml index 799dbeeddc3..c6e8abe11a3 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerTopBar.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerTopBar.qml @@ -19,6 +19,7 @@ Rectangle { signal saveClicked signal saveAsClicked signal assignToSelectedClicked + signal openShadersCodeEditor Row { spacing: 5 @@ -48,12 +49,24 @@ Rectangle { style: StudioTheme.Values.viewBarButtonStyle buttonIcon: StudioTheme.Constants.saveAs_medium tooltip: qsTr("Save current composition with a new name") - enabled: root.backendModel ? root.backendModel.isEnabled && root.backendModel.currentComposition !== "" + enabled: root.backendModel ? root.backendModel.isEnabled + && root.backendModel.currentComposition !== "" : false onClicked: root.saveAsClicked() } + HelperWidgets.AbstractButton { + style: StudioTheme.Values.viewBarButtonStyle + buttonIcon: StudioTheme.Constants.codeEditor_medium + tooltip: qsTr("Open Code") + enabled: root.backendModel ? root.backendModel.isEnabled + && root.backendModel.currentComposition !== "" + : false + + onClicked: root.openShadersCodeEditor() + } + HelperWidgets.AbstractButton { style: StudioTheme.Values.viewBarButtonStyle buttonIcon: StudioTheme.Constants.assignTo_medium diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNode.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNode.qml index a606461b5c5..ef59468ed60 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNode.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNode.qml @@ -30,10 +30,34 @@ HelperWidgets.Section { eyeEnabled: nodeEnabled eyeButtonToolTip: qsTr("Enable/Disable Node") + signal openShadersCodeEditor(index: int) + onEyeButtonClicked: { nodeEnabled = root.eyeEnabled } + icons: HelperWidgets.IconButton { + icon: StudioTheme.Constants.codeEditor_medium + transparentBg: true + buttonSize: 21 + iconSize: StudioTheme.Values.smallIconFontSize + iconColor: StudioTheme.Values.themeTextColor + iconScale: containsMouse ? 1.2 : 1 + implicitWidth: width + onClicked: root.openShadersCodeEditor(index) + } + + content: Label { + text: root.caption + color: root.labelColor + elide: Text.ElideRight + font.pixelSize: root.sectionFontSize + font.capitalization: root.labelCapitalization + anchors.verticalCenter: parent?.verticalCenter + textFormat: Text.RichText + leftPadding: StudioTheme.Values.toolbarSpacing + } + Column { spacing: 10 diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml index 245b8506a28..232574a2207 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml @@ -39,6 +39,8 @@ Item { textFormat: Text.RichText } + property Item icons + property int leftPadding: StudioTheme.Values.sectionLeftPadding property int rightPadding: 0 property int topPadding: StudioTheme.Values.sectionHeadSpacerHeight @@ -214,6 +216,13 @@ Item { } } + Item { + id: iconsContent + height: header.height + children: [ section.icons ] + Layout.preferredWidth: childrenRect.width + } + IconButton { id: arrow icon: StudioTheme.Constants.sectionToggle diff --git a/src/plugins/effectcomposer/CMakeLists.txt b/src/plugins/effectcomposer/CMakeLists.txt index 71805ea1be2..4e3e7283b3b 100644 --- a/src/plugins/effectcomposer/CMakeLists.txt +++ b/src/plugins/effectcomposer/CMakeLists.txt @@ -6,12 +6,14 @@ add_qtc_plugin(EffectComposer Qt::Core Qt::CorePrivate Qt::Widgets Qt::Qml Qt::QmlPrivate Qt::Quick QtCreator::Utils SOURCES + effectcodeeditorwidget.cpp effectcodeeditorwidget.h effectcomposerplugin.cpp effectcomposerwidget.cpp effectcomposerwidget.h effectcomposerview.cpp effectcomposerview.h effectcomposermodel.cpp effectcomposermodel.h effectcomposernodesmodel.cpp effectcomposernodesmodel.h effectcomposeruniformsmodel.cpp effectcomposeruniformsmodel.h + effectshaderscodeeditor.cpp effectshaderscodeeditor.h effectnode.cpp effectnode.h effectnodescategory.cpp effectnodescategory.h compositionnode.cpp compositionnode.h diff --git a/src/plugins/effectcomposer/compositionnode.cpp b/src/plugins/effectcomposer/compositionnode.cpp index a69cd00e075..5426d55f2cb 100644 --- a/src/plugins/effectcomposer/compositionnode.cpp +++ b/src/plugins/effectcomposer/compositionnode.cpp @@ -3,8 +3,9 @@ #include "compositionnode.h" -#include "effectutils.h" #include "effectcomposeruniformsmodel.h" +#include "effectshaderscodeeditor.h" +#include "effectutils.h" #include "propertyhandler.h" #include "uniform.h" @@ -44,6 +45,8 @@ CompositionNode::CompositionNode(const QString &effectName, const QString &qenPa } } +CompositionNode::~CompositionNode() = default; + QString CompositionNode::fragmentCode() const { return m_fragmentCode; @@ -110,8 +113,8 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c m_name = json.value("name").toString(); m_description = json.value("description").toString(); - m_fragmentCode = EffectUtils::codeFromJsonArray(json.value("fragmentCode").toArray()); - m_vertexCode = EffectUtils::codeFromJsonArray(json.value("vertexCode").toArray()); + setFragmentCode(EffectUtils::codeFromJsonArray(json.value("fragmentCode").toArray())); + setVertexCode(EffectUtils::codeFromJsonArray(json.value("vertexCode").toArray())); if (json.contains("extraMargin")) m_extraMargin = json.value("extraMargin").toInt(); @@ -154,6 +157,36 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c } } +void CompositionNode::ensureShadersCodeEditor() +{ + if (m_shadersCodeEditor) + return; + + m_shadersCodeEditor = Utils::makeUniqueObjectLatePtr(name()); + m_shadersCodeEditor->setFragmentValue(fragmentCode()); + m_shadersCodeEditor->setVertexValue(vertexCode()); + + connect(m_shadersCodeEditor.get(), &EffectShadersCodeEditor::vertexValueChanged, this, [this] { + setVertexCode(m_shadersCodeEditor->vertexValue()); + }); + + connect(m_shadersCodeEditor.get(), &EffectShadersCodeEditor::fragmentValueChanged, this, [this] { + setFragmentCode(m_shadersCodeEditor->fragmentValue()); + }); + + connect( + m_shadersCodeEditor.get(), + &EffectShadersCodeEditor::rebakeRequested, + this, + &CompositionNode::rebakeRequested); +} + +void CompositionNode::requestRebakeIfLiveUpdateMode() +{ + if (m_shadersCodeEditor && m_shadersCodeEditor->liveUpdate()) + emit rebakeRequested(); +} + QList CompositionNode::uniforms() const { return m_uniforms; @@ -189,6 +222,34 @@ void CompositionNode::setRefCount(int count) emit isDepencyChanged(); } +void CompositionNode::setFragmentCode(const QString &fragmentCode) +{ + if (m_fragmentCode == fragmentCode) + return; + + m_fragmentCode = fragmentCode; + emit fragmentCodeChanged(); + + requestRebakeIfLiveUpdateMode(); +} + +void CompositionNode::setVertexCode(const QString &vertexCode) +{ + if (m_vertexCode == vertexCode) + return; + + m_vertexCode = vertexCode; + emit vertexCodeChanged(); + + requestRebakeIfLiveUpdateMode(); +} + +void CompositionNode::openShadersCodeEditor() +{ + ensureShadersCodeEditor(); + m_shadersCodeEditor->showWidget(); +} + QString CompositionNode::name() const { return m_name; diff --git a/src/plugins/effectcomposer/compositionnode.h b/src/plugins/effectcomposer/compositionnode.h index 433468688a2..dcd66072afa 100644 --- a/src/plugins/effectcomposer/compositionnode.h +++ b/src/plugins/effectcomposer/compositionnode.h @@ -5,11 +5,15 @@ #include "effectcomposeruniformsmodel.h" +#include + #include #include namespace EffectComposer { +class EffectShadersCodeEditor; + class CompositionNode : public QObject { Q_OBJECT @@ -18,6 +22,12 @@ class CompositionNode : public QObject Q_PROPERTY(bool nodeEnabled READ isEnabled WRITE setIsEnabled NOTIFY isEnabledChanged) Q_PROPERTY(bool isDependency READ isDependency NOTIFY isDepencyChanged) Q_PROPERTY(QObject *nodeUniformsModel READ uniformsModel NOTIFY uniformsModelChanged) + Q_PROPERTY( + QString fragmentCode + READ fragmentCode + WRITE setFragmentCode + NOTIFY fragmentCodeChanged) + Q_PROPERTY(QString vertexCode READ vertexCode WRITE setVertexCode NOTIFY vertexCodeChanged) public: enum NodeType { @@ -27,6 +37,7 @@ public: }; CompositionNode(const QString &effectName, const QString &qenPath, const QJsonObject &json = {}); + virtual ~CompositionNode(); QString fragmentCode() const; QString vertexCode() const; @@ -54,14 +65,23 @@ public: int extraMargin() const { return m_extraMargin; } + void setFragmentCode(const QString &fragmentCode); + void setVertexCode(const QString &vertexCode); + + void openShadersCodeEditor(); + signals: void uniformsModelChanged(); void isEnabledChanged(); void isDepencyChanged(); void rebakeRequested(); + void fragmentCodeChanged(); + void vertexCodeChanged(); private: void parse(const QString &effectName, const QString &qenPath, const QJsonObject &json); + void ensureShadersCodeEditor(); + void requestRebakeIfLiveUpdateMode(); QString m_name; NodeType m_type = CustomNode; @@ -77,6 +97,7 @@ private: QList m_uniforms; EffectComposerUniformsModel m_unifomrsModel; + Utils::UniqueObjectLatePtr m_shadersCodeEditor; }; } // namespace EffectComposer diff --git a/src/plugins/effectcomposer/effectcodeeditorwidget.cpp b/src/plugins/effectcomposer/effectcodeeditorwidget.cpp new file mode 100644 index 00000000000..c6fcf7c952e --- /dev/null +++ b/src/plugins/effectcomposer/effectcodeeditorwidget.cpp @@ -0,0 +1,142 @@ +// 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 "effectcodeeditorwidget.h" + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +namespace EffectComposer { + +constexpr char EFFECTEDITOR_CONTEXT_ID[] = "EffectEditor.EffectEditorContext"; + +EffectCodeEditorWidget::EffectCodeEditorWidget() + : m_context(new Core::IContext(this)) +{ + Core::Context context(EFFECTEDITOR_CONTEXT_ID, ProjectExplorer::Constants::QMLJS_LANGUAGE_ID); + + m_context->setWidget(this); + m_context->setContext(context); + Core::ICore::addContextObject(m_context); + + Utils::TransientScrollAreaSupport::support(this); + + /* + * We have to register our own active auto completion shortcut, because the original shortcut will + * use the cursor position of the original editor in the editor manager. + */ + m_completionAction = new QAction(tr("Trigger Completion"), this); + + Core::Command *command = Core::ActionManager::registerAction( + m_completionAction, TextEditor::Constants::COMPLETE_THIS, context); + command->setDefaultKeySequence(QKeySequence( + Core::useMacShortcuts + ? tr("Meta+Space") + : tr("Ctrl+Space"))); + + connect(m_completionAction, &QAction::triggered, this, [this] { + invokeAssist(TextEditor::Completion); + }); +} + +EffectCodeEditorWidget::~EffectCodeEditorWidget() +{ + unregisterAutoCompletion(); +} + +void EffectCodeEditorWidget::unregisterAutoCompletion() +{ + if (m_completionAction) { + Core::ActionManager::unregisterAction(m_completionAction, TextEditor::Constants::COMPLETE_THIS); + delete m_completionAction; + m_completionAction = nullptr; + } +} + +void EffectCodeEditorWidget::setEditorTextWithIndentation(const QString &text) +{ + auto *doc = document(); + doc->setPlainText(text); + + // We don't need to indent an empty text but is also needed for safer text.length()-1 below + if (text.isEmpty()) + return; + + auto modifier = std::make_unique(doc, QTextCursor{doc}); + modifier->indent(0, text.length()-1); +} + +EffectDocument::EffectDocument() + : QmlJSEditor::QmlJSEditorDocument(EFFECTEDITOR_CONTEXT_ID) + , m_semanticHighlighter(new QmlJSEditor::SemanticHighlighter(this)) +{} + +EffectDocument::~EffectDocument() +{ + delete m_semanticHighlighter; +} + +void EffectDocument::applyFontSettings() +{ + TextDocument::applyFontSettings(); + m_semanticHighlighter->updateFontSettings(fontSettings()); + if (!isSemanticInfoOutdated() && semanticInfo().isValid()) + m_semanticHighlighter->rerun(semanticInfo()); +} + +void EffectDocument::triggerPendingUpdates() +{ + TextDocument::triggerPendingUpdates(); // Calls applyFontSettings if necessary + if (!isSemanticInfoOutdated() && semanticInfo().isValid()) + m_semanticHighlighter->rerun(semanticInfo()); +} + +EffectCodeEditorFactory::EffectCodeEditorFactory() +{ + setId(EFFECTEDITOR_CONTEXT_ID); + setDisplayName(::Core::Tr::tr("Effect Code Editor")); + addMimeType(EFFECTEDITOR_CONTEXT_ID); + addMimeType(Utils::Constants::QML_MIMETYPE); + addMimeType(Utils::Constants::QMLTYPES_MIMETYPE); + addMimeType(Utils::Constants::JS_MIMETYPE); + + setDocumentCreator([]() { return new EffectDocument; }); + setEditorWidgetCreator([]() { return new EffectCodeEditorWidget; }); + setEditorCreator([]() { return new QmlJSEditor::QmlJSEditor; }); + setAutoCompleterCreator([]() { return new QmlJSEditor::AutoCompleter; }); + setCommentDefinition(Utils::CommentDefinition::CppStyle); + setParenthesesMatchingEnabled(true); + setCodeFoldingSupported(true); + + addHoverHandler(new QmlJSEditor::QmlJSHoverHandler); + setCompletionAssistProvider(new QmlJSEditor::QmlJSCompletionAssistProvider); +} + +void EffectCodeEditorFactory::decorateEditor(TextEditor::TextEditorWidget *editor) +{ + editor->textDocument()->resetSyntaxHighlighter( + [] { return new QmlJSEditor::QmlJSHighlighter(); }); + editor->textDocument()->setIndenter(QmlJSEditor::createQmlJsIndenter( + editor->textDocument()->document())); + editor->setAutoCompleter(new QmlJSEditor::AutoCompleter); +} + +} // namespace EffectComposer diff --git a/src/plugins/effectcomposer/effectcodeeditorwidget.h b/src/plugins/effectcomposer/effectcodeeditorwidget.h new file mode 100644 index 00000000000..1ea043dc68e --- /dev/null +++ b/src/plugins/effectcomposer/effectcodeeditorwidget.h @@ -0,0 +1,63 @@ +// 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 + +QT_FORWARD_DECLARE_CLASS(QAction) + +namespace QmlJSEditor { +class SemanticHighlighter; +} + +namespace Core { +class IContext; +} + +namespace EffectComposer { + +class EffectCodeEditorWidget : public QmlJSEditor::QmlJSEditorWidget +{ + Q_OBJECT + +public: + EffectCodeEditorWidget(); + ~EffectCodeEditorWidget() override; + + void unregisterAutoCompletion(); + void setEditorTextWithIndentation(const QString &text); + +signals: + void returnKeyClicked(); + +public: + Core::IContext *m_context = nullptr; + QAction *m_completionAction = nullptr; + bool m_isMultiline = true; +}; + +class EffectDocument : public QmlJSEditor::QmlJSEditorDocument +{ +public: + EffectDocument(); + ~EffectDocument(); + +protected: + void applyFontSettings() final; + void triggerPendingUpdates() final; + +private: + QmlJSEditor::SemanticHighlighter *m_semanticHighlighter = nullptr; +}; + +class EffectCodeEditorFactory : public TextEditor::TextEditorFactory +{ +public: + EffectCodeEditorFactory(); + + static void decorateEditor(TextEditor::TextEditorWidget *editor); +}; + +} // namespace EffectComposer diff --git a/src/plugins/effectcomposer/effectcomposermodel.cpp b/src/plugins/effectcomposer/effectcomposermodel.cpp index 3561f46a3f0..673c6c62b70 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.cpp +++ b/src/plugins/effectcomposer/effectcomposermodel.cpp @@ -4,6 +4,7 @@ #include "effectcomposermodel.h" #include "compositionnode.h" +#include "effectshaderscodeeditor.h" #include "effectutils.h" #include "propertyhandler.h" #include "syntaxhighlighterdata.h" @@ -252,6 +253,8 @@ void EffectComposerModel::setFragmentShader(const QString &newFragmentShader) return; m_fragmentShader = newFragmentShader; + + rebakeIfLiveUpdateMode(); } QString EffectComposerModel::vertexShader() const @@ -265,6 +268,8 @@ void EffectComposerModel::setVertexShader(const QString &newVertexShader) return; m_vertexShader = newVertexShader; + + rebakeIfLiveUpdateMode(); } QString EffectComposerModel::qmlComponentString() const @@ -990,6 +995,50 @@ void EffectComposerModel::saveComposition(const QString &name) setHasUnsavedChanges(false); } +void EffectComposerModel::openShadersCodeEditor(int idx) +{ + if (m_nodes.size() < idx || idx < 0) + return; + + CompositionNode *node = m_nodes.at(idx); + node->openShadersCodeEditor(); +} + +void EffectComposerModel::openMainShadersCodeEditor() +{ + if (!m_shadersCodeEditor) { + m_shadersCodeEditor = Utils::makeUniqueObjectLatePtr( + currentComposition()); + m_shadersCodeEditor->setFragmentValue(generateFragmentShader(true)); + m_shadersCodeEditor->setVertexValue(generateVertexShader(true)); + + connect( + m_shadersCodeEditor.get(), + &EffectShadersCodeEditor::vertexValueChanged, + this, + [this] { + setVertexShader(m_shadersCodeEditor->vertexValue()); + setHasUnsavedChanges(true); + }); + + connect( + m_shadersCodeEditor.get(), + &EffectShadersCodeEditor::fragmentValueChanged, + this, + [this] { + setFragmentShader(m_shadersCodeEditor->fragmentValue()); + setHasUnsavedChanges(true); + }); + + connect( + m_shadersCodeEditor.get(), + &EffectShadersCodeEditor::rebakeRequested, + this, + &EffectComposerModel::startRebakeTimer); + } + m_shadersCodeEditor->showWidget(); +} + void EffectComposerModel::openComposition(const QString &path) { clear(true); @@ -1828,7 +1877,6 @@ void EffectComposerModel::bakeShaders() runQsb(qsbPath, outPaths, false); runQsb(qsbPrevPath, outPrevPaths, true); - } bool EffectComposerModel::shadersUpToDate() const @@ -2003,14 +2051,16 @@ QString EffectComposerModel::getQmlComponentString(bool localFiles) void EffectComposerModel::connectCompositionNode(CompositionNode *node) { - connect(qobject_cast(node->uniformsModel()), - &EffectComposerUniformsModel::dataChanged, this, [this] { - setHasUnsavedChanges(true); - }); - connect(node, &CompositionNode::rebakeRequested, this, [this] { - // This can come multiple times in a row in response to property changes, so let's buffer it - m_rebakeTimer.start(200); - }); + auto setUnsaved = std::bind(&EffectComposerModel::setHasUnsavedChanges, this, true); + connect( + qobject_cast(node->uniformsModel()), + &EffectComposerUniformsModel::dataChanged, + this, + setUnsaved); + + connect(node, &CompositionNode::rebakeRequested, this, &EffectComposerModel::startRebakeTimer); + connect(node, &CompositionNode::fragmentCodeChanged, this, setUnsaved); + connect(node, &CompositionNode::vertexCodeChanged, this, setUnsaved); } void EffectComposerModel::updateExtraMargin() @@ -2020,6 +2070,18 @@ void EffectComposerModel::updateExtraMargin() m_extraMargin = qMax(node->extraMargin(), m_extraMargin); } +void EffectComposerModel::startRebakeTimer() +{ + // This can come multiple times in a row in response to property changes, so let's buffer it + m_rebakeTimer.start(200); +} + +void EffectComposerModel::rebakeIfLiveUpdateMode() +{ + if (m_shadersCodeEditor && m_shadersCodeEditor->liveUpdate()) + startRebakeTimer(); +} + QSet EffectComposerModel::getExposedProperties(const QByteArray &qmlContent) { QSet returnSet; @@ -2051,6 +2113,8 @@ void EffectComposerModel::setCurrentComposition(const QString &newCurrentComposi m_currentComposition = newCurrentComposition; emit currentCompositionChanged(); + + m_shadersCodeEditor.reset(); } Utils::FilePath EffectComposerModel::compositionPath() const diff --git a/src/plugins/effectcomposer/effectcomposermodel.h b/src/plugins/effectcomposer/effectcomposermodel.h index 098cc730069..9079e9bfd35 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.h +++ b/src/plugins/effectcomposer/effectcomposermodel.h @@ -6,6 +6,7 @@ #include "shaderfeatures.h" #include +#include #include #include @@ -26,6 +27,7 @@ class Process; namespace EffectComposer { class CompositionNode; +class EffectShadersCodeEditor; class Uniform; struct EffectError { @@ -100,6 +102,9 @@ public: Q_INVOKABLE void saveComposition(const QString &name); + Q_INVOKABLE void openShadersCodeEditor(int idx); + Q_INVOKABLE void openMainShadersCodeEditor(); + void openComposition(const QString &path); QString currentComposition() const; @@ -190,6 +195,8 @@ private: void connectCompositionNode(CompositionNode *node); void updateExtraMargin(); + void startRebakeTimer(); + void rebakeIfLiveUpdateMode(); QSet getExposedProperties(const QByteArray &qmlContent); QList m_nodes; @@ -230,6 +237,7 @@ private: int m_extraMargin = 0; QString m_effectTypePrefix; Utils::FilePath m_compositionPath; + Utils::UniqueObjectLatePtr m_shadersCodeEditor; const QRegularExpression m_spaceReg = QRegularExpression("\\s+"); }; diff --git a/src/plugins/effectcomposer/effectshaderscodeeditor.cpp b/src/plugins/effectcomposer/effectshaderscodeeditor.cpp new file mode 100644 index 00000000000..95fe30a54e6 --- /dev/null +++ b/src/plugins/effectcomposer/effectshaderscodeeditor.cpp @@ -0,0 +1,226 @@ +// 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 "effectshaderscodeeditor.h" +#include "effectcodeeditorwidget.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace { + +using IconId = QmlDesigner::DesignerIcons::IconId; + +inline constexpr char EFFECTCOMPOSER_LIVE_UPDATE_KEY[] = "EffectComposer/CodeEditor/LiveUpdate"; + +QIcon toolbarIcon(IconId iconId) +{ + return QmlDesigner::DesignerActionManager::instance().toolbarIcon(iconId); +}; + +} // namespace + +namespace EffectComposer { + +EffectShadersCodeEditor::EffectShadersCodeEditor(const QString &title, QWidget *parent) + : QWidget(parent) + , m_settings(new QSettings(qApp->organizationName(), qApp->applicationName(), this)) +{ + setWindowFlag(Qt::Tool, true); + setWindowTitle(title); + + m_fragmentEditor = createJSEditor(); + m_vertexEditor = createJSEditor(); + + connect( + m_fragmentEditor, + &QPlainTextEdit::textChanged, + this, + &EffectShadersCodeEditor::fragmentValueChanged); + connect( + m_vertexEditor, + &QPlainTextEdit::textChanged, + this, + &EffectShadersCodeEditor::vertexValueChanged); + + setupUIComponents(); +} + +EffectShadersCodeEditor::~EffectShadersCodeEditor() +{ + m_fragmentEditor->deleteLater(); + m_vertexEditor->deleteLater(); +} + +void EffectShadersCodeEditor::showWidget() +{ + readAndApplyLiveUpdateSettings(); + show(); + raise(); + m_vertexEditor->setFocus(); +} + +void EffectShadersCodeEditor::showWidget(int x, int y) +{ + showWidget(); + move(QPoint(x, y)); +} + +QString EffectShadersCodeEditor::fragmentValue() const +{ + if (!m_fragmentEditor) + return {}; + + return m_fragmentEditor->document()->toPlainText(); +} + +void EffectShadersCodeEditor::setFragmentValue(const QString &text) +{ + if (m_fragmentEditor) + m_fragmentEditor->setEditorTextWithIndentation(text); +} + +QString EffectShadersCodeEditor::vertexValue() const +{ + if (!m_vertexEditor) + return {}; + + return m_vertexEditor->document()->toPlainText(); +} + +void EffectShadersCodeEditor::setVertexValue(const QString &text) +{ + if (m_vertexEditor) + m_vertexEditor->setEditorTextWithIndentation(text); +} + +bool EffectShadersCodeEditor::liveUpdate() const +{ + return m_liveUpdate; +} + +void EffectShadersCodeEditor::setLiveUpdate(bool liveUpdate) +{ + if (m_liveUpdate == liveUpdate) + return; + + m_liveUpdate = liveUpdate; + writeLiveUpdateSettings(); + + emit liveUpdateChanged(m_liveUpdate); + + if (m_liveUpdate) + emit rebakeRequested(); +} + +EffectCodeEditorWidget *EffectShadersCodeEditor::createJSEditor() +{ + static EffectCodeEditorFactory f; + TextEditor::BaseTextEditor *editor = qobject_cast( + f.createEditor()); + Q_ASSERT(editor); + + editor->setParent(this); + + EffectCodeEditorWidget *editorWidget = qobject_cast( + editor->editorWidget()); + Q_ASSERT(editorWidget); + + editorWidget->setLineNumbersVisible(false); + editorWidget->setMarksVisible(false); + editorWidget->setCodeFoldingSupported(false); + editorWidget->setTabChangesFocus(true); + editorWidget->unregisterAutoCompletion(); + editorWidget->setParent(this); + editorWidget->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); + + return editorWidget; +} + +void EffectShadersCodeEditor::setupUIComponents() +{ + QVBoxLayout *verticalLayout = new QVBoxLayout(this); + QTabWidget *tabWidget = new QTabWidget(this); + + tabWidget->addTab(m_fragmentEditor, tr("Fragment Shader")); + tabWidget->addTab(m_vertexEditor, tr("Vertex Shader")); + + verticalLayout->setContentsMargins(0, 0, 0, 0); + verticalLayout->addWidget(createToolbar()); + verticalLayout->addWidget(tabWidget); + + this->resize(660, 240); +} + +void EffectShadersCodeEditor::closeEvent(QCloseEvent *event) +{ + QWidget::closeEvent(event); + + if (!liveUpdate()) + emit rebakeRequested(); +} + +void EffectShadersCodeEditor::writeLiveUpdateSettings() +{ + m_settings->setValue(EFFECTCOMPOSER_LIVE_UPDATE_KEY, m_liveUpdate); +} + +void EffectShadersCodeEditor::readAndApplyLiveUpdateSettings() +{ + bool liveUpdateStatus = m_settings->value(EFFECTCOMPOSER_LIVE_UPDATE_KEY, false).toBool(); + + setLiveUpdate(liveUpdateStatus); +} + +QToolBar *EffectShadersCodeEditor::createToolbar() +{ + using QmlDesigner::Theme; + + QToolBar *toolbar = new QToolBar(this); + + toolbar->setFixedHeight(Theme::toolbarSize()); + toolbar->setFloatable(false); + toolbar->setContentsMargins(0, 0, 0, 0); + + toolbar->setStyleSheet(Theme::replaceCssColors( + QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css")))); + + QAction *liveUpdateButton + = toolbar->addAction(toolbarIcon(IconId::LiveUpdateIcon), tr("Live Update")); + liveUpdateButton->setCheckable(true); + connect(liveUpdateButton, &QAction::toggled, this, &EffectShadersCodeEditor::setLiveUpdate); + + QAction *applyAction = toolbar->addAction(toolbarIcon(IconId::SyncIcon), tr("Apply")); + connect(applyAction, &QAction::triggered, this, &EffectShadersCodeEditor::rebakeRequested); + + auto syncLive = [liveUpdateButton, applyAction](bool liveState) { + liveUpdateButton->setChecked(liveState); + applyAction->setDisabled(liveState); + }; + + connect(this, &EffectShadersCodeEditor::liveUpdateChanged, this, syncLive); + syncLive(liveUpdate()); + + toolbar->addAction(liveUpdateButton); + toolbar->addAction(applyAction); + + return toolbar; +} + +} // namespace EffectComposer diff --git a/src/plugins/effectcomposer/effectshaderscodeeditor.h b/src/plugins/effectcomposer/effectshaderscodeeditor.h new file mode 100644 index 00000000000..f797315f4a6 --- /dev/null +++ b/src/plugins/effectcomposer/effectshaderscodeeditor.h @@ -0,0 +1,61 @@ +// 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 + +QT_FORWARD_DECLARE_CLASS(QSettings) +QT_FORWARD_DECLARE_CLASS(QToolBar) + +namespace EffectComposer { + +class EffectCodeEditorWidget; + +class EffectShadersCodeEditor : public QWidget +{ + Q_OBJECT + Q_PROPERTY(bool liveUpdate READ liveUpdate WRITE setLiveUpdate NOTIFY liveUpdateChanged) + +public: + EffectShadersCodeEditor(const QString &title = tr("Untitled Editor"), QWidget *parent = nullptr); + ~EffectShadersCodeEditor() override; + + void showWidget(); + void showWidget(int x, int y); + + QString fragmentValue() const; + void setFragmentValue(const QString &text); + + QString vertexValue() const; + void setVertexValue(const QString &text); + + bool liveUpdate() const; + void setLiveUpdate(bool liveUpdate); + +signals: + void liveUpdateChanged(bool); + void fragmentValueChanged(); + void vertexValueChanged(); + void rebakeRequested(); + +protected: + using QWidget::show; + EffectCodeEditorWidget *createJSEditor(); + void setupUIComponents(); + + void closeEvent(QCloseEvent *event) override; + +private: + void writeLiveUpdateSettings(); + void readAndApplyLiveUpdateSettings(); + QToolBar *createToolbar(); + + QSettings *m_settings = nullptr; + QPointer m_fragmentEditor; + QPointer m_vertexEditor; + + bool m_liveUpdate = false; +}; + +} // namespace EffectComposer diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp index 07497c935e0..652f3838539 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp @@ -21,7 +21,6 @@ #include -#include #include #include diff --git a/src/plugins/qmldesigner/components/componentcore/designericons.h b/src/plugins/qmldesigner/components/componentcore/designericons.h index 1bce6581bdb..98edfac0b59 100644 --- a/src/plugins/qmldesigner/components/componentcore/designericons.h +++ b/src/plugins/qmldesigner/components/componentcore/designericons.h @@ -80,6 +80,7 @@ public: LightDirectionalIcon, LightPointIcon, LightSpotIcon, + LiveUpdateIcon, LocalOrientIcon, MakeComponentIcon, MaterialIcon, @@ -107,6 +108,7 @@ public: SnappingIcon, SnappingConfIcon, SplitViewIcon, + SyncIcon, TimelineIcon, ToggleGroupIcon, VisibilityIcon diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index 4f5bdab700d..950575888e6 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -1759,13 +1759,10 @@ void editInEffectComposer(const SelectionContext &selectionContext) bool isEffectComposerActivated() { - const ExtensionSystem::PluginSpecs specs = ExtensionSystem::PluginManager::plugins(); - return std::ranges::find_if(specs, - [](ExtensionSystem::PluginSpec *spec) { - return spec->name() == "EffectComposer" - && spec->isEffectivelyEnabled(); - }) - != specs.end(); + using namespace ExtensionSystem; + return Utils::anyOf(PluginManager::plugins(), [](PluginSpec *spec) { + return spec->name() == "EffectComposer" && spec->isEffectivelyEnabled(); + }); } void openEffectComposer(const QString &filePath) From 2cfeb2ceddc78118a0a50c60f132aa7cc047e709 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 16 Feb 2024 16:43:22 +0100 Subject: [PATCH 25/44] QmlDesigner: Fix crash observed during drag and drop MoveManipulator::end() is called from the dragtool and in this case m_itemList can contain a dangling pointer. m_view->scene()->allFormEditorItems().contains(item) is checking for this case. Change-Id: I367600d7136233d32c9c1683c1be0afcf928fc58 Reviewed-by: Miikka Heikkinen --- .../qmldesigner/components/formeditor/movemanipulator.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp index 167282ea90f..516e7a3c609 100644 --- a/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp +++ b/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp @@ -101,8 +101,9 @@ bool MoveManipulator::itemsCanReparented() const void MoveManipulator::setDirectUpdateInNodeInstances(bool directUpdate) { - for (FormEditorItem* item : std::as_const(m_itemList)) { - if (item && item->qmlItemNode().isValid()) + const auto allFormEditorItems = m_view->scene()->allFormEditorItems(); + for (FormEditorItem *item : std::as_const(m_itemList)) { + if (item && allFormEditorItems.contains(item) && item->qmlItemNode().isValid()) item->qmlItemNode().nodeInstance().setDirectUpdate(directUpdate); } } From 7df954c52b2ca60a7dc3d25ec0f1c52a74db526f Mon Sep 17 00:00:00 2001 From: Johanna Vanhatapio Date: Thu, 10 Oct 2024 13:47:12 +0300 Subject: [PATCH 26/44] Doc: Remove Model Editor docs Task-number: QDS-13221 Change-Id: I4b24e5344c71e0eebe48c9deb5a3c5214cd77f01 Reviewed-by: Mats Honkamaa Reviewed-by: Ali Kianian --- .../config/style/qt5-sidebar.html | 2 - .../images/edit-list-model-model-editor.webp | Bin 16430 -> 0 bytes .../images/model-editor-new-model.webp | Bin 5832 -> 0 bytes .../images/repeater3d-model-editor.webp | Bin 10202 -> 0 bytes .../images/studio-edit-list-model.webp | Bin 0 -> 3206 bytes .../src/components/qtquick-data-models.qdoc | 14 +-- .../src/qtdesignstudio-toc.qdoc | 2 - .../qtdesignstudio-3d-repeater-3d.qdoc | 93 ++++++++++++------ .../views/qtquick-connection-editor-json.qdoc | 63 ------------ .../src/views/qtquick-connection-editor.qdoc | 5 - .../src/views/studio-model-editor.qdoc | 62 ------------ 11 files changed, 69 insertions(+), 172 deletions(-) delete mode 100644 doc/qtdesignstudio/images/edit-list-model-model-editor.webp delete mode 100644 doc/qtdesignstudio/images/model-editor-new-model.webp delete mode 100644 doc/qtdesignstudio/images/repeater3d-model-editor.webp create mode 100644 doc/qtdesignstudio/images/studio-edit-list-model.webp delete mode 100644 doc/qtdesignstudio/src/views/qtquick-connection-editor-json.qdoc delete mode 100644 doc/qtdesignstudio/src/views/studio-model-editor.qdoc diff --git a/doc/qtdesignstudio/config/style/qt5-sidebar.html b/doc/qtdesignstudio/config/style/qt5-sidebar.html index e88ece7b7ae..798cbe5a41e 100644 --- a/doc/qtdesignstudio/config/style/qt5-sidebar.html +++ b/doc/qtdesignstudio/config/style/qt5-sidebar.html @@ -120,7 +120,6 @@
  • Data
      -
    • Connecting Properties to JSON Data Source
    • Data Models
    • Lists and Other Data Models
    • Loading Placeholder Data
    • @@ -442,7 +441,6 @@
    • Effect Composer
    • File System
    • Material Editor and Browser
    • -
    • Model Editor
    • Navigator
    • Open Documents
    • Projects
    • diff --git a/doc/qtdesignstudio/images/edit-list-model-model-editor.webp b/doc/qtdesignstudio/images/edit-list-model-model-editor.webp deleted file mode 100644 index e7f47c6402cf513408e3abf1fcdd02849b60ef31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16430 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 KzO-M;!vFx?47j-f diff --git a/doc/qtdesignstudio/images/model-editor-new-model.webp b/doc/qtdesignstudio/images/model-editor-new-model.webp deleted file mode 100644 index 6ea705a047b9b83cf86a385aeb2dc40decdf11bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5832 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 diff --git a/doc/qtdesignstudio/images/repeater3d-model-editor.webp b/doc/qtdesignstudio/images/repeater3d-model-editor.webp deleted file mode 100644 index e0e608736688e0f263656bedefee6fe3ad3dd505..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10202 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 \uicontrol Views to the \uicontrol Navigator or \uicontrol {2D} view. \li Right-click the view in \uicontrol Navigator, and select - \uicontrol {Edit Model} in the context-menu to open the - \uicontrol {Model Editor} view. - \image edit-list-model-model-editor.webp "List view in Model Editor" - \li Double-click a cell to edit its value. - \li Use the toolbar buttons to add or remove rows and columns. - In a list, each column represents a property, and each row adds a + \uicontrol {Edit List Model} in the context-menu to open + the list model editor. + \image studio-edit-list-model.webp "List view in the list model editor" + \li Double-click the column headings and cells to change their values. + \li Use the toolbar buttons to add, remove, or move rows and columns. + In a list, each column represents a property and each row adds a list item. \endlist diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc index abc575e8d9b..b9229af03c8 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc @@ -29,7 +29,6 @@ \li \l{Effect Composer} \li \l{File System} \li \l{Material Editor and Browser} - \li \l{Model Editor} \li \l{Navigator} \li \l{Open Documents} \li \l{Projects} @@ -134,7 +133,6 @@ \li\l{Connecting Components to Signals} \li\l{Adding Bindings Between Properties} \li\l{Specifying Custom Properties} - \li\l{Connecting Properties to JSON Data Source} \endlist \li \l{Working with States} \endlist diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-repeater-3d.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-repeater-3d.qdoc index 5cf2370cc98..56a2a803705 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-repeater-3d.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-repeater-3d.qdoc @@ -96,44 +96,75 @@ \endlist \image repeater3d-numeric-model.webp - \section1 Adding a Repeater3D Component with a Model + \section1 Adding a Repeater3D Component with a List Model This section explains how to add a \uicontrol Repeater3D component with - a model to your \QDS project: + a list model to your \QDS project: To add a \uicontrol Repeater3D component: \list 1 \li Drag a \uicontrol Repeater3D component from \uicontrol Components to \e scene in \uicontrol Navigator. - \li Go to \uicontrol {Model Editor} and create a new model with the name - \e planetModel. - \li Add the following columns and data to the model. - \raw HTML - - - - - - - - - - - - - - - - - -
      name (String)radius (Real)
      Mars3.39
      Earth6.37
      Venus6.05
      - \endraw - \note You can also import a model in JSON or CSV format. See \l {Importing a Data Model}. - \image repeater3d-model-editor.webp - \li In \uicontrol Navigator, select \e{_3DRepeater}. - \li In \uicontrol Properties, set \uicontrol Model to \e {DataStore.planetModel}. + \li You need to enter the QML code for the \uicontrol ListModel manually. + Go to the \uicontrol {Code} view and enter the following code somewhere + inside the root object: + \code qml + ListModel { + id: planetModel + ListElement { + name: "Mars" + radius: 3.39 + } + ListElement { + name: "Earth" + radius: 6.37 + } + ListElement { + name: "Venus" + radius: 6.05 + } + } + \endcode + The default root object for a \QDS project is \uicontrol Rectangle, so + you can paste the \uicontrol ListModel code, for example, like this: + \code qml + Rectangle { + width: Constants.width + height: Constants.height + color: Constants.backgroundColor + + ListModel { + id: planetModel + ListElement { + name: "Mars" + radius: 3.39 + } + ListElement { + name: "Earth" + radius: 6.37 + } + ListElement { + name: "Venus" + radius: 6.05 + } + } + View3D { + id: view3D + anchors.fill: parent + ... + \endcode + \li In the \uicontrol {Code} view, add \c {model: planetModel} to the + \uicontrol Repeater3D object to tell that you want to use your + \uicontrol ListModel as the model for the \uicontrol Repeater3D object. \endlist + \code qml + Repeater3D { + id: repeater3D + model: planetModel + } + \endcode + Now, you have set up the \uicontrol Repeater3D component to use a \uicontrol ListModel to draw the items. Next, you need to add the item to draw. In this example, you are using a \uicontrol Sphere. @@ -147,7 +178,7 @@ next to \uicontrol Scale > \uicontrol X. \li Select \uicontrol {Set binding} to open \uicontrol {Binding Editor}. \li In the binding editor, enter \c{radius}. This sets the X - scale to the radius value defined in the model for each of the sphere + scale to the radius value defined in the list model for each of the sphere instances. \image repeater3d-radius-binding.png \li Select \uicontrol OK. @@ -170,6 +201,6 @@ result. You need to zoom out to see all the spheres. \endlist - \image repeater3d-list-model.webp + \image repeater3d-list-model.webp "Spheres in Repeater3D with a ListModel" */ diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor-json.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-json.qdoc deleted file mode 100644 index 8b7451b3aa3..00000000000 --- a/doc/qtdesignstudio/src/views/qtquick-connection-editor-json.qdoc +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only - -/*! - \page quick-json-data-properties.html - \previouspage quick-dynamic-properties.html - \nextpage quick-states.html - - \title Connecting Properties to JSON Data Source - - Connect properties to data from a JSON file. You need two files in your project to do this: - - \table - \row - \li \c {data.json} - \li A data file. - \row - \li \c {JsonData.qml} - \li A singleton that reads data from \c {data.json}. - \endtable - - To create these files, you need to create a new data model: - - \list 1 - \li In \uicontrol {Model Editor}, select \inlineimage {icons/zoomIn.png}. - \li Select \uicontrol{Create}. - \endlist - - The files are created in the \e {/imports//} folder of the project. - - \section1 Connecting a Text Property to a Data Source - - To connect a text property to a corresponding field in a JSON file: - - \list 1 - \li In the \uicontrol Navigator or \uicontrol 2D view, select a component - that has a text property, for example, a text field. - \li In the \uicontrol Connections view, go to the \uicontrol Bindings - tab. - \li Select \inlineimage {icons/plus.png}. - \li In the first \uicontrol From field, select \uicontrol {DataStore}, and in the second field, - select the JSON entry you want to use. In this example, \uicontrol {backend.name} is - selected. This corresponds to the \e name entry in \c {data.json}. - \li In the \uicontrol To field, ensure that \uicontrol text is selected. - \image json-text-binding.webp - \endlist - - Now, the text field is populated with data from the JSON file. - - \section1 Adding Data Fields to the JSON File - - If you add data fields to the JSON file, you need to manually do the same - updates to \c {JsonData.qml}. - - \list 1 - \li Go to the \uicontrol Projects view and open \c {JsonData.qml}. - \image project-jasondata.webp - \li In the \uicontrol Properties view, create a new local custom property. - \image json-new-property.webp - \li Ensure that the name of the property matches the data entry in the JSON file. - \endlist - -*/ diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc index 586098ffca8..bd976fbfd54 100644 --- a/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc @@ -32,11 +32,6 @@ can specify values for. You can add custom properties that would not otherwise exist for a particular \l{Component Types} {component type} or your custom components. - - \li \l{Connecting Properties to JSON Data Source} - - You can add bindings between properties and data from a JSON file. - \endlist For an example of using properties, bindings, and connections to create a diff --git a/doc/qtdesignstudio/src/views/studio-model-editor.qdoc b/doc/qtdesignstudio/src/views/studio-model-editor.qdoc deleted file mode 100644 index 0caebcfb493..00000000000 --- a/doc/qtdesignstudio/src/views/studio-model-editor.qdoc +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only - -/*! - \page studio-model-editor.html - \previouspage qtquick-effect-composer-view.html - \nextpage creator-project-managing-workspaces.html - - \ingroup studio-views - - \title Model Editor - - \brief Create, manage, import, and export data models. - - In the \uicontrol {Model Editor} view, you can create, manage, import, and export - data models. With data models, you can, for example, populate views with data. - - \image edit-list-model-model-editor.webp - - For examples of how to use data models, see - \l {Adding a Repeater3D Component with a Model}. - - \section1 Creating a Data Model - - To create a data model: - \list 1 - \li In \uicontrol {Model Editor}, select \inlineimage {icons/zoomIn.png}. - \li Enter a name and select \uicontrol {Create}. - \endlist - - This creates a single-cell table. - - \image model-editor-new-model.webp - - Next, add columns, rows, and data to the model. - - \note You must manually save the table after you have made changes. To do this, - select \inlineimage {icons/save-effect-composer.png}. - - \section1 Editing a Data Model - - Edit a data model in one of the following ways: - \list - \li Right-click a column name to edit its name and type, delete, or sort it. - \li Double-click a cell to edit its content. - \li Use the toolbar to add and remove columns and rows. - \endlist - - \note You must manually save the table after you have made changes. To do this, - select \inlineimage {icons/save-effect-composer.png}. - - \section1 Importing a Data Model - - Import data models from JSON or CSV files. To do this, select \inlineimage {icons/import.png} - in \uicontrol {Model Editor}. - - \section1 Exporting a Data Model - - Export data models to JSON or CSV files. To do this, select \inlineimage {icons/export.png} - in \uicontrol {Model Editor}. - -*/ From c120ed0ac6363e57ca0d17f67695f896a6d2ba6a Mon Sep 17 00:00:00 2001 From: Shrief Gabr Date: Wed, 9 Oct 2024 20:43:31 +0300 Subject: [PATCH 27/44] QmlDesigner: Fix missing Assets on folder drag & drop Fixes: QDS-13784 Change-Id: I86c3f0c9b476a3945219e6be155831c795bdd9da Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../assetsLibraryQmlSources/Assets.qml | 6 +-- .../AssetsContextMenu.qml | 2 +- .../assetsLibraryQmlSources/AssetsView.qml | 8 ++-- .../assetslibrary/assetslibrarymodel.cpp | 39 +++++-------------- .../assetslibrary/assetslibrarymodel.h | 14 +++---- .../assetslibrary/assetslibrarywidget.cpp | 2 +- 6 files changed, 24 insertions(+), 47 deletions(-) diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/Assets.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/Assets.qml index 0514f3dfaef..60beacfe6e2 100644 --- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/Assets.qml +++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/Assets.qml @@ -101,7 +101,7 @@ Item { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { - if (assetsModel.hasFiles) { + if (!assetsModel.isEmpty) { function onFolderCreated(path) { assetsView.addCreatedFolder(path) } @@ -189,13 +189,13 @@ Item { leftPadding: 10 color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.baseFont - visible: !assetsModel.hasFiles && !root.__searchBoxEmpty + visible: assetsModel.isEmpty && !root.__searchBoxEmpty } Item { // placeholder when the assets library is empty width: parent.width height: parent.height - toolbar.height - column.spacing - visible: !assetsModel.hasFiles && root.__searchBoxEmpty + visible: assetsModel.isEmpty && root.__searchBoxEmpty clip: true MouseArea { // right clicking the empty area of the view diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsContextMenu.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsContextMenu.qml index 40cdac85bbb..08f6c0a990f 100644 --- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsContextMenu.qml +++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsContextMenu.qml @@ -192,7 +192,7 @@ StudioControls.Menu { StudioControls.MenuItem { text: qsTr("New Folder") - visible: root.assetsModel.hasFiles + visible: !root.assetsModel.isEmpty height: visible ? implicitHeight : 0 NewFolderDialog { diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml index 307d3637521..df45bc32487 100644 --- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml +++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml @@ -70,9 +70,9 @@ TreeView { model: assetsModel onRowsChanged: { - if (root.rows > root.rootPathRow + 1 && !assetsModel.hasFiles || - root.rows <= root.rootPathRow + 1 && assetsModel.hasFiles) { - assetsModel.syncHasFiles() + if (root.rows > root.rootPathRow + 1 && assetsModel.isEmpty || + root.rows <= root.rootPathRow + 1 && !assetsModel.isEmpty) { + assetsModel.syncIsEmpty() } root.updateRows() @@ -328,7 +328,7 @@ TreeView { function moveSelection(amount) { - if (!assetsModel.hasFiles || !amount) + if (assetsModel.isEmpty || !amount) return let index = root.currentFilePath ? assetsModel.indexForPath(root.currentFilePath) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp index d12d824ddc8..febf11a9176 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp @@ -41,7 +41,7 @@ void AssetsLibraryModel::createBackendModel() QObject::connect(m_sourceFsModel, &QFileSystemModel::directoryLoaded, this, [this]([[maybe_unused]] const QString &dir) { - syncHasFiles(); + syncIsEmpty(); }); m_fileWatcher = new Utils::FileSystemWatcher(parent()); @@ -224,41 +224,20 @@ bool AssetsLibraryModel::filterAcceptsRow(int sourceRow, const QModelIndex &sour } } -bool AssetsLibraryModel::checkHasFiles(const QModelIndex &parentIdx) const +void AssetsLibraryModel::setIsEmpty(bool value) { - if (!parentIdx.isValid()) - return false; - - const int rowCount = this->rowCount(parentIdx); - for (int i = 0; i < rowCount; ++i) { - auto newIdx = this->index(i, 0, parentIdx); - if (!isDirectory(newIdx)) - return true; - - if (checkHasFiles(newIdx)) - return true; - } - - return false; -} - -void AssetsLibraryModel::setHasFiles(bool value) -{ - if (m_hasFiles != value) { - m_hasFiles = value; - emit hasFilesChanged(); + if (m_isEmpty != value) { + m_isEmpty = value; + emit isEmptyChanged(); } } -bool AssetsLibraryModel::checkHasFiles() const +void AssetsLibraryModel::syncIsEmpty() { - auto rootIdx = indexForPath(m_rootPath); - return checkHasFiles(rootIdx); -} + QModelIndex rootIdx = indexForPath(m_rootPath); -void AssetsLibraryModel::syncHasFiles() -{ - setHasFiles(checkHasFiles()); + bool hasContent = rowCount(rootIdx); + setIsEmpty(!hasContent); } void AssetsLibraryModel::setRootPath(const QString &newPath) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h index 27b5eb77f27..5b5525a01bf 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h @@ -23,7 +23,7 @@ public: void setRootPath(const QString &newPath); void setSearchText(const QString &searchText); - Q_PROPERTY(bool hasFiles READ hasFiles NOTIFY hasFilesChanged) + Q_PROPERTY(bool isEmpty READ isEmpty NOTIFY isEmptyChanged) Q_INVOKABLE QString rootPath() const; Q_INVOKABLE QString filePath(const QModelIndex &index) const; @@ -36,7 +36,7 @@ public: Q_INVOKABLE QModelIndex parentDirIndex(const QString &path) const; Q_INVOKABLE QModelIndex parentDirIndex(const QModelIndex &index) const; Q_INVOKABLE QString parentDirPath(const QString &path) const; - Q_INVOKABLE void syncHasFiles(); + Q_INVOKABLE void syncIsEmpty(); Q_INVOKABLE QList parentIndices(const QModelIndex &index) const; Q_INVOKABLE bool indexIsValid(const QModelIndex &index) const; @@ -58,29 +58,27 @@ public: return std::min(result, 1); } - bool hasFiles() const { return m_hasFiles; } + bool isEmpty() const { return m_isEmpty; } signals: void directoryLoaded(const QString &path); void rootPathChanged(); - void hasFilesChanged(); + void isEmptyChanged(); void fileChanged(const QString &path); void effectsDeleted(const QStringList &effectNames); private: - void setHasFiles(bool value); + void setIsEmpty(bool value); bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; void resetModel(); void createBackendModel(); void destroyBackendModel(); - bool checkHasFiles(const QModelIndex &parentIdx) const; - bool checkHasFiles() const; QString m_searchText; QString m_rootPath; QFileSystemModel *m_sourceFsModel = nullptr; - bool m_hasFiles = false; + bool m_isEmpty = true; Utils::FileSystemWatcher *m_fileWatcher = nullptr; }; diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index e7d1e431633..1ccda93b130 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -436,7 +436,7 @@ QList AssetsLibraryWidget::createToolBarWidgets() void AssetsLibraryWidget::handleSearchFilterChanged(const QString &filterText) { - if (filterText == m_filterText || (!m_assetsModel->hasFiles() + if (filterText == m_filterText || (m_assetsModel->isEmpty() && filterText.contains(m_filterText, Qt::CaseInsensitive))) return; From 6ccb8d919e7459673fdbf893a3b7cad40f644fd4 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 14 Oct 2024 13:24:56 +0300 Subject: [PATCH 28/44] Fix unidentified type in 6.8 build IconImage requires "import QtQuick.Controls.impl" in Qt 6.8 builds. Change-Id: I5a643567c3f8d8967dee8534dc3633b283bb5812 Reviewed-by: Mahmoud Badri --- .../qmldesigner/effectComposerQmlSources/EffectNode.qml | 1 + 1 file changed, 1 insertion(+) diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectNode.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectNode.qml index dd361b08d73..130208253c6 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectNode.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectNode.qml @@ -3,6 +3,7 @@ import QtQuick import QtQuick.Controls +import QtQuick.Controls.impl import HelperWidgets import StudioControls as StudioControls import StudioTheme as StudioTheme From cf27c5d71b6ce60131caa71b332bc61131ff5fc4 Mon Sep 17 00:00:00 2001 From: Johanna Vanhatapio Date: Wed, 9 Oct 2024 12:35:50 +0300 Subject: [PATCH 29/44] Doc: Remove app flow docs Task-number: QDS-13232 Change-Id: I452b418fc4b59fab28f6d2284776ad8274d5ad96 Reviewed-by: Thomas Hartmann --- .../config/style/qt5-sidebar.html | 7 - .../images/studio-feedback-popup-material.png | Bin 0 -> 10991 bytes .../images/studio-feedback-popup.png | Bin 5977 -> 0 bytes .../src/components/qtquick-components.qdoc | 4 +- .../overviews/qtquick-animation-overview.qdoc | 39 +- .../src/overviews/qtquick-motion-design.qdoc | 6 +- .../src/overviews/qtquick-uis.qdoc | 13 +- .../src/overviews/studio-user-feedback.qdoc | 2 +- .../src/qtdesignstudio-app-flows.qdoc | 707 ------------------ .../src/qtdesignstudio-projects.qdoc | 6 +- .../src/qtdesignstudio-toc.qdoc | 11 - 11 files changed, 16 insertions(+), 779 deletions(-) create mode 100644 doc/qtdesignstudio/images/studio-feedback-popup-material.png delete mode 100644 doc/qtdesignstudio/images/studio-feedback-popup.png delete mode 100644 doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc diff --git a/doc/qtdesignstudio/config/style/qt5-sidebar.html b/doc/qtdesignstudio/config/style/qt5-sidebar.html index 798cbe5a41e..6fa341ba470 100644 --- a/doc/qtdesignstudio/config/style/qt5-sidebar.html +++ b/doc/qtdesignstudio/config/style/qt5-sidebar.html @@ -81,13 +81,6 @@
-
  • Code
      diff --git a/doc/qtdesignstudio/images/studio-feedback-popup-material.png b/doc/qtdesignstudio/images/studio-feedback-popup-material.png new file mode 100644 index 0000000000000000000000000000000000000000..2d935349bf12750499e35bda8dc933633901c83b GIT binary patch literal 10991 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 Hr-UW|R>s>= literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/images/studio-feedback-popup.png b/doc/qtdesignstudio/images/studio-feedback-popup.png deleted file mode 100644 index 5a6d38bc050649a1b4a1bd2db28a0be24b99a4ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5977 zcmeAS@N?(olHy`uVBq!ia0y~yUljy?ghrUAy-D`Sa|p*EFl=C?>aLZ#}p6-utMisJ(mlZr!@Iy1IJl zwfFDezn?N?%J=Wz4Gj&~u3g)5?)jWKbCQ#j_dfrA?fv(lprAR|-WL}aS08(xot+)E z_g+s=&%O6QijO_tdhh$vrAu2{T4wJ(=jG+)U+ z+sscZe{=QzN4|F-zG~)u`=D9VRcP1hzwzC#E9w_C#a@am4bHi&>9zdEvfwFx8-15+ z%uSl@7ie|VZ0@3xu3RhEmm;@Ix-MyMdnsaH_G$(L0|P_igusLe(A2{#P z?ByE%AI}C)S^ndh=BePC&mvDX_f>X%5=q`36Q;_(P-B;1O;3-|Y85Ae!U+MA-~a!Q zdTppbYtixVUS^?BLS8*ld5|=7{@mli{td^2{p-r){B0TK{B3{Ue0d|d`P#yoX+bVi zJh&D3x0Za4wsvr1z2G?2OZ9AEk}AWrZT41DGLg3oIJM6kzpo5s*sKxg_dsU7Q0eV3 z6@UN96L0hEy%L=lEzx)Ffk?uoZLXbsmo_fgGfyWru^eN0z z*rIWN$D$>ZQti5%5}5lePDe_*{SOM7vN+;-)l8-b_qk)e12}TC%=3><@DlH7eRAh~ z+q{g=k2BJ?Z#UZQ$s<%C-+F(3pKYp6)Sj;&&s}kOv1d{H6{Z9!mbMFP{<%D0aIEM* zox!=s(_qgD@5<*I>q}Q~Xec_pca3|QxlXwAn78h^zS^26KmNYF8T?HrWC8=fb#Ujx zw2isCix0ljoVfg%=DLsmbC{ogxU%a)<4ZH4iA%j^{XI2hj_99rQ

      LYtDMLW1i`k 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 \uicontrol {Flow - View} to set up alternative pathways between flow items, as described in - \l{Simulating Conditions}. - \li Use \l{Working with States}{states} in flows to modify the appearance - of components on screens in response to user interaction, as - described in \l{Applying States in Flows}. - \li Use \uicontrol {Flow Wildcard} components from - \uicontrol Components > \uicontrol {Flow View} to prioritize events - from other applications and to stop some screens from appearing on - others, as described in \l{Reacting to External Events}. - \endlist -*/ - -/*! - \page studio-flow-view.html - \previouspage studio-app-flows.html - \nextpage studio-flow-item.html - - \title Adding Flow Views - - A flow view is the base component of the flow diagram that you can use to wireframe - the UI of your application. For more information, see \l{Designing Application Flows}. - - Add a flow view to an existing project or create a new project for it, as described in - \l {Creating Projects}. - - To create the flow view, select \uicontrol File > - \uicontrol {New File} > - \uicontrol {Qt Quick Files} > \uicontrol {Flow View} - and follow the instructions of the wizard. - - \image studio-flow-view-create.png "Create Flow View wizard template" - - If you want to add an event simulator to the flow view, select the - \uicontrol {Use Event Simulator} checkbox. In this case, select also the - \uicontrol {Use Application Import} checkbox to import the project to the flow view - as the event simulator requires it to work correctly. You need the - import also for access to the project \c Constants.qml file that contains - global settings for the project. For more information, see \l {Simulating Events}. - - You can adjust the appearance of all the items in the flow: action areas, - transition lines, decisions, and wildcards. Change the global settings for all items - by editing the flow view properties. To add additional semantics to the flow diagram - design, select an individual action area or transition line and change the appearance - of just that component. - - \section1 Flow View Properties - - You can specify basic properties for a \uicontrol {Flow View} component - in the \l {Type}{Component}, \l {2D Geometry}{Geometry - 2D}, and - \l Visibility sections in the \l Properties view. Specify flow view - properties in the \uicontrol {Flow View} section. - - \image studio-flow-view-properties.webp "Flow View component properties" - - To specify the \uicontrol {Flow Item} that is currently visible in the - flow view, set its index in the \uicontrol {Current index} field. - - Use the \l{Picking Colors}{color picker} to set colors for: - - \list - \li Transition lines - \li Area outlines - \li Area fills - \li Block items - \endlist - - You can set some additional global properties for drawing transition lines: - - \image studio-flow-view-properties-transition.png "Flow View transition properties" - - \list - \li In the \uicontrol {Type} field, select \uicontrol Bezier to draw - transition lines as bezier curves. - \li In the \uicontrol {Radius} field, specify the corner radius for - default curves. - \li In the \uicontrol {Bezier factor} field, specify the factor that - modifies the positions of the control points used for bezier curves. - \endlist - - For more information about changing the appearance of a particular action - area or transition line, see \l{Flow Action Area Properties} and - \l{Flow Transition Properties}. - - In the \uicontrol Advanced section, you can manage the more - \l{Specifying Developer Properties}{advanced properties} - of components. -*/ - -/*! - \page studio-flow-item.html - \previouspage studio-flow-view.html - \nextpage studio-flow-action-area.html - - \title Adding Flow Items - - After you create a \l{Adding Flow Views}{Flow View} component, use a project wizard - template to add a \uicontrol {Flow Item} component for each screen in the UI. - - If you \l{Importing 2D Assets}{imported} your screen designs from a - design tool as individual \l{glossary-component}{components} - (\e {.ui.qml} files), you can use them as content for flow items like any other components. - The imported components are listed in \uicontrol Components - > \uicontrol {My Components}. - - If you are building your UI from scratch in \QDS, add components to the flow items - first to create the screens as you would any components. For more information, see - \l {Using Components}. The flow items that you attach the components to are listed under - \uicontrol {My Components}. - - \image studio-flow-item.webp "Custom Flow Item in Components" - - \note You must use the wizard to create the flow items. After you create - a flow view, the \uicontrol {Flow View} module is added to - \uicontrol Components. It contains the \uicontrol {Flow Item} component for - \l{Applying States in Flows}{applying states to flow items}, and solely for that purpose. - - To add flow items: - - \list 1 - \li Select \uicontrol File > \uicontrol {New File} > - \uicontrol {Qt Quick Files} > - \uicontrol {Flow Item} and follow the instructions of the wizard - to create flow items for each screen in the UI. - \li Add content to the flow item in one of the following ways: - \list - \li Drag components from \uicontrol Components to a - flow item in the \l {2D} view or \l Navigator. - \li Drag a screen from \uicontrol Components - > \uicontrol {My Components} to a flow item in - the \uicontrol {2D} view or \uicontrol Navigator. - \endlist - \li In \l Properties, edit the properties of each flow item. - \endlist - - Now, drag the flow items from \uicontrol Components > \uicontrol {My Components} to the - flow view in the \uicontrol {2D} or \uicontrol Navigator view. When you have all the flow - items in place, \l{Adding Action Areas and Transitions}{add action areas} to them to create - transitions between them. - - \section1 Flow Item Properties - - You can specify basic properties for a \uicontrol {Flow Item} component - in the \l {Type}{Component}, \l {2D Geometry}{Geometry - 2D}, and - \l Visibility sections in the \uicontrol Properties view. Specify flow item - properties in the \uicontrol {Flow Item} section. - - \image studio-flow-item-properties.png "Flow Item properties" - - The \uicontrol {State change target} and \uicontrol {Target state} - properties are used to \l{Applying States in Flows}{apply states} - in flows. - - To include another flow view as a flow item into a flow view, select the UI file (.ui.qml) - that specifies the flow view in the \uicontrol {Loader source} field. - - Usually, a flow item is inactive and invisible when it is not currently - selected in the flow. Especially, all events from the flow item are ignored. - To make a flow item always active, so that another flow item within it - can respond to events and trigger the opening of a dialog, for example, - select the \uicontrol {Force active} checkbox. - - In the flow view, transitions are drawn from action areas to the target flow item by default. - To draw the transitions from the edges of flow items instead, select the - \uicontrol {Join lines} checkbox in the \uicontrol {Transition Lines} - section. - - In the \uicontrol Advanced section, you can manage the more - \l{Specifying Developer Properties}{advanced properties} of components. -*/ - -/*! - \page studio-flow-action-area.html - \previouspage studio-flow-item.html - \nextpage studio-flow-effects.html - - \title Adding Action Areas and Transitions - - \e {Action areas} are clickable areas that initiate transitions between flow items or - \l{Connecting and Releasing Signals}{create connections} to any signal from any component in a - \l{Adding Flow Items}{flow item}. For example, you could connect an - action to the \c onPressed signal of a button in your flow item to - determine what should happen when users press the button. - - \image studio-flow-action-area.webp "Flow Action Area in the 2D view" - - Select the type of the mouse or touch input to use for triggering - events, such as click, double-click, flick, pinch, or long press. - - Typically, a flow item is connected to several other flow items in the - flow with two-way connections. To avoid clutter, set an action area - as \e {go back} instead of adding explicit transition lines to and from - every potentially connected flow item. When the \uicontrol {Go back} option - is enabled, the transition will always take the user back to the previous - flow item. - - You can specify the appearance of each action area or transition line, - including the color, line thickness, dotted or solid lines, and even - the curve of the transition lines. You can change some of these properties - globally, as instructed in \l{Flow View Properties}. - - To create action areas: - - \list 1 - \li Select the flow item in the \l {2D} view, then right-click it, and select - \uicontrol {Flow} > \uicontrol {Create Flow Action} in - the context menu. - \li Drag the action area to the UI control that you want to connect - to the other flow item. For example, to a button that opens another - flow item when clicked. - \li Double-click the action area and drag the transition line to the flow item you want to - connect to. Alternatively, select the action area, right-click it to open the - context-menu, and then select \uicontrol Connect and the flow item from the list. - \li In \l Properties, modify the properties of the action area - and transition line. - \endlist - - To preview the flow, select the - \uicontrol {Live Preview} button on the top toolbar or press \key Alt + - \key P. - - \section1 Common Properties - - Specify basic properties for \uicontrol {Flow Action Area} - and \uicontrol {Flow Transition} components in the \l {Type}{Component}, - \l {2D Geometry}{Geometry - 2D}, and \l Visibility sections in the - \uicontrol Properties view. - - Use \l{Setting Anchors and Margins}{anchors} in the \uicontrol Layout tab to position - the component. - - Manage the more \l{Specifying Developer Properties}{advanced properties} of components - in the \uicontrol Advanced section. - - \section1 Flow Action Area Properties - - Use the \l{Picking Colors}{color picker} in the \uicontrol {Flow Action Area} section - to set line and fill color. - - \image studio-flow-action-area-properties.webp "Flow Action Area properties" - - Specify additional properties for action areas in the \uicontrol {Flow Action} and - \uicontrol {Action Area} sections: - - \list - \li Select the \uicontrol {Go back} checkbox to specify that the - transition will always take the user back to the previous flow item. - \li In the \uicontrol {Event IDs} field, specify the IDs of the - events to connect to, such as mouse, touch or keyboard events. - \li In the \uicontrol {Action type} field, select the type of the - mouse or touch input to use for triggering events. - \li In the \uicontrol {Line width} field, set the width of the - action area outline. - \li Select the \uicontrol {Dashed line} checkbox to draw a dashed - action area outline. - \li Select the \uicontrol Enabled checkbox to enable interaction - with the action area during preview. - \endlist - - \section1 Flow Transition Properties - - Specify additional properties for transitions between \l{Adding Flow Items}{flow items} - in the \uicontrol Transition section: - - \image studio-flow-transition-properties.webp "Flow Transition properties" - - \list - \li Select the \uicontrol Condition checkbox to activate the - transition. Select \inlineimage icons/action-icon.png - to \l{Adding Bindings Between Properties}{bind} a condition - to the transition. - \li In the \uicontrol Question field, enter the text that will appear - next to the transition line. If the transition represents the - connection to a \uicontrol {Flow Decision} component, the - text will also be visible in the selection dialog that opens when - the \l{Simulating Conditions}{condition} is triggered. - \li In the \uicontrol {Event IDs} field, specify the IDs of the - events to connect to, such as mouse, touch or keyboard events. - \li In the \uicontrol From and \uicontrol To fields, select the - flow item where the transition starts and the one where it - ends. - \endlist - - Specify the following properties to change the appearance of transition lines in - the \uicontrol {2D} view: - - \image studio-flow-transition-line-properties.webp "Flow Transition Line properties" - - \list - \li In the \uicontrol {Line width} field, set the width of the - transition line. - \li In the \uicontrol {Offset} and \uicontrol {Break offset} fields, set - the start point (\uicontrol Out) or end point (\uicontrol In) of a - transition line or a break to the specified offset. This enables - you to move them up and down or left and right. - \li Select the \uicontrol {Dashed line} checkbox to draw a dashed line. - \li In the \uicontrol Type field, select \uicontrol Bezier to draw - transition lines as bezier curves. - \li In the \uicontrol Radius field, specify the corner radius for - default curves. - \li In the \uicontrol {Bezier factor} field, specify the factor that - modifies the positions of the control points used for a bezier - curve. - \li In the \uicontrol {Label position} field, set the position of - the value of the \uicontrol Question field in respect to the - transition start point. - \li Select the \uicontrol {Label flip side} checkbox to move the - \uicontrol Question value to the opposite side of the transition - line. - \endlist - - \section1 Connecting and Releasing Signals - - To connect components to \l{Connecting Components to Signals}{signals}, export the - components first as \l{Adding Property Aliases}{aliases} in \l Navigator. To create - and release connections, select \uicontrol {Open Signal Dialog} in the context menu. - The \uicontrol {Signal List} dialog displays the signals for all components. - - \image studio-flow-signal-list.webp "Signal List dialog" - - To connect a component to a signal, select \uicontrol Connect next to one - in the list. To release a connected signal, select \uicontrol Release. -*/ - -/*! - \page studio-flow-effects.html - \previouspage studio-flow-action-area.html - \nextpage studio-flow-events.html - - \title Applying Effects to Transitions - - You can apply effects, such as fade, move, or push, to - \l{Adding Action Areas and Transitions}{transitions} between - \l{Adding Flow Items}{flow items}. A fade effect makes the first - flow item appear to fade out, while the next flow item fades in. - A move effect makes the second flow item appear to move in over the - first flow item. The push effect makes a flow item appear to push out the previous one. - You can also use your own custom effects that you have created with some other tool. - - The transition direction determines the direction the new flow item appears - from: left, right, top, bottom. You can set the duration of the effect and - \l{Editing Easing Curves}{attach an easing curve} to the effect. - - To add effects: - - \list 1 - \li Select a transition line in the \l {2D} view. - \li Right-click the transition line to open the context menu, select \uicontrol {Flow} > - \uicontrol {Flow Effects}, and then select the effect to apply. - \li In \l Properties, modify the properties of the effect. - \endlist - - To edit effect properties later, select a transition, open the context menu, and then select - \uicontrol {Flow} > \uicontrol {Select Effect}. - - To use your own custom effects, select a transition, open the context menu, and then select - \uicontrol {Flow} > \uicontrol {Flow Effects} > \uicontrol {Assign Custom FlowEffect}. - Then specify the path to your custom effect file. - - To remove the current effect from a transition, select a transition, open the context menu, - and then select \uicontrol {Flow} > \uicontrol {Flow Effects} > - \uicontrol {Assign FlowEffect None}. - - \section1 Flow Effect Properties - - Specify basic properties for a \uicontrol {Flow Effect} component in the \l Type and - \l ID fields in the \uicontrol Component section in the \uicontrol Properties view. - - \image studio-flow-effect-properties.png "Flow Effect properties" - - Set the duration and easing curve of flow effects in the \uicontrol {Transition Effect} - section: - - \list - \li In the \uicontrol Duration field, specify the duration of the - effect. - \li Select the \inlineimage icons/curve_editor.png - button to open \uicontrol {Easing Curve Editor} to attach an - \l{Editing Easing Curves}{easing curve} to the effect. - \endlist - - Set some additional properties for a move or push effect in the \uicontrol {Push Effect} - or \uicontrol {Move Effect} section: - - \image studio-flow-effect-push-properties.png "Flow Push Effect properties" - - \list - \li In the \uicontrol Direction field, specify the direction that - the target \uicontrol {Flow Item} appears from: left, right, top, - or bottom. - \li In the \uicontrol Scale field, set scaling for the effect. - \li In the \uicontrol {Incoming opacity} and - \uicontrol {Outgoing opacity} fields, specify the opacity of - the effect as a number between 0 and 1. - \li Select the \uicontrol Reveal checkbox to reveal the - \uicontrol {Flow Item} where the transition starts. - \endlist -*/ - -/*! - \page studio-flow-events.html - \previouspage studio-flow-effects.html - \nextpage studio-flow-conditions.html - - \title Simulating Events - - While \l{Adding Action Areas and Transitions}{transition lines} - are useful for prototyping, in production you need to use the real - \l{Connecting and Releasing Signals}{signals} from UI - \l{glossary-component}{components} to control the flow of the application. - For this purpose, you can use action areas in a more advanced way, by - having them listen to signals from flow items or the controls in them and - by connecting these to the \l{Adding Flow Views}{flow view}. You can use - keyboard shortcuts to simulate these events when you preview the UI. - - When you use the wizard to create a \uicontrol {Flow View} component, select - the \uicontrol {Use event simulator} checkbox to add an event simulator to - the flow view. - - You can create an event list where you assign keyboard shortcuts to events, - and then use context-menu commands to attach the events to action areas or - transition lines. - - \section1 Creating Event Lists - - To create an event list: - - \list 1 - \li Right-click in the \uicontrol 2D or \uicontrol Navigator view and select - \uicontrol {Event List} > \uicontrol {Show Event List}. - \li In the \uicontrol {Event List} dialog, select \inlineimage icons/plus.png - to add a keyboard shortcut for triggering an event to the list. - \image studio-flow-event-list.png "Event List dialog" - \li In the \uicontrol {Event ID} field, enter an identifier for the event. To search - for existing events, enter search criteria in the \uicontrol Filter field. - \li In the \uicontrol Description field, describe the keyboard shortcut. - \li In the \uicontrol Shortcut field, press the keyboard key that will - trigger the event, and then select \uicontrol R to record the - keyboard shortcut. The key identifier appears in the field. - \endlist - - You can now assign the events to action areas and transitions. - - \section1 Assigning Events to Actions - - To assign events to actions: - - \list 1 - \li Select \uicontrol eventListSimulator in \uicontrol Navigator, and in - \uicontrol Properties > \uicontrol {Exposed Custom Properties}, select the - \uicontrol active checkbox. If \uicontrol eventListSimulator is not visible - in the \uicontrol Navigator, select \inlineimage icons/visibilityon.png. - \li In \uicontrol Navigator, select an action area or transition line. - \li In the context menu, select \uicontrol {Event List} > - \uicontrol {Assign Events to Actions}. - \image studio-flow-events-assign.webp "Assign Events to Actions dialog" - \li To connect an event, select \uicontrol Connect next to an event in - the list. To release a connected event, select \uicontrol Release. - \li Press \key {Alt+P} to preview the UI. - \li Select action areas in the preview, double-click events in the - event list, or use the keyboard shortcuts to trigger events. - \image studio-flow-events-event-list.webp "Event list in Live Preview" - \endlist - -*/ - -/*! - \page studio-flow-conditions.html - \previouspage studio-flow-events.html - \nextpage studio-flow-states.html - - \title Simulating Conditions - - Part of any complex UI is the conditional logic it uses to present its - state to users or to collect and process data from various sources. Data - can be produced by user interaction from a variety of inputs, such as - buttons and controls, sensor readings from arrays of equipment, or general - values received from backend or service APIs. - - The \uicontrol {Flow Decision} component simulates conditions by displaying a - list of options you can choose from when you preview the flow. This enables - you to prototype complex interactions before you have access to the physical - controls, backend, or sensor data that will be required for the production - version. - - \image studio-flow-decision.webp "Flow Decision in the 2D view" - - To simulate conditions: - - \list 1 - \li Drag a \uicontrol {Flow Decision} component from - \uicontrol Components > \uicontrol {Flow View} to a - \l{Adding Flow Views}{flow view} in the \l Navigator or \l {2D} view. - \li Select the flow item where you want the application to start in - the \uicontrol Navigator or \uicontrol {2D} view. Then right-click the component - to open the context menu, and select \uicontrol Flow > \uicontrol {Set Flow Start}. - \li Create an \l{Adding Action Areas and Transitions}{action area} for - the component that will trigger the condition and connect it to the - flow decision. - \li Select the flow decision, and then select \uicontrol Connect in the - context menu to create connections to the flow items that will open - depending on whether the condition is met. - \li In the \l Properties view, \uicontrol {Dialog title} field, enter a - title for the selection dialog that opens when the condition is - triggered. - \li Select a transition line in the \uicontrol Navigator or - \uicontrol {2D} view, and add a descriptive text in the - \uicontrol {Question} field in \uicontrol Properties to represent - a choice in the selection dialog. - \image studio-flow-transition-properties-question.webp "Flow Transition properties" - \li Press \key {Alt+P} to preview the UI. - \li Select action areas in the preview, double-click events in the - event list, or use the keyboard shortcuts to trigger events. - \endlist - - Flow decisions are listed in a dialog where you can select which condition - is met to see the results. - - \image studio-flow-decision-preview.webp "Selection dialog for flow decision" - - \section1 Flow Decision Properties - - Specify basic properties for a \uicontrol {Flow Decision} component - in the \l Type and \l ID fields in the \uicontrol Component section in the - \uicontrol Properties view. Specify properties for flow decisions in the - \uicontrol {Flow Decision} section. - - \image studio-flow-decision-properties.webp "Flow Decision properties" - - In the \uicontrol {Dialog title} field, enter a title for the selection - dialog that opens when the condition is triggered. - - Specify the following properties to change the appearance of the - flow decision icon \inlineimage icons/flow-decision-icon.png - : - - \list - \li Select \inlineimage icons/visibility-off.png - to display the ID of the \uicontrol {Flow Decision} - component in the \l {2D} view. - \li In the \uicontrol {Label position} field, select the corner of - the flow decision icon to place the label in. - \li Use the \l{Picking Colors}{color picker} to set \uicontrol {Outline color} and - \uicontrol {Fill color} of the flow decision icon. - \li In the \uicontrol Size field, specify the size of the flow - decision icon. - \li In the \uicontrol Radius field, specify the radius of the flow - decision icon corners. - \endlist - -*/ - -/*! - \page studio-flow-states.html - \previouspage studio-flow-conditions.html - \nextpage studio-flow-external-events.html - - \title Applying States in Flows - - Use \l{Working with States}{states} in flows to modify how the \l{glossary-component} - {component} properties change in flow items. For this purpose, use the \uicontrol {Flow Item} - component available in \uicontrol Components > \uicontrol {Flow View}. - - To apply states in flows: - - \list 1 - \li Select \uicontrol File > \uicontrol {New File} > - \uicontrol {Qt Quick Files} > - \uicontrol {Flow Item} to create a flow item. - \li In the \l States view, add states to the flow item. - \li In the \l Projects view, open the .ui.qml file that contains the \l{Adding Flow Views} - {flow view}, and drag the flow item from \uicontrol Components > - \uicontrol {My Components} to the flow view in the \l Navigator or \l 2D view. - \li From \uicontrol Components > \uicontrol {Flow View}, drag an empty - \uicontrol {Flow Item} component (1) to the flow view for each state that you added. - \image studio-flow-item-component.webp "Flow Item in the Components view." - \li In the \uicontrol Navigator or \uicontrol 2D view, select an empty - \uicontrol {Flow Item} to open the \l Properties view. - \li In the \uicontrol {State change target} field, select the flow item that you created - using the wizard. - \li In the \uicontrol {Target state} field, select the state to apply to the flow item. - \image studio-flow-states-item-properties.webp "Flow Item properties" - \endlist - - To apply the different states to your application flow, add - \l{Adding Action Areas and Transitions}{action areas} and - \l{Simulating Conditions}{flow decisions} to the flow items. -*/ - -/*! - \page studio-flow-external-events.html - \previouspage studio-flow-states.html - \nextpage quick-components.html - - \title Reacting to External Events - - On mobile and embedded platforms, applications are usually integrated into - the platform and therefore screens might pop-up from anywhere or at any - time, based on a conditional event. For example, push notifications - appear on mobile devices and incoming call screens on a car's HMI. - - Use the \uicontrol {Flow Wildcard} component to model this type of - screens in your \l{Adding Flow Views}{flow view} using real or simulated events. - Add \l{Adding Flow Items}{flow items} to an \uicontrol {Allow - list} to prioritize them or to a \uicontrol {Block list} to stop some screens from - appearing on others. For example, you could block the incoming call screen - from appearing on a warning screen for the engine if you consider the - warning more important. - - To use wildcards: - - \list 1 - \li Drag a \uicontrol {Flow Wildcard} component from - \uicontrol Components > \uicontrol {Flow View} to the \l {2D} view. - \li To connect the wildcard to a flow item with a \l{Adding Action Areas and Transitions} - {transition line}, double-click the wildcard and drag the transition line to the flow - item. - \li To add logic to the \uicontrol {Flow Wildcard} component, use - \l{Simulating Events}{events}, \l{Simulating Conditions}{Flow Decision} components, - or \l{Connecting and Releasing Signals}{signals}. - \li To manage the priority of your flow items, add flow items to - \uicontrol {Allow list} or \uicontrol {Block list} in \l Properties. - \image studio-flow-wildcard.webp "The wildcard component in 2D view." - \endlist - - \section1 Flow Wildcard Properties - - Specify basic properties for a \uicontrol {Flow Wildcard} component - in the \l Type and \l ID fields in the \uicontrol Component section in the - \uicontrol Properties view. Specify properties for flow wildcards in the - \uicontrol {Flow Wildcard} section. - - \image studio-flow-wildcard-properties.webp "Flow Wildcard properties" - - In the \uicontrol {Event IDs} field, specify the IDs of the events to - connect to, such as mouse, touch or keyboard events. - - Select the \uicontrol {Global wildcard} checkbox to enable triggering - the wildcard from several flows. - - To give flow items high priority, select them in the - \uicontrol {Allow list} field. To block flow items, - select them in the \uicontrol {Block list} field. - - Specify the following properties to change the appearance of the - wildcard icon \inlineimage icons/flow-wildcard-icon.png: - - \list - \li To set the outline and fill color of the wildcard icon, use the - \l{Picking Colors}{color picker}. - \li In the \uicontrol Size field, specify the size of the wildcard icon. - \li In the \uicontrol Radius field, specify the radius of the wildcard - icon corners. - \endlist - -*/ diff --git a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc index 02a82d02031..c65469d8cd0 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc @@ -247,11 +247,7 @@ \li Wizard Template \li Purpose \row - \li {1,5} Qt Quick Files - \li Flow Item and Flow View - \li Generate components that you can use to design the - \l{Designing Application Flows}{application flow}. - \row + \li {1,4} Qt Quick Files \li Qt Quick File \li Generates a component with one of the following default components or \l{Using Positioners}{positioners} as the root component: diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc index b9229af03c8..05615085770 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc @@ -52,17 +52,6 @@ \endlist \li \l{Wireframing} \list - \li \l{Designing Application Flows} - \list - \li \l{Adding Flow Views} - \li \l{Adding Flow Items} - \li \l{Adding Action Areas and Transitions} - \li \l{Applying Effects to Transitions} - \li \l{Simulating Events} - \li \l{Simulating Conditions} - \li \l{Applying States in Flows} - \li \l{Reacting to External Events} - \endlist \li \l {Using Components} \list \li \l{Preset Components} From af46310681cbb264512718e3478d8f81c8cf93f0 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Thu, 10 Oct 2024 12:29:02 +0300 Subject: [PATCH 30/44] QmlDesigner: Enable 'automatic cmake generation' by wizard Task-number: QDS-13344 Change-Id: Ie3e5baf42e31375df8d2d00cb5bf916b2b8bd2ad Reviewed-by: Mahmoud Badri Reviewed-by: Thomas Hartmann --- .../imports/NewProjectDialog/Details.qml | 15 ++ .../projects/application-3d/wizard.json | 10 + .../application-extended-3d/wizard.json | 10 + .../projects/application/wizard.json | 10 + .../projects/common/app.qmlproject.tpl | 4 + src/plugins/studiowelcome/CMakeLists.txt | 1 + src/plugins/studiowelcome/createproject.cpp | 3 + src/plugins/studiowelcome/createproject.h | 6 + src/plugins/studiowelcome/fieldhelper.cpp | 89 +++++++++ src/plugins/studiowelcome/fieldhelper.h | 46 +++++ src/plugins/studiowelcome/presetmodel.cpp | 1 + src/plugins/studiowelcome/presetmodel.h | 1 + src/plugins/studiowelcome/qdsnewdialog.cpp | 55 +++++- src/plugins/studiowelcome/qdsnewdialog.h | 15 ++ src/plugins/studiowelcome/userpresets.cpp | 18 +- src/plugins/studiowelcome/userpresets.h | 7 +- src/plugins/studiowelcome/wizardhandler.cpp | 177 ++++-------------- src/plugins/studiowelcome/wizardhandler.h | 7 +- 18 files changed, 313 insertions(+), 162 deletions(-) create mode 100644 src/plugins/studiowelcome/fieldhelper.cpp create mode 100644 src/plugins/studiowelcome/fieldhelper.h diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml index f905191eff9..ccad08f738a 100644 --- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml @@ -391,6 +391,21 @@ Item { visible: BackendApi.haveVirtualKeyboard } + StudioControls.CheckBox { + id: enableCMakeGeneration + actionIndicatorVisible: false + text: qsTr("Enable Cmake Generation") + font.pixelSize: DialogValues.defaultPixelSize + checked: BackendApi.enableCMakeGeneration + visible: BackendApi.hasCMakeGeneration + } + + Binding { + target: BackendApi + property: "enableCMakeGeneration" + value: enableCMakeGeneration.checked + } + RowLayout { // Target Qt Version width: parent.width visible: BackendApi.haveTargetQtVersion diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json index afb00fa253c..ae3dfe5a4ab 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json @@ -32,6 +32,7 @@ { "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" }, { "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" }, { "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" }, + { "key": "EnableCMakeGenerationDefault", "value": "%{JS: true}" }, { "key": "QtQuick3DVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuick3DVersion}" } ], @@ -208,6 +209,15 @@ "checked": "%{UseVirtualKeyboardDefault}" } }, + { + "name": "EnableCMakeGeneration", + "trDisplayName": "Enable CMake Genertion", + "type": "CheckBox", + "data": + { + "checked": "%{EnableCMakeGenerationDefault}" + } + }, { "name": "CustomScreenWidth", "trDisplayName": "Custom screen width:", diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-extended-3d/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application-extended-3d/wizard.json index ccfcd01a983..a0cccc15915 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application-extended-3d/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-extended-3d/wizard.json @@ -32,6 +32,7 @@ { "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" }, { "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" }, { "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" }, + { "key": "EnableCMakeGenerationDefault", "value": "%{JS: true}" }, { "key": "QtQuick3DVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuick3DVersion}" } ], @@ -208,6 +209,15 @@ "checked": "%{UseVirtualKeyboardDefault}" } }, + { + "name": "EnableCMakeGeneration", + "trDisplayName": "Enable CMake Genertion", + "type": "CheckBox", + "data": + { + "checked": "%{EnableCMakeGenerationDefault}" + } + }, { "name": "CustomScreenWidth", "trDisplayName": "Custom screen width:", diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json index 0aab9b601f3..a7eb00ae0f5 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json @@ -31,6 +31,7 @@ { "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" }, { "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" }, { "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" }, + { "key": "EnableCMakeGenerationDefault", "value": "%{JS: true}" }, { "key": "DefaultStyle", "value": "Basic" } ], @@ -207,6 +208,15 @@ "checked": "%{UseVirtualKeyboardDefault}" } }, + { + "name": "EnableCMakeGeneration", + "trDisplayName": "Enable CMake Genertion", + "type": "CheckBox", + "data": + { + "checked": "%{EnableCMakeGenerationDefault}" + } + }, { "name": "CustomScreenWidth", "trDisplayName": "Custom screen width:", diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl index 7e4e70fb9b9..615cc8d2348 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl @@ -103,6 +103,10 @@ Project { /* Required for deployment */ targetDirectory: "/opt/%{ProjectName}" +@if %{EnableCMakeGeneration} + enableCMakeGeneration: true +@endif + qdsVersion: "4.6" quickVersion: "%{QtQuickVersion}" diff --git a/src/plugins/studiowelcome/CMakeLists.txt b/src/plugins/studiowelcome/CMakeLists.txt index c4db40db5e9..ead7b757893 100644 --- a/src/plugins/studiowelcome/CMakeLists.txt +++ b/src/plugins/studiowelcome/CMakeLists.txt @@ -4,6 +4,7 @@ add_qtc_plugin(StudioWelcome PLUGIN_DEPENDS Core ProjectExplorer QtSupport QmlDesigner DEFINES STUDIO_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/qml/" SOURCES + fieldhelper.cpp fieldhelper.h studiowelcomeplugin.cpp studiowelcomeplugin.h newprojectdialogimageprovider.cpp newprojectdialogimageprovider.h presetmodel.cpp presetmodel.h diff --git a/src/plugins/studiowelcome/createproject.cpp b/src/plugins/studiowelcome/createproject.cpp index 6ed783780cb..5ed59a339e4 100644 --- a/src/plugins/studiowelcome/createproject.cpp +++ b/src/plugins/studiowelcome/createproject.cpp @@ -43,6 +43,9 @@ void CreateProject::processFieldPage(ProjectExplorer::JsonFieldPage *page) if (page->jsonField("UseVirtualKeyboard")) m_wizard.setUseVirtualKeyboard(m_useVirtualKeyboard); + if (page->jsonField("EnableCMakeGeneration")) + m_wizard.enableCMakeGeneration(m_enableCMakeGeneration); + auto widthField = dynamic_cast(page->jsonField("CustomScreenWidth")); auto heightField = dynamic_cast(page->jsonField("CustomScreenHeight")); diff --git a/src/plugins/studiowelcome/createproject.h b/src/plugins/studiowelcome/createproject.h index e1b0af34205..b9abe2d2edb 100644 --- a/src/plugins/studiowelcome/createproject.h +++ b/src/plugins/studiowelcome/createproject.h @@ -28,6 +28,11 @@ public: CreateProject &withStyle(int styleIndex) { m_styleIndex = styleIndex; return *this; } CreateProject &useQtVirtualKeyboard(bool value) { m_useVirtualKeyboard = value; return *this; } + CreateProject &enableCMakeGeneration(bool value) + { + m_enableCMakeGeneration = value; + return *this; + } CreateProject &saveAsDefaultLocation(bool value) { m_saveAsDefaultLocation = value; return *this; } CreateProject &withTargetQtVersion(int targetQtVersionIndex) { m_targetQtVersionIndex = targetQtVersionIndex; return *this; } @@ -48,6 +53,7 @@ private: QString m_customHeight; int m_styleIndex = -1; bool m_useVirtualKeyboard = false; + bool m_enableCMakeGeneration = false; bool m_saveAsDefaultLocation = false; int m_targetQtVersionIndex = -1; }; diff --git a/src/plugins/studiowelcome/fieldhelper.cpp b/src/plugins/studiowelcome/fieldhelper.cpp new file mode 100644 index 00000000000..5fdf3532be3 --- /dev/null +++ b/src/plugins/studiowelcome/fieldhelper.cpp @@ -0,0 +1,89 @@ +// 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 "fieldhelper.h" + +#include +#include + +#include + +using namespace StudioWelcome::FieldHelper; + +CheckBoxHelper::CheckBoxHelper(ProjectExplorer::JsonFieldPage *detailsPage, const QString &fieldName) + : m_field(dynamic_cast(detailsPage->jsonField(fieldName))) +{} + +void CheckBoxHelper::setChecked(bool value) +{ + QTC_ASSERT(m_field, return); + + m_field->setChecked(value); +} + +ComboBoxHelper::ComboBoxHelper(ProjectExplorer::JsonFieldPage *detailsPage, const QString &fieldName) + : m_field(dynamic_cast(detailsPage->jsonField(fieldName))) +{} + +void ComboBoxHelper::selectIndex(int index) +{ + QTC_ASSERT(m_field, return); + + m_field->selectRow(index); +} + +QString ComboBoxHelper::text(int index) const +{ + QTC_ASSERT(m_field, return {}); + + QStandardItemModel *model = m_field->model(); + if (index < 0 || index >= model->rowCount()) + return {}; + + return model->item(index)->text(); +} + +int ComboBoxHelper::indexOf(const QString &text) const +{ + QTC_ASSERT(m_field, return -1); + + const QStandardItemModel *model = m_field->model(); + for (int i = 0; i < model->rowCount(); ++i) { + const QStandardItem *item = model->item(i, 0); + const QString text = item->text(); + + if (text == text) + return i; + } + + return -1; +} + +int ComboBoxHelper::selectedIndex() const +{ + QTC_ASSERT(m_field, return -1); + + return m_field->selectedRow(); +} + +QStandardItemModel *ComboBoxHelper::model() const +{ + QTC_ASSERT(m_field, return {}); + + return m_field->model(); +} + +QStringList ComboBoxHelper::allTexts() const +{ + QTC_ASSERT(m_field, return {}); + + QStandardItemModel *model = m_field->model(); + const int rows = model->rowCount(); + QStringList result; + result.reserve(rows); + + for (int i = 0; i < rows; ++i) + result.append(model->item(i)->text()); + + return result; +} diff --git a/src/plugins/studiowelcome/fieldhelper.h b/src/plugins/studiowelcome/fieldhelper.h new file mode 100644 index 00000000000..886e49d0df8 --- /dev/null +++ b/src/plugins/studiowelcome/fieldhelper.h @@ -0,0 +1,46 @@ +// 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 + +QT_FORWARD_DECLARE_CLASS(QStandardItemModel) + +namespace ProjectExplorer { +class JsonFieldPage; +class CheckBoxField; +class ComboBoxField; +} + +namespace StudioWelcome::FieldHelper { + +class CheckBoxHelper +{ +public: + CheckBoxHelper(ProjectExplorer::JsonFieldPage *detailsPage, const QString &fieldName); + + void setChecked(bool value); + +private: + ProjectExplorer::CheckBoxField *m_field = nullptr; +}; + +class ComboBoxHelper +{ +public: + ComboBoxHelper(ProjectExplorer::JsonFieldPage *detailsPage, const QString &fieldName); + + void selectIndex(int index); + + QString text(int index) const; + int indexOf(const QString &text) const; + int selectedIndex() const; + QStandardItemModel *model() const; + QStringList allTexts() const; + +private: + ProjectExplorer::ComboBoxField *m_field = nullptr; +}; + +} // namespace StudioWelcome::FieldHelper diff --git a/src/plugins/studiowelcome/presetmodel.cpp b/src/plugins/studiowelcome/presetmodel.cpp index 06e8def612b..e4562872b7a 100644 --- a/src/plugins/studiowelcome/presetmodel.cpp +++ b/src/plugins/studiowelcome/presetmodel.cpp @@ -93,6 +93,7 @@ PresetItems PresetData::makeUserPresets(const PresetItems &wizardPresets, presetItem->qtVersion = userPresetData.qtVersion; presetItem->styleName = userPresetData.styleName; presetItem->useQtVirtualKeyboard = userPresetData.useQtVirtualKeyboard; + presetItem->enableCMakeGeneration = userPresetData.enableCMakeGeneration; presetItem->create = foundPreset->create; presetItem->description = foundPreset->description; diff --git a/src/plugins/studiowelcome/presetmodel.h b/src/plugins/studiowelcome/presetmodel.h index f23ec2ea778..94f11fb9aff 100644 --- a/src/plugins/studiowelcome/presetmodel.h +++ b/src/plugins/studiowelcome/presetmodel.h @@ -80,6 +80,7 @@ struct UserPresetItem : public PresetItem public: QString userName; bool useQtVirtualKeyboard; + bool enableCMakeGeneration; QString qtVersion; QString styleName; }; diff --git a/src/plugins/studiowelcome/qdsnewdialog.cpp b/src/plugins/studiowelcome/qdsnewdialog.cpp index 1fa82e55034..1032e7fceea 100644 --- a/src/plugins/studiowelcome/qdsnewdialog.cpp +++ b/src/plugins/studiowelcome/qdsnewdialog.cpp @@ -133,6 +133,15 @@ void QdsNewDialog::setProjectLocation(const QString &location) m_wizard.setProjectLocation(m_qmlProjectLocation); } +void QdsNewDialog::setHasCMakeGeneration(bool haveCmakeGen) +{ + if (m_qmlHasCMakeGeneration == haveCmakeGen) + return; + + m_qmlHasCMakeGeneration = haveCmakeGen; + emit hasCMakeGenerationChanged(); +} + void QdsNewDialog::onStatusMessageChanged(Utils::InfoLabel::InfoType type, const QString &message) { switch (type) { @@ -192,9 +201,16 @@ void QdsNewDialog::onWizardCreated(QStandardItemModel *screenSizeModel, QStandar auto userPreset = m_currentPreset->asUserPreset(); if (m_qmlDetailsLoaded) { + setHasCMakeGeneration(m_wizard.hasCMakeGeneration()); + + if (m_currentPreset->isUserPreset()) { + if (getHaveVirtualKeyboard()) + setUseVirtualKeyboard(userPreset->useQtVirtualKeyboard); + if (hasCMakeGeneration()) + setEnableCMakeGeneration(userPreset->enableCMakeGeneration); + } + m_targetQtVersions.clear(); - if (m_currentPreset->isUserPreset() && m_wizard.haveVirtualKeyboard()) - setUseVirtualKeyboard(userPreset->useQtVirtualKeyboard); if (m_wizard.haveTargetQtVersion()) { m_targetQtVersions = m_wizard.targetQtVersionNames(); int index = m_currentPreset->isUserPreset() ? m_wizard.targetQtVersionIndex(userPreset->qtVersion) @@ -227,6 +243,15 @@ void QdsNewDialog::onWizardCreated(QStandardItemModel *screenSizeModel, QStandar } } +void QdsNewDialog::setEnableCMakeGeneration(bool newQmlEnableCMakeGeneration) +{ + if (m_qmlEnableCMakeGeneration == newQmlEnableCMakeGeneration) + return; + + m_qmlEnableCMakeGeneration = newQmlEnableCMakeGeneration; + emit enableCMakeGenerationChanged(); +} + QString QdsNewDialog::currentPresetQmlPath() const { if (!m_currentPreset || m_currentPreset->qmlPath.isEmpty()) @@ -385,6 +410,11 @@ bool QdsNewDialog::getHaveTargetQtVersion() const return m_wizard.haveTargetQtVersion(); } +bool QdsNewDialog::hasCMakeGeneration() const +{ + return m_qmlHasCMakeGeneration; +} + void QdsNewDialog::accept() { CreateProject create{m_wizard}; @@ -395,6 +425,7 @@ void QdsNewDialog::accept() .withScreenSizes(m_qmlScreenSizeIndex, m_qmlCustomWidth, m_qmlCustomHeight) .withStyle(getStyleIndex()) .useQtVirtualKeyboard(m_qmlUseVirtualKeyboard) + .enableCMakeGeneration(m_qmlEnableCMakeGeneration) .saveAsDefaultLocation(m_qmlSaveAsDefaultLocation) .withTargetQtVersion(m_qmlTargetQtVersionIndex) .execute(); @@ -446,6 +477,7 @@ UserPresetData QdsNewDialog::currentUserPresetData(const QString &displayName) c QString targetQtVersion = ""; QString styleName = ""; bool useVirtualKeyboard = false; + bool enableCMakeGeneration = false; if (m_wizard.haveTargetQtVersion()) targetQtVersion = m_wizard.targetQtVersionName(m_qmlTargetQtVersionIndex); @@ -456,13 +488,18 @@ UserPresetData QdsNewDialog::currentUserPresetData(const QString &displayName) c if (m_wizard.haveVirtualKeyboard()) useVirtualKeyboard = m_qmlUseVirtualKeyboard; - UserPresetData preset = {m_currentPreset->categoryId, - m_currentPreset->wizardName, - displayName, - screenSize, - useVirtualKeyboard, - targetQtVersion, - styleName}; + if (m_wizard.hasCMakeGeneration()) + enableCMakeGeneration = m_qmlEnableCMakeGeneration; + + UserPresetData preset{ + m_currentPreset->categoryId, + m_currentPreset->wizardName, + displayName, + screenSize, + useVirtualKeyboard, + enableCMakeGeneration, + targetQtVersion, + styleName}; return preset; } diff --git a/src/plugins/studiowelcome/qdsnewdialog.h b/src/plugins/studiowelcome/qdsnewdialog.h index 95bfa52fe9b..b5aee2ff065 100644 --- a/src/plugins/studiowelcome/qdsnewdialog.h +++ b/src/plugins/studiowelcome/qdsnewdialog.h @@ -34,7 +34,13 @@ public: Q_PROPERTY(QString customHeight MEMBER m_qmlCustomHeight) Q_PROPERTY(int styleIndex MEMBER m_qmlStyleIndex READ getStyleIndex WRITE setStyleIndex) Q_PROPERTY(bool useVirtualKeyboard MEMBER m_qmlUseVirtualKeyboard READ getUseVirtualKeyboard WRITE setUseVirtualKeyboard NOTIFY useVirtualKeyboardChanged) + Q_PROPERTY( + bool enableCMakeGeneration + MEMBER m_qmlEnableCMakeGeneration + WRITE setEnableCMakeGeneration + NOTIFY enableCMakeGenerationChanged) Q_PROPERTY(bool haveVirtualKeyboard MEMBER m_qmlHaveVirtualKeyboard READ getHaveVirtualKeyboard NOTIFY haveVirtualKeyboardChanged) + Q_PROPERTY(bool hasCMakeGeneration READ hasCMakeGeneration NOTIFY hasCMakeGenerationChanged) Q_PROPERTY(bool haveTargetQtVersion MEMBER m_qmlHaveTargetQtVersion READ getHaveTargetQtVersion NOTIFY haveTargetQtVersionChanged) Q_PROPERTY(int targetQtVersionIndex MEMBER m_qmlTargetQtVersionIndex READ getTargetQtVersionIndex WRITE setTargetQtVersionIndex NOTIFY targetQtVersionIndexChanged) Q_PROPERTY(bool saveAsDefaultLocation MEMBER m_qmlSaveAsDefaultLocation WRITE setSaveAsDefaultLocation) @@ -85,12 +91,15 @@ public: bool getFieldsValid() const { return m_qmlFieldsValid; } bool getHaveVirtualKeyboard() const; bool getHaveTargetQtVersion() const; + bool hasCMakeGeneration() const; void setSaveAsDefaultLocation(bool value) { m_qmlSaveAsDefaultLocation = value; } QString getStatusMessage() const { return m_qmlStatusMessage; } QString getStatusType() const { return m_qmlStatusType; } + void setEnableCMakeGeneration(bool newQmlEnableCMakeGeneration); + public slots: void accept(); void reject(); @@ -102,7 +111,9 @@ signals: void projectLocationChanged(); void projectDescriptionChanged(); void useVirtualKeyboardChanged(); + void enableCMakeGenerationChanged(); void haveVirtualKeyboardChanged(); + void hasCMakeGenerationChanged(); void haveTargetQtVersionChanged(); void statusMessageChanged(); void statusTypeChanged(); @@ -129,6 +140,8 @@ private: emit projectDescriptionChanged(); } + void setHasCMakeGeneration(bool haveCmakeGen); + QString projectDescription() const { return m_qmlProjectDescription; } void updateScreenSizes(); @@ -156,7 +169,9 @@ private: // m_qmlStyleIndex is like a cache, so it needs to be updated on get() mutable int m_qmlStyleIndex = -1; bool m_qmlUseVirtualKeyboard = false; + bool m_qmlEnableCMakeGeneration = false; bool m_qmlHaveVirtualKeyboard = false; + bool m_qmlHasCMakeGeneration = false; bool m_qmlHaveTargetQtVersion = false; bool m_qmlSaveAsDefaultLocation = false; bool m_qmlFieldsValid = false; diff --git a/src/plugins/studiowelcome/userpresets.cpp b/src/plugins/studiowelcome/userpresets.cpp index ddc8a406261..cd551f5efe0 100644 --- a/src/plugins/studiowelcome/userpresets.cpp +++ b/src/plugins/studiowelcome/userpresets.cpp @@ -67,13 +67,16 @@ void UserPresetsStore::savePresets(const std::vector &presetItem QJsonArray jsonArray; for (const auto &preset : presetItems) { - QJsonObject obj({{"categoryId", preset.categoryId}, - {"wizardName", preset.wizardName}, - {"name", preset.name}, - {"screenSize", preset.screenSize}, - {"useQtVirtualKeyboard", preset.useQtVirtualKeyboard}, - {"qtVersion", preset.qtVersion}, - {"styleName", preset.styleName}}); + QJsonObject obj{ + {"categoryId", preset.categoryId}, + {"wizardName", preset.wizardName}, + {"name", preset.name}, + {"screenSize", preset.screenSize}, + {"useQtVirtualKeyboard", preset.useQtVirtualKeyboard}, + {"enableCMakeGeneration", preset.enableCMakeGeneration}, + {"qtVersion", preset.qtVersion}, + {"styleName", preset.styleName}, + }; jsonArray.append(QJsonValue{obj}); } @@ -164,6 +167,7 @@ std::vector UserPresetsStore::fetchAll() const preset.name = obj["name"].toString(); preset.screenSize = obj["screenSize"].toString(); preset.useQtVirtualKeyboard = obj["useQtVirtualKeyboard"].toBool(); + preset.enableCMakeGeneration = obj["enableCMakeGeneration"].toBool(); preset.qtVersion = obj["qtVersion"].toString(); preset.styleName = obj["styleName"].toString(); diff --git a/src/plugins/studiowelcome/userpresets.h b/src/plugins/studiowelcome/userpresets.h index 6ea15e8b60f..ae6686279d8 100644 --- a/src/plugins/studiowelcome/userpresets.h +++ b/src/plugins/studiowelcome/userpresets.h @@ -20,6 +20,7 @@ struct UserPresetData QString screenSize; bool useQtVirtualKeyboard; + bool enableCMakeGeneration; QString qtVersion; QString styleName; @@ -36,6 +37,7 @@ inline QDebug &operator<<(QDebug &d, const UserPresetData &preset) d << "UserPreset{category = " << preset.categoryId; d << "; wizardName = " << preset.wizardName; d << "; name = " << preset.name; + d << "; cmakeGeneration = " << preset.enableCMakeGeneration; d << "; screenSize = " << preset.screenSize; d << "; keyboard = " << preset.useQtVirtualKeyboard; d << "; qt = " << preset.qtVersion; @@ -48,9 +50,10 @@ inline QDebug &operator<<(QDebug &d, const UserPresetData &preset) inline bool operator==(const UserPresetData &lhs, const UserPresetData &rhs) { return lhs.categoryId == rhs.categoryId && lhs.wizardName == rhs.wizardName - && lhs.name == rhs.name && lhs.screenSize == rhs.screenSize + && lhs.enableCMakeGeneration == rhs.enableCMakeGeneration && lhs.name == rhs.name + && lhs.screenSize == rhs.screenSize && lhs.useQtVirtualKeyboard == rhs.useQtVirtualKeyboard && lhs.qtVersion == rhs.qtVersion - && lhs.styleName == rhs.styleName;; + && lhs.styleName == rhs.styleName; } enum class StorePolicy {UniqueNames, UniqueValues}; diff --git a/src/plugins/studiowelcome/wizardhandler.cpp b/src/plugins/studiowelcome/wizardhandler.cpp index b86d33a1dfb..a1882f50a2e 100644 --- a/src/plugins/studiowelcome/wizardhandler.cpp +++ b/src/plugins/studiowelcome/wizardhandler.cpp @@ -1,20 +1,21 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include -#include - #include "wizardhandler.h" +#include "fieldhelper.h" #include #include - #include #include #include +#include +#include + using namespace StudioWelcome; +using namespace StudioWelcome::FieldHelper; void WizardHandler::reset(const std::shared_ptr &presetInfo, int presetSelection) { @@ -57,8 +58,8 @@ void WizardHandler::setupWizard() emit wizardCreationFailed(); return; } - auto *screenFactorModel = getScreenFactorModel(m_detailsPage); - auto *styleModel = getStyleModel(m_detailsPage); + auto *screenFactorModel = getScreenFactorModel(); + auto *styleModel = getStyleModel(); emit wizardCreated(screenFactorModel, styleModel); } @@ -105,16 +106,9 @@ void WizardHandler::initializeFieldsPage(QWizardPage *page) fieldsPage->initializePage(); } -QStandardItemModel *WizardHandler::getScreenFactorModel(ProjectExplorer::JsonFieldPage *page) +QStandardItemModel *WizardHandler::getScreenFactorModel() { - auto *field = page->jsonField("ScreenFactor"); - if (!field) - return nullptr; - - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return nullptr); - - return cbfield->model(); + return ComboBoxHelper(m_detailsPage, "ScreenFactor").model(); } bool WizardHandler::haveStyleModel() const @@ -122,16 +116,9 @@ bool WizardHandler::haveStyleModel() const return m_wizard->hasField("ControlsStyle"); } -QStandardItemModel *WizardHandler::getStyleModel(ProjectExplorer::JsonFieldPage *page) +QStandardItemModel *WizardHandler::getStyleModel() { - auto *field = page->jsonField("ControlsStyle"); - if (!field) - return nullptr; - - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return nullptr); - - return cbfield->model(); + return ComboBoxHelper(m_detailsPage, "ControlsStyle").model(); } void WizardHandler::onWizardResetting() @@ -147,61 +134,27 @@ void WizardHandler::onWizardResetting() void WizardHandler::setScreenSizeIndex(int index) { - auto *field = m_detailsPage->jsonField("ScreenFactor"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return); - - cbfield->selectRow(index); + ComboBoxHelper(m_detailsPage, "ScreenFactor").selectIndex(index); } QString WizardHandler::screenSizeName(int index) const { - auto *field = m_detailsPage->jsonField("ScreenFactor"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return ""); - - QStandardItemModel *model = cbfield->model(); - if (index < 0 || index >= model->rowCount()) - return {}; - - QString text = model->item(index)->text(); - return text; + return ComboBoxHelper(m_detailsPage, "ScreenFactor").text(index); } int WizardHandler::screenSizeIndex() const { - auto *field = m_detailsPage->jsonField("ScreenFactor"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return -1); - - return cbfield->selectedRow(); + return ComboBoxHelper(m_detailsPage, "ScreenFactor").selectedIndex(); } int WizardHandler::screenSizeIndex(const QString &sizeName) const { - auto *field = m_detailsPage->jsonField("ScreenFactor"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return false); - - const QStandardItemModel *model = cbfield->model(); - for (int i = 0; i < model->rowCount(); ++i) { - const QStandardItem *item = model->item(i, 0); - const QString text = item->text(); - - if (text == sizeName) - return i; - } - - return -1; + return ComboBoxHelper(m_detailsPage, "ScreenFactor").indexOf(sizeName); } void WizardHandler::setTargetQtVersionIndex(int index) { - auto *field = m_detailsPage->jsonField("TargetQtVersion"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return); - - cbfield->selectRow(index); + ComboBoxHelper(m_detailsPage, "TargetQtVersion").selectIndex(index); } bool WizardHandler::haveTargetQtVersion() const @@ -211,117 +164,47 @@ bool WizardHandler::haveTargetQtVersion() const QString WizardHandler::targetQtVersionName(int index) const { - auto *field = m_detailsPage->jsonField("TargetQtVersion"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return ""); - - QStandardItemModel *model = cbfield->model(); - if (index < 0 || index >= model->rowCount()) - return {}; - - QString text = model->item(index)->text(); - return text; + return ComboBoxHelper(m_detailsPage, "TargetQtVersion").text(index); } QStringList WizardHandler::targetQtVersionNames() const { - auto *field = m_detailsPage->jsonField("TargetQtVersion"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return {}); - - QStandardItemModel *model = cbfield->model(); - QStringList targetVersions; - - for (int i = 0; i < model->rowCount(); ++i) - targetVersions.append(model->item(i)->text()); - - return targetVersions; + return ComboBoxHelper(m_detailsPage, "TargetQtVersion").allTexts(); } int WizardHandler::targetQtVersionIndex(const QString &qtVersionName) const { - auto *field = m_detailsPage->jsonField("TargetQtVersion"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return -1); - - const QStandardItemModel *model = cbfield->model(); - for (int i = 0; i < model->rowCount(); ++i) { - const QStandardItem *item = model->item(i, 0); - const QString text = item->text(); - - if (text == qtVersionName) - return i; - } - - return -1; + return ComboBoxHelper(m_detailsPage, "TargetQtVersion").indexOf(qtVersionName); } int WizardHandler::targetQtVersionIndex() const { - auto *field = m_detailsPage->jsonField("TargetQtVersion"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return -1); - - return cbfield->selectedRow(); + return ComboBoxHelper(m_detailsPage, "TargetQtVersion").selectedIndex(); } void WizardHandler::setStyleIndex(int index) { - auto *field = m_detailsPage->jsonField("ControlsStyle"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return); - - cbfield->selectRow(index); + ComboBoxHelper(m_detailsPage, "ControlsStyle").selectIndex(index); } int WizardHandler::styleIndex() const { - auto *field = m_detailsPage->jsonField("ControlsStyle"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return -1); - - return cbfield->selectedRow(); + return ComboBoxHelper(m_detailsPage, "ControlsStyle").selectedIndex(); } int WizardHandler::styleIndex(const QString &styleName) const { - auto *field = m_detailsPage->jsonField("ControlsStyle"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return -1); - - const QStandardItemModel *model = cbfield->model(); - for (int i = 0; i < model->rowCount(); ++i) { - const QStandardItem *item = model->item(i, 0); - const QString text = item->text(); - - if (text == styleName) - return i; - } - - return -1; + return ComboBoxHelper(m_detailsPage, "ControlsStyle").indexOf(styleName); } QString WizardHandler::styleName(int index) const { - auto *field = m_detailsPage->jsonField("ControlsStyle"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return ""); - - QStandardItemModel *model = cbfield->model(); - if (index < 0 || index >= model->rowCount()) - return {}; - - QString text = model->item(index)->text(); - return text; + return ComboBoxHelper(m_detailsPage, "ControlsStyle").text(index); } void WizardHandler::setUseVirtualKeyboard(bool value) { - auto *field = m_detailsPage->jsonField("UseVirtualKeyboard"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return); - - cbfield->setChecked(value); + CheckBoxHelper(m_detailsPage, "UseVirtualKeyboard").setChecked(value); } bool WizardHandler::haveVirtualKeyboard() const @@ -329,6 +212,16 @@ bool WizardHandler::haveVirtualKeyboard() const return m_wizard->hasField("UseVirtualKeyboard"); } +void WizardHandler::enableCMakeGeneration(bool value) +{ + CheckBoxHelper(m_detailsPage, "EnableCMakeGeneration").setChecked(value); +} + +bool WizardHandler::hasCMakeGeneration() const +{ + return m_wizard->hasField("EnableCMakeGeneration"); +} + void WizardHandler::run(const std::function &processPage) { m_wizard->restart(); diff --git a/src/plugins/studiowelcome/wizardhandler.h b/src/plugins/studiowelcome/wizardhandler.h index e6009dd9362..640ebb41342 100644 --- a/src/plugins/studiowelcome/wizardhandler.h +++ b/src/plugins/studiowelcome/wizardhandler.h @@ -48,6 +48,9 @@ public: void setUseVirtualKeyboard(bool value); bool haveVirtualKeyboard() const; + void enableCMakeGeneration(bool value); + bool hasCMakeGeneration() const; + void setProjectName(const QString &name); void setProjectLocation(const Utils::FilePath &location); @@ -67,8 +70,8 @@ private: void initializeProjectPage(QWizardPage *page); void initializeFieldsPage(QWizardPage *page); - QStandardItemModel *getScreenFactorModel(ProjectExplorer::JsonFieldPage *page); - QStandardItemModel *getStyleModel(ProjectExplorer::JsonFieldPage *page); + QStandardItemModel *getScreenFactorModel(); + QStandardItemModel *getStyleModel(); private slots: void onWizardResetting(); From c00485d9a29d9d5d5546ad42bf39363fce9d0793 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 14 Oct 2024 15:59:23 +0300 Subject: [PATCH 31/44] QmlDesigner: Fix Image elements in composed effects when no image source If image source is empty, we still need to generate the Image element for the effect, as user may set the image source later via effect properties. Change-Id: I3a7641f144f6be78062d24e8219064d050d0e471 Reviewed-by: Mahmoud Badri --- src/plugins/effectcomposer/effectcomposermodel.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/plugins/effectcomposer/effectcomposermodel.cpp b/src/plugins/effectcomposer/effectcomposermodel.cpp index 673c6c62b70..926bd948bbb 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.cpp +++ b/src/plugins/effectcomposer/effectcomposermodel.cpp @@ -1403,8 +1403,6 @@ QString EffectComposerModel::valueAsVariable(const Uniform &uniform) // Return name for the image property Image element QString EffectComposerModel::getImageElementName(const Uniform &uniform, bool localFiles) { - if (localFiles && uniform.value().toString().isEmpty()) - return QStringLiteral("null"); QString simplifiedName = uniform.name().simplified(); simplifiedName = simplifiedName.remove(' '); return QStringLiteral("imageItem") + simplifiedName; @@ -1925,11 +1923,7 @@ QString EffectComposerModel::getQmlImagesString(bool localFiles) for (Uniform *uniform : uniforms) { if (uniform->type() == Uniform::Type::Sampler) { QString imagePath = uniform->value().toString(); - // For preview, generate image element even if path is empty, as changing uniform values - // will not trigger qml code regeneration if (localFiles) { - if (imagePath.isEmpty()) - continue; QFileInfo fi(imagePath); imagePath = fi.fileName(); imagesString += QString(" property url %1Url: \"%2\"\n") From d7edd5c757ef2e1c9555fcf3c1e5090a217cef68 Mon Sep 17 00:00:00 2001 From: Pranta Dastider Date: Wed, 2 Oct 2024 17:43:08 +0200 Subject: [PATCH 32/44] QmlDesigner: Update contextual help doc with Git information The contextual help was missing Git requirement information to be able to use the CMake Generation option in Design Studio. This patch fixes the issue by including the information. Change-Id: I094d6a411df96d9995578cc0dbdd26a5e84f2d6e Reviewed-by: Mats Honkamaa Reviewed-by: Thomas Hartmann --- .../src/developers/studio-designer-developer-workflow.qdoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/qtdesignstudio/src/developers/studio-designer-developer-workflow.qdoc b/doc/qtdesignstudio/src/developers/studio-designer-developer-workflow.qdoc index 5b59d665971..78e90404542 100644 --- a/doc/qtdesignstudio/src/developers/studio-designer-developer-workflow.qdoc +++ b/doc/qtdesignstudio/src/developers/studio-designer-developer-workflow.qdoc @@ -39,6 +39,9 @@ \list \li Qt Creator 13.0 or above. \li \QDS 4.5 or above. + \li Git. + + \note Learn more about getting Git \l {https://wiki.qt.io/Git_Installation} {here}. \endlist \list 1 From e46c8740a323c5fe788de89d8225b2127bdb44e8 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Tue, 15 Oct 2024 12:23:32 +0300 Subject: [PATCH 33/44] QmlDesigner: Check the existence of the view for the Camera View For making sure that the scene is available, we should check both of the following nodes: * Scene manager * A scene root node among ancestors Fixes: QDS-13671 Change-Id: I7439727193b51e80a0500f8aab5a86c5c84d7f02 Reviewed-by: Miikka Heikkinen --- .../qml2puppet/qml2puppet/editor3d/generalhelper.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp index 4d57c0d1646..19c50cfba0a 100644 --- a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp +++ b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp @@ -704,7 +704,16 @@ bool GeneralHelper::isSceneObject(QQuick3DNode *node) const const QQuick3DObject *sceneObject = importSceneManager->m_nodeMap.value(objectPrivate->spatialNode, nullptr); - return sceneObject != nullptr; + if (!sceneObject) + return false; + + QQuick3DNode *parentNode = node->parentNode(); + while (parentNode) { + if (parentNode->inherits("QQuick3DSceneRootNode")) + return true; + parentNode = parentNode->parentNode(); + } + return false; } // Emitter gizmo model creation is done in C++ as creating dynamic properties and From 5d331cd96539336856f3dc04fee51cce0423911a Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 15 Oct 2024 14:07:25 +0300 Subject: [PATCH 34/44] QmlDesigner: Remove unused DropArea from 3D view This is legacy code from the times 3D view was still a separate window. Change-Id: Iffa117e490b38ac2a394981dfcca237a6bdb55ce Reviewed-by: Mahmoud Badri --- src/tools/qml2puppet/mockfiles/qt6/EditView3D.qml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/tools/qml2puppet/mockfiles/qt6/EditView3D.qml b/src/tools/qml2puppet/mockfiles/qt6/EditView3D.qml index e159b532c34..c4cae6c5c2d 100644 --- a/src/tools/qml2puppet/mockfiles/qt6/EditView3D.qml +++ b/src/tools/qml2puppet/mockfiles/qt6/EditView3D.qml @@ -971,10 +971,6 @@ Item { } } - DropArea { - anchors.fill: parent - } - Overlay2D { id: gizmoLabel targetNode: activeOverlayView.moveGizmo.visible ? activeOverlayView.moveGizmo From 5a19f357a0cb9607d21d6b37baeb816349233275 Mon Sep 17 00:00:00 2001 From: Shrief Gabr Date: Fri, 11 Oct 2024 07:36:18 +0300 Subject: [PATCH 35/44] QmlDesigner: Provide feedback on folder move failure Fixes: QDS-13785 Change-Id: I014066a4dfad9979a54b8b7b0c544f9f37ec340d Reviewed-by: Mahmoud Badri Reviewed-by: Miikka Heikkinen --- .../assetslibrary/assetslibrarymodel.cpp | 2 +- .../assetslibrary/assetslibrarywidget.cpp | 25 +++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp index febf11a9176..a47192854b1 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp @@ -202,7 +202,7 @@ bool AssetsLibraryModel::isSameOrDescendantPath(const QUrl &source, const QStrin Utils::FilePath srcPath = Utils::FilePath::fromUrl(source); Utils::FilePath targetPath = Utils::FilePath::fromString(target); - return targetPath.isChildOf(srcPath); + return srcPath == targetPath || targetPath.isChildOf(srcPath); } bool AssetsLibraryModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 1ccda93b130..3af1ebcde99 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -391,11 +391,11 @@ void AssetsLibraryWidget::handleAssetsDrop(const QList &urls, const QStrin if (destDir.isFile()) destDir = destDir.parentDir(); - QMessageBox mb; - mb.setInformativeText("What would you like to do with the existing asset?"); - mb.addButton("Keep Both", QMessageBox::AcceptRole); - mb.addButton("Replace", QMessageBox::ResetRole); - mb.addButton("Cancel", QMessageBox::RejectRole); + QMessageBox msgBox; + msgBox.setInformativeText("What would you like to do with the existing asset?"); + msgBox.addButton("Keep Both", QMessageBox::AcceptRole); + msgBox.addButton("Replace", QMessageBox::ResetRole); + msgBox.addButton("Cancel", QMessageBox::RejectRole); for (const QUrl &url : urls) { Utils::FilePath src = Utils::FilePath::fromUrl(url); @@ -405,9 +405,9 @@ void AssetsLibraryWidget::handleAssetsDrop(const QList &urls, const QStrin continue; if (dest.exists()) { - mb.setText("An asset named " + dest.fileName() + " already exists."); - mb.exec(); - int userAction = mb.buttonRole(mb.clickedButton()); + msgBox.setText("An asset named " + dest.fileName() + " already exists."); + msgBox.exec(); + int userAction = msgBox.buttonRole(msgBox.clickedButton()); if (userAction == QMessageBox::AcceptRole) { // "Keep Both" dest = Utils::FilePath::fromString(UniqueName::generatePath(dest.toString())); @@ -421,8 +421,13 @@ void AssetsLibraryWidget::handleAssetsDrop(const QList &urls, const QStrin } } - if (!src.renameFile(dest)) - qWarning() << __FUNCTION__ << "Failed to move asset from" << src << "to" << dest; + if (!src.renameFile(dest) && src.isDir()) { + QMessageBox errBox; + QString message = QString("Failed to move folder \"%1\".\nThe folder might contain subfolders or one of its files is in use.") + .arg(src.fileName()); + errBox.setInformativeText(message); + errBox.exec(); + } } if (m_assetsView->model()) From f93e12de2b8f282b25005bf7044c23bcb99e5241 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 26 Sep 2024 13:38:24 +0200 Subject: [PATCH 36/44] QmlDesigner: Add hints to hide node in navigator For effects we want to explcitly hide certain items. Change-Id: I49748f851453c7c8d5001ca696d5a6b1b2969550 Reviewed-by: Thomas Hartmann --- .../navigator/navigatortreemodel.cpp | 5 ++- .../libs/designercore/include/nodehints.h | 1 + .../libs/designercore/include/nodemetainfo.h | 1 + .../libs/designercore/metainfo/nodehints.cpp | 13 +++++++ .../designercore/metainfo/nodemetainfo.cpp | 12 ++++++ .../projectstorage/projectstorageinfotypes.h | 7 +++- .../projectstorage/typeannotationreader.cpp | 2 + .../tests/printers/gtest-creator-printing.cpp | 3 ++ .../unittests/metainfo/nodemetainfo-test.cpp | 37 +++++++++++++++++++ .../typeannotationreader-test.cpp | 29 +++++++++++++++ 10 files changed, 107 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 8e5a279ea03..2c6a02002d4 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -324,7 +324,10 @@ QList NavigatorTreeModel::filteredList(const NodeListProperty &proper if (filter) { list.append(::Utils::filtered(nameFilteredList, [](const ModelNode &arg) { - const bool value = (QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator()) + const bool visibleInNavigator = NodeHints::fromModelNode(arg).visibleInNavigator(); + const bool hideInNavigator = NodeHints::fromModelNode(arg).hideInNavigator(); + const bool value = ((QmlItemNode::isValidQmlItemNode(arg) && !hideInNavigator) + || visibleInNavigator) && arg.id() != Constants::MATERIAL_LIB_ID; return value; })); diff --git a/src/plugins/qmldesigner/libs/designercore/include/nodehints.h b/src/plugins/qmldesigner/libs/designercore/include/nodehints.h index 99470db65f1..5992d7d64a3 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/nodehints.h +++ b/src/plugins/qmldesigner/libs/designercore/include/nodehints.h @@ -49,6 +49,7 @@ public: QStringList visibleNonDefaultProperties() const; bool takesOverRenderingOfChildren() const; bool visibleInNavigator() const; + bool hideInNavigator() const; bool visibleInLibrary() const; QString forceNonDefaultProperty() const; QPair setParentProperty() const; diff --git a/src/plugins/qmldesigner/libs/designercore/include/nodemetainfo.h b/src/plugins/qmldesigner/libs/designercore/include/nodemetainfo.h index ea01e9438b6..ed2920cac4b 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/nodemetainfo.h +++ b/src/plugins/qmldesigner/libs/designercore/include/nodemetainfo.h @@ -87,6 +87,7 @@ public: FlagIs isStackedContainer() const; FlagIs takesOverRenderingOfChildren() const; FlagIs visibleInNavigator() const; + FlagIs hideInNavigator() const; FlagIs visibleInLibrary() const; bool hasProperty(::Utils::SmallStringView propertyName) const; diff --git a/src/plugins/qmldesigner/libs/designercore/metainfo/nodehints.cpp b/src/plugins/qmldesigner/libs/designercore/metainfo/nodehints.cpp index 1f9a3e42bd6..5cbae6861fa 100644 --- a/src/plugins/qmldesigner/libs/designercore/metainfo/nodehints.cpp +++ b/src/plugins/qmldesigner/libs/designercore/metainfo/nodehints.cpp @@ -321,6 +321,19 @@ bool NodeHints::visibleInNavigator() const return evaluateBooleanExpression("visibleInNavigator", false); } +bool NodeHints::hideInNavigator() const +{ + if (!isValid()) + return false; + + auto flagIs = m_modelNode.metaInfo().hideInNavigator(); + + if (flagIs != FlagIs::Set) + return convert(flagIs); + + return evaluateBooleanExpression("hideInNavigator", false); +} + bool NodeHints::visibleInLibrary() const { auto flagIs = m_metaInfo.visibleInLibrary(); diff --git a/src/plugins/qmldesigner/libs/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/libs/designercore/metainfo/nodemetainfo.cpp index 47943e096e9..56836119d06 100644 --- a/src/plugins/qmldesigner/libs/designercore/metainfo/nodemetainfo.cpp +++ b/src/plugins/qmldesigner/libs/designercore/metainfo/nodemetainfo.cpp @@ -1780,6 +1780,18 @@ FlagIs NodeMetaInfo::visibleInNavigator() const return FlagIs::Set; } +FlagIs NodeMetaInfo::hideInNavigator() const +{ + if constexpr (useProjectStorage()) { + if (isValid()) + return typeData().traits.hideInNavigator; + + return FlagIs::False; + } + + return FlagIs::Set; +} + FlagIs NodeMetaInfo::visibleInLibrary() const { if constexpr (useProjectStorage()) { diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinfotypes.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinfotypes.h index 7d1598191d6..8b602ed65a9 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinfotypes.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinfotypes.h @@ -147,6 +147,7 @@ struct TypeTraits , takesOverRenderingOfChildren{FlagIs::False} , visibleInNavigator{FlagIs::False} , visibleInLibrary{FlagIs::False} + , hideInNavigator{FlagIs::False} , dummy2{0U} {} @@ -193,7 +194,8 @@ struct TypeTraits keyValue("is stacked container", typeTraits.isStackedContainer), keyValue("takes over rendering of children", typeTraits.takesOverRenderingOfChildren), keyValue("visible in navigator", typeTraits.visibleInNavigator), - keyValue("visible in library", typeTraits.visibleInLibrary)); + keyValue("visible in library", typeTraits.visibleInLibrary), + keyValue("hide in navigator", typeTraits.hideInNavigator)); convertToString(string, dict); } @@ -228,7 +230,8 @@ struct TypeTraits FlagIs takesOverRenderingOfChildren : 2; FlagIs visibleInNavigator : 2; FlagIs visibleInLibrary : 2; - unsigned int dummy2 : 6; + FlagIs hideInNavigator : 2; + unsigned int dummy2 : 4; }; unsigned int annotation; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.cpp index 71eba949662..4d604cdf2ea 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.cpp @@ -400,6 +400,8 @@ void setTrait(QStringView name, FlagIs flag, Storage::TypeTraits &traits) traits.visibleInNavigator = flag; } else if (name == "visibleInLibrary"_L1) { traits.visibleInLibrary = flag; + } else if (name == "hideInNavigator"_L1) { + traits.hideInNavigator = flag; } } diff --git a/tests/unit/tests/printers/gtest-creator-printing.cpp b/tests/unit/tests/printers/gtest-creator-printing.cpp index fac58b7bd90..d7a63fe6900 100644 --- a/tests/unit/tests/printers/gtest-creator-printing.cpp +++ b/tests/unit/tests/printers/gtest-creator-printing.cpp @@ -656,6 +656,9 @@ std::ostream &operator<<(std::ostream &out, TypeTraits traits) if (traits.visibleInLibrary != QmlDesigner::FlagIs::False) out << " | visibleInLibrary(" << traits.visibleInLibrary << ")"; + if (traits.hideInNavigator != QmlDesigner::FlagIs::False) + out << " | hideInNavigator(" << traits.hideInNavigator << ")"; + return out << ")"; } diff --git a/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp index b17a38098ee..f3f55136f27 100644 --- a/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp +++ b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp @@ -3061,6 +3061,43 @@ TEST_F(NodeMetaInfo, invalid_is_not_visible_in_library) ASSERT_THAT(visibleInLibrary, FlagIs::False); } +TEST_F(NodeMetaInfo, object_is_not_hide_in_navigator) +{ + auto hideInNavigator = objectMetaInfo.hideInNavigator(); + + ASSERT_THAT(hideInNavigator, FlagIs::False); +} + +TEST_F(NodeMetaInfo, default_is_not_hide_in_navigator) +{ + auto hideInNavigator = QmlDesigner::NodeMetaInfo{}.hideInNavigator(); + + ASSERT_THAT(hideInNavigator, FlagIs::False); +} + +TEST_F(NodeMetaInfo, invalid_is_not_hide_in_navigator) +{ + auto node = model.createModelNode("Foo"); + auto metaInfo = node.metaInfo(); + + auto hideInNavigator = metaInfo.hideInNavigator(); + + ASSERT_THAT(hideInNavigator, FlagIs::False); +} + +TEST_F(NodeMetaInfo, component_is_hide_in_navigator) +{ + auto moduleId = projectStorageMock.createModule("/path/to/project", ModuleKind::PathLibrary); + TypeTraits traits{TypeTraitsKind::Reference}; + traits.hideInNavigator = FlagIs::True; + auto typeId = projectStorageMock.createType(moduleId, "Foo", traits); + QmlDesigner::NodeMetaInfo metaInfo{typeId, &projectStorageMock}; + + auto hideInNavigator = metaInfo.hideInNavigator(); + + ASSERT_THAT(hideInNavigator, FlagIs::True); +} + TEST_F(NodeMetaInfo, component_is_visible_in_library) { auto moduleId = projectStorageMock.createModule("/path/to/project", ModuleKind::PathLibrary); diff --git a/tests/unit/tests/unittests/projectstorage/typeannotationreader-test.cpp b/tests/unit/tests/unittests/projectstorage/typeannotationreader-test.cpp index b91a89bbaf7..2959a19799c 100644 --- a/tests/unit/tests/unittests/projectstorage/typeannotationreader-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/typeannotationreader-test.cpp @@ -236,6 +236,35 @@ TEST_F(TypeAnnotationReader, parse_false_canBeDroppedInNavigator) IsEmpty()))); } +TEST_F(TypeAnnotationReader, parse_true_hideInNavigator) +{ + using QmlDesigner::FlagIs; + auto content = QString{R"xy( + MetaInfo { + Type { + name: "QtQuick.Controls.Frame" + icon: "images/frame-icon16.png" + + Hints { + hideInNavigator: true + } + } + })xy"}; + traits.hideInNavigator = FlagIs::True; + + auto annotations = reader.parseTypeAnnotation(content, "/path", sourceId, directorySourceId); + + ASSERT_THAT(annotations, + ElementsAre(IsTypeAnnotation(sourceId, + directorySourceId, + "Frame", + moduleId("QtQuick.Controls"), + "/path/images/frame-icon16.png", + traits, + IsEmpty(), + IsEmpty()))); +} + TEST_F(TypeAnnotationReader, parse_true_canBeDroppedInView3D) { using QmlDesigner::FlagIs; From ff32c0ef68705c8a7c2e8d28c69f468659b19dc1 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Tue, 15 Oct 2024 15:22:53 +0300 Subject: [PATCH 37/44] QmlDesigner: Ensure Content library tabs always visible Tabs are now responsive with the width of the view. Also a tooltip makes sure user can view the name of the tab in case it is elided. Also wrapped the message that appears when the materials view is empty. Fixes: QDS-13795 Change-Id: I43c08124696e252b834c846ae24975dd837400c5 Reviewed-by: Shrief Gabr Reviewed-by: Ali Kianian Reviewed-by: Miikka Heikkinen --- .../ContentLibraryMaterialsView.qml | 2 ++ .../contentLibraryQmlSource/ContentLibraryTabBar.qml | 4 +++- .../ContentLibraryTabButton.qml | 10 ++++++++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml index c7b2f5a0822..8cfabf06d22 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml @@ -133,6 +133,8 @@ HelperWidgets.ScrollView { topPadding: 10 leftPadding: 10 visible: root.materialsModel.isEmpty + wrapMode: Text.WordWrap + width: root.width - x } } } diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml index ca8fb64eccf..a0942bc64a6 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml @@ -2,11 +2,12 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick +import QtQuick.Layouts import HelperWidgets 2.0 as HelperWidgets import StudioControls 1.0 as StudioControls import StudioTheme 1.0 as StudioTheme -Row { +RowLayout { id: root property int currIndex: 0 @@ -24,6 +25,7 @@ Row { icon: modelData.icon selected: root.currIndex === index onClicked: root.currIndex = index + Layout.fillWidth: true } } } diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml index 587f846a10b..cc8efbf7168 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick +import QtQuick.Controls import HelperWidgets 2.0 as HelperWidgets import StudioControls 1.0 as StudioControls import StudioTheme 1.0 as StudioTheme @@ -16,7 +17,6 @@ Rectangle { property bool selected: false height: button.height - width: button.width + label.width + contentRow.spacing + 6 color: StudioTheme.Values.themeToolbarBackground radius: StudioTheme.Values.smallRadius @@ -43,9 +43,9 @@ Rectangle { color: StudioTheme.Values.themeTextColor text: qsTr("Materials") font.pixelSize: StudioTheme.Values.baseFontSize - horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter elide: Text.ElideRight + width: root.width - x } } @@ -56,6 +56,12 @@ Rectangle { onClicked: root.clicked() } + StudioControls.ToolTip { + visible: mouseArea.containsMouse + text: label.text + delay: 1000 + } + states: [ State { name: "default" From 867343465d55de37ab801d074f6756cf4c0025c1 Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Wed, 16 Oct 2024 11:21:47 +0300 Subject: [PATCH 38/44] Doc: Add links to overview pages Add links to existing overview pages in the left side bar Task-number: QDS-13385 Change-Id: I1ae626532219d96f9b29ddaa8022a8fc1935a279 Reviewed-by: Johanna Vanhatapio --- doc/qtdesignstudio/config/style/qt5-sidebar.html | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/qtdesignstudio/config/style/qt5-sidebar.html b/doc/qtdesignstudio/config/style/qt5-sidebar.html index 6fa341ba470..f1e2fc4af57 100644 --- a/doc/qtdesignstudio/config/style/qt5-sidebar.html +++ b/doc/qtdesignstudio/config/style/qt5-sidebar.html @@ -92,6 +92,7 @@

      • Components
          +
        • Overview
        • Annotating Designs
        • Adding and Removing Modules
        • Creating Component Instances
        • @@ -212,6 +213,7 @@
          • Qt Design Studio on MCUs
              +
            • Overview
            • Connecting MCUs with Qt Creator
            • Creating Projects for MCUs
            • Creating UIs for MCUs
            • @@ -315,6 +317,7 @@

              Tutorials

                +
              • Overview
              • Adding Multi-lanugage support to Your Project
              • Animated State Transitions
              • Creating a C++ Backend for a Qt Design Studio Application
              • @@ -334,6 +337,7 @@

                Examples

                  +
                • Overview
                • Coffee Machine
                • E-Bike Design
                • Effect Composer Example
                • @@ -423,6 +427,7 @@
                  • Views
                      +
                    • Overview
                    • 2D
                    • 3D
                    • Assets
                    • From eea998da9a96e647aad56721042763c22b0a452b Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Thu, 17 Oct 2024 11:32:54 +0300 Subject: [PATCH 39/44] EffectComposer: Save composition's root shaders to the qep file Shaders of the root are saved as `vertexCode` and `fragmentCode` into the root of the qep file. Task-number: QDS-13852 Fixes: QDS-13832 Change-Id: I71ff4d21400d01be999463d1ac5da13eb70c5f69 Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../effectcomposer/effectcomposermodel.cpp | 143 ++++++++++-------- .../effectcomposer/effectcomposermodel.h | 12 +- 2 files changed, 89 insertions(+), 66 deletions(-) diff --git a/src/plugins/effectcomposer/effectcomposermodel.cpp b/src/plugins/effectcomposer/effectcomposermodel.cpp index 926bd948bbb..0d9fca2b526 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.cpp +++ b/src/plugins/effectcomposer/effectcomposermodel.cpp @@ -59,11 +59,12 @@ EffectComposerModel::EffectComposerModel(QObject *parent) QHash EffectComposerModel::roleNames() const { - QHash roles; - roles[NameRole] = "nodeName"; - roles[EnabledRole] = "nodeEnabled"; - roles[UniformsRole] = "nodeUniformsModel"; - roles[Dependency] = "isDependency"; + static const QHash roles = { + {NameRole, "nodeName"}, + {EnabledRole, "nodeEnabled"}, + {UniformsRole, "nodeUniformsModel"}, + {Dependency, "isDependency"}, + }; return roles; } @@ -207,6 +208,8 @@ void EffectComposerModel::clear(bool clearName) if (clearName) { setCurrentComposition(""); setCompositionPath(""); + resetRootFragmentShader(); + resetRootVertexShader(); } setHasUnsavedChanges(!m_currentComposition.isEmpty()); @@ -253,8 +256,6 @@ void EffectComposerModel::setFragmentShader(const QString &newFragmentShader) return; m_fragmentShader = newFragmentShader; - - rebakeIfLiveUpdateMode(); } QString EffectComposerModel::vertexShader() const @@ -268,8 +269,40 @@ void EffectComposerModel::setVertexShader(const QString &newVertexShader) return; m_vertexShader = newVertexShader; +} - rebakeIfLiveUpdateMode(); +void EffectComposerModel::setRootFragmentShader(const QString &shader) +{ + m_rootFragmentShader = shader; +} + +void EffectComposerModel::resetRootFragmentShader() +{ + static const QString defaultRootFragmentShader = { + "void main() {\n" + " fragColor = texture(iSource, texCoord);\n" + " @nodes\n" + " fragColor = fragColor * qt_Opacity;\n" + "}\n"}; + setRootFragmentShader(defaultRootFragmentShader); +} + +void EffectComposerModel::setRootVertexShader(const QString &shader) +{ + m_rootVertexShader = shader; +} + +void EffectComposerModel::resetRootVertexShader() +{ + static const QString defaultRootVertexShader = { + "void main() {\n" + " texCoord = qt_MultiTexCoord0;\n" + " fragCoord = qt_Vertex.xy;\n" + " vec2 vertCoord = qt_Vertex.xy;\n" + " @nodes\n" + " gl_Position = qt_Matrix * vec4(vertCoord, 0.0, 1.0);\n" + "}\n"}; + setRootVertexShader(defaultRootVertexShader); } QString EffectComposerModel::qmlComponentString() const @@ -978,9 +1011,19 @@ void EffectComposerModel::saveComposition(const QString &name) nodesArray.append(nodeObject); } + auto toJsonArray = [](const QString &code) -> QJsonArray { + return QJsonArray::fromStringList(code.split('\n')); + }; + if (!nodesArray.isEmpty()) json.insert("nodes", nodesArray); + if (!m_rootVertexShader.isEmpty()) + json.insert("vertexCode", toJsonArray(m_rootVertexShader)); + + if (!m_rootFragmentShader.isEmpty()) + json.insert("fragmentCode", toJsonArray(m_rootFragmentShader)); + QJsonObject rootJson; rootJson.insert("QEP", json); QJsonDocument jsonDoc(rootJson); @@ -1009,25 +1052,20 @@ void EffectComposerModel::openMainShadersCodeEditor() if (!m_shadersCodeEditor) { m_shadersCodeEditor = Utils::makeUniqueObjectLatePtr( currentComposition()); - m_shadersCodeEditor->setFragmentValue(generateFragmentShader(true)); - m_shadersCodeEditor->setVertexValue(generateVertexShader(true)); + m_shadersCodeEditor->setFragmentValue(m_rootFragmentShader); + m_shadersCodeEditor->setVertexValue(m_rootVertexShader); + + connect(m_shadersCodeEditor.get(), &EffectShadersCodeEditor::vertexValueChanged, this, [this] { + setRootVertexShader(m_shadersCodeEditor->vertexValue()); + setHasUnsavedChanges(true); + rebakeIfLiveUpdateMode(); + }); connect( - m_shadersCodeEditor.get(), - &EffectShadersCodeEditor::vertexValueChanged, - this, - [this] { - setVertexShader(m_shadersCodeEditor->vertexValue()); - setHasUnsavedChanges(true); - }); - - connect( - m_shadersCodeEditor.get(), - &EffectShadersCodeEditor::fragmentValueChanged, - this, - [this] { - setFragmentShader(m_shadersCodeEditor->fragmentValue()); + m_shadersCodeEditor.get(), &EffectShadersCodeEditor::fragmentValueChanged, this, [this] { + setRootFragmentShader(m_shadersCodeEditor->fragmentValue()); setHasUnsavedChanges(true); + rebakeIfLiveUpdateMode(); }); connect( @@ -1090,6 +1128,23 @@ void EffectComposerModel::openComposition(const QString &path) return; } + auto toCodeBlock = [](const QJsonValue &jsonValue) -> QString { + if (!jsonValue.isArray()) + return {}; + + QString code; + const QJsonArray array = jsonValue.toArray(); + for (const QJsonValue &lineValue : array) { + if (lineValue.isString()) + code += lineValue.toString() + '\n'; + } + + return code; + }; + + setRootVertexShader(toCodeBlock(json["vertexCode"])); + setRootFragmentShader(toCodeBlock(json["fragmentCode"])); + if (json.contains("nodes") && json["nodes"].isArray()) { beginResetModel(); QHash refCounts; @@ -1486,32 +1541,6 @@ QString EffectComposerModel::processFragmentRootLine(const QString &line) return output; } -QStringList EffectComposerModel::getDefaultRootVertexShader() -{ - if (m_defaultRootVertexShader.isEmpty()) { - m_defaultRootVertexShader << "void main() {"; - m_defaultRootVertexShader << " texCoord = qt_MultiTexCoord0;"; - m_defaultRootVertexShader << " fragCoord = qt_Vertex.xy;"; - m_defaultRootVertexShader << " vec2 vertCoord = qt_Vertex.xy;"; - m_defaultRootVertexShader << " @nodes"; - m_defaultRootVertexShader << " gl_Position = qt_Matrix * vec4(vertCoord, 0.0, 1.0);"; - m_defaultRootVertexShader << "}"; - } - return m_defaultRootVertexShader; -} - -QStringList EffectComposerModel::getDefaultRootFragmentShader() -{ - if (m_defaultRootFragmentShader.isEmpty()) { - m_defaultRootFragmentShader << "void main() {"; - m_defaultRootFragmentShader << " fragColor = texture(iSource, texCoord);"; - m_defaultRootFragmentShader << " @nodes"; - m_defaultRootFragmentShader << " fragColor = fragColor * qt_Opacity;"; - m_defaultRootFragmentShader << "}"; - } - return m_defaultRootFragmentShader; -} - // Remove all post-processing tags ("@tag") from the code. // Except "@nodes" tag as that is handled later. QStringList EffectComposerModel::removeTagsFromCode(const QStringList &codeLines) @@ -1574,7 +1603,7 @@ QString EffectComposerModel::generateVertexShader(bool includeUniforms) // split to root and main parts QString s_root; QString s_main; - QStringList s_sourceCode; + QStringList s_sourceCode = m_rootVertexShader.split('\n'); m_shaderVaryingVariables.clear(); for (const CompositionNode *n : std::as_const(m_nodes)) { if (!n->vertexCode().isEmpty() && n->isEnabled()) { @@ -1591,11 +1620,6 @@ QString EffectComposerModel::generateVertexShader(bool includeUniforms) } } - if (s_sourceCode.isEmpty()) { - // If source nodes doesn't contain any code, use default one - s_sourceCode << getDefaultRootVertexShader(); - } - if (removeTags) { s_sourceCode = removeTagsFromCode(s_sourceCode); s_root = removeTagsFromCode(s_root); @@ -1630,7 +1654,7 @@ QString EffectComposerModel::generateFragmentShader(bool includeUniforms) // split to root and main parts QString s_root; QString s_main; - QStringList s_sourceCode; + QStringList s_sourceCode = m_rootFragmentShader.split('\n'); for (const CompositionNode *n : std::as_const(m_nodes)) { if (!n->fragmentCode().isEmpty() && n->isEnabled()) { const QStringList fragmentCode = n->fragmentCode().split('\n'); @@ -1646,11 +1670,6 @@ QString EffectComposerModel::generateFragmentShader(bool includeUniforms) } } - if (s_sourceCode.isEmpty()) { - // If source nodes doesn't contain any code, use default one - s_sourceCode << getDefaultRootFragmentShader(); - } - if (removeTags) { s_sourceCode = removeTagsFromCode(s_sourceCode); s_root = removeTagsFromCode(s_root); diff --git a/src/plugins/effectcomposer/effectcomposermodel.h b/src/plugins/effectcomposer/effectcomposermodel.h index 9079e9bfd35..1d1389864ed 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.h +++ b/src/plugins/effectcomposer/effectcomposermodel.h @@ -93,6 +93,12 @@ public: QString vertexShader() const; void setVertexShader(const QString &newVertexShader); + void setRootFragmentShader(const QString &shader); + void resetRootFragmentShader(); + + void setRootVertexShader(const QString &shader); + void resetRootVertexShader(); + Q_INVOKABLE QString qmlComponentString() const; Q_INVOKABLE void updateQmlComponent(); @@ -172,8 +178,6 @@ private: int getTagIndex(const QStringList &code, const QString &tag); QString processVertexRootLine(const QString &line); QString processFragmentRootLine(const QString &line); - QStringList getDefaultRootVertexShader(); - QStringList getDefaultRootFragmentShader(); QStringList removeTagsFromCode(const QStringList &codeLines); QString removeTagsFromCode(const QString &code); QString getCustomShaderVaryings(bool outState); @@ -212,8 +216,8 @@ private: QStringList m_shaderVaryingVariables; QString m_fragmentShader; QString m_vertexShader; - QStringList m_defaultRootVertexShader; - QStringList m_defaultRootFragmentShader; + QString m_rootVertexShader; + QString m_rootFragmentShader; // Temp files to store shaders sources and binary data QTemporaryDir m_shaderDir; QString m_fragmentSourceFilename; From 5285ff2bc95afab2f9af12efd5c2c8d408e42cec Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Thu, 17 Oct 2024 17:54:53 +0300 Subject: [PATCH 40/44] EffectComposer: Use default shaders if they don't exist in QEP file * If a shader does not exist in QEP file, default shader will be used * If a user clears the shader code, an empty array would be inserted into the QEP file as the shader. This prevents using default shaders when the user clears the code deliberately. * QQEM effect files are not supported * `tool` property is added to the root of QEP Fixes: QDS-13857 Change-Id: I85bf6cdd9fe318afbc4c2e943b2d4faaccedbdeb Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../effectcomposer/effectcomposermodel.cpp | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/plugins/effectcomposer/effectcomposermodel.cpp b/src/plugins/effectcomposer/effectcomposermodel.cpp index 0d9fca2b526..33e72b145db 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.cpp +++ b/src/plugins/effectcomposer/effectcomposermodel.cpp @@ -26,6 +26,8 @@ #include #include +using namespace Qt::StringLiterals; + namespace EffectComposer { enum class FileType @@ -1003,6 +1005,7 @@ void EffectComposerModel::saveComposition(const QString &name) QJsonObject json; // File format version json.insert("version", 1); + json.insert("tool", "EffectComposer"); // Add nodes QJsonArray nodesArray; @@ -1012,17 +1015,16 @@ void EffectComposerModel::saveComposition(const QString &name) } auto toJsonArray = [](const QString &code) -> QJsonArray { + if (code.isEmpty()) + return {}; return QJsonArray::fromStringList(code.split('\n')); }; if (!nodesArray.isEmpty()) json.insert("nodes", nodesArray); - if (!m_rootVertexShader.isEmpty()) - json.insert("vertexCode", toJsonArray(m_rootVertexShader)); - - if (!m_rootFragmentShader.isEmpty()) - json.insert("fragmentCode", toJsonArray(m_rootFragmentShader)); + json.insert("vertexCode", toJsonArray(m_rootVertexShader)); + json.insert("fragmentCode", toJsonArray(m_rootFragmentShader)); QJsonObject rootJson; rootJson.insert("QEP", json); @@ -1117,6 +1119,18 @@ void EffectComposerModel::openComposition(const QString &path) QJsonObject json = rootJson["QEP"].toObject(); + const QString toolName = json.contains("tool") ? json["tool"].toString() + : json.contains("QQEM") ? "QQEM"_L1 + : ""_L1; + + if (!toolName.isEmpty() && toolName != "EffectComposer") { + const QString error + = tr("Error: '%1' effects are not compatible with 'Effect Composer'").arg(toolName); + qWarning() << error; + setEffectError(error); + return; + } + int version = -1; if (json.contains("version")) version = json["version"].toInt(-1); @@ -1142,8 +1156,15 @@ void EffectComposerModel::openComposition(const QString &path) return code; }; - setRootVertexShader(toCodeBlock(json["vertexCode"])); - setRootFragmentShader(toCodeBlock(json["fragmentCode"])); + if (json.contains("vertexCode")) + setRootVertexShader(toCodeBlock(json["vertexCode"])); + else + resetRootVertexShader(); + + if (json.contains("fragmentCode")) + setRootFragmentShader(toCodeBlock(json["fragmentCode"])); + else + resetRootFragmentShader(); if (json.contains("nodes") && json["nodes"].isArray()) { beginResetModel(); From 84ca3659858bfc76b033550205349b4d912a6ba1 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 17 Oct 2024 16:15:56 +0300 Subject: [PATCH 41/44] EffectComposer: Allow user to choose custom preview image The current preview image selection and any custom image path is stored in the .qep file on effect save. When a custom image outside of project is chosen, the image is imported into the project into the default image assets folder. Fixes: QDS-13438 Change-Id: If15049612bbca9a744a383c49716cb3648a52af3 Reviewed-by: Mats Honkamaa Reviewed-by: Mahmoud Badri Reviewed-by: Ali Kianian --- .../PreviewImagesComboBox.qml | 107 +++++++++----- .../effectcomposer/effectcomposermodel.cpp | 131 +++++++++++++++++- .../effectcomposer/effectcomposermodel.h | 12 ++ .../componentcore/modelnodeoperations.h | 2 +- 4 files changed, 210 insertions(+), 42 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/PreviewImagesComboBox.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/PreviewImagesComboBox.qml index 201fab9699d..e4280111892 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/PreviewImagesComboBox.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/PreviewImagesComboBox.qml @@ -22,12 +22,17 @@ StudioControls.ComboBox { required property Item mainRoot - property var images: ["images/preview0.png", - "images/preview1.png", - "images/preview2.png", - "images/preview3.png", - "images/preview4.png"] - property string selectedImage: images[0] + property var images: [Qt.url(""), + Qt.url("images/preview0.png"), + Qt.url("images/preview1.png"), + Qt.url("images/preview2.png"), + Qt.url("images/preview3.png"), + Qt.url("images/preview4.png")] + property url selectedImage: EffectComposerBackend.effectComposerModel.currentPreviewImage != Qt.url("") + ? EffectComposerBackend.effectComposerModel.currentPreviewImage + : images[1] + + Component.onCompleted: EffectComposerBackend.effectComposerModel.currentPreviewImage = images[1] readonly property int popupHeight: Math.min(800, col.height + 2) @@ -122,45 +127,77 @@ StudioControls.ComboBox { border.width: 1 focus: true - HelperWidgets.ScrollView { + Column { anchors.fill: parent - anchors.margins: 1 - clip: true - Column { - id: col + Item { + id: setCustomItem + width: parent.width + height: 40 - padding: 10 - spacing: 10 + HelperWidgets.Button { + anchors.fill: parent + anchors.margins: 2 + text: qsTr("Set Custom Image") + onClicked: { + EffectComposerBackend.effectComposerModel.chooseCustomPreviewImage() + root.popup.close() + } + } + } - Repeater { - model: root.images - Rectangle { - required property int index - required property var modelData + HelperWidgets.ScrollView { + width: parent.width - 2 + height: parent.height - setCustomItem.height - color: "transparent" - border.color: root.selectedImage === modelData ? StudioTheme.Values.themeInteraction - : "transparent" + clip: true - width: 200 - height: 200 + Column { + id: col - Image { - source: modelData - anchors.fill: parent - fillMode: Image.PreserveAspectFit - smooth: true - anchors.margins: 1 - } + padding: 10 + spacing: 10 - MouseArea { - anchors.fill: parent + Repeater { + model: root.images - onClicked: { - root.selectedImage = root.images[index] - root.popup.close() + Rectangle { + required property int index + required property var modelData + + color: "transparent" + border.color: root.selectedImage === modelData ? StudioTheme.Values.themeInteraction + : "transparent" + + width: 200 + height: 200 + visible: index > 0 + || EffectComposerBackend.effectComposerModel.customPreviewImage !== Qt.url("") + + Image { + source: index > 0 + ? parent.modelData + : EffectComposerBackend.effectComposerModel.customPreviewImage + anchors.fill: parent + fillMode: Image.PreserveAspectFit + smooth: true + anchors.margins: 1 + } + + MouseArea { + anchors.fill: parent + + onClicked: { + if (parent.index > 0) { + EffectComposerBackend.effectComposerModel.currentPreviewImage + = root.images[index] + } else { + EffectComposerBackend.effectComposerModel.currentPreviewImage + = EffectComposerBackend.effectComposerModel.customPreviewImage + } + root.popup.close() + } } } } diff --git a/src/plugins/effectcomposer/effectcomposermodel.cpp b/src/plugins/effectcomposer/effectcomposermodel.cpp index 33e72b145db..6f7a2612c98 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.cpp +++ b/src/plugins/effectcomposer/effectcomposermodel.cpp @@ -10,18 +10,24 @@ #include "syntaxhighlighterdata.h" #include "uniform.h" +#include +#include +#include +#include +#include + +#include + #include #include #include -#include #include #include -#include - #include +#include #include #include #include @@ -247,6 +253,47 @@ bool EffectComposerModel::nameExists(const QString &name) const return QFile::exists(path.arg(name)); } +void EffectComposerModel::chooseCustomPreviewImage() +{ + QTimer::singleShot(0, this, [&]() { + using Utils::FilePath; + static FilePath lastDir; + const QStringList &suffixes = QmlDesigner::Asset::supportedImageSuffixes(); + QmlDesigner::DesignDocument *document = QmlDesigner::QmlDesignerPlugin::instance()->currentDesignDocument(); + const FilePath currentDir = lastDir.isEmpty() ? document->fileName().parentDir() + : lastDir; + const QStringList fileNames = QFileDialog::getOpenFileNames(Core::ICore::dialogParent(), + tr("Select custom effect background image"), + currentDir.toFSPathString(), + tr("Image Files (%1)").arg(suffixes.join(" "))); + + if (!fileNames.isEmpty()) { + FilePath imageFile = FilePath::fromString(fileNames.first()); + lastDir = imageFile.absolutePath(); + if (imageFile.exists()) { + FilePath projDir = QmlDesigner::QmlDesignerPlugin::instance()->documentManager() + .currentProjectDirPath(); + if (!imageFile.isChildOf(projDir)) { + FilePath imagesDir = QmlDesigner::ModelNodeOperations::getImagesDefaultDirectory(); + FilePath targetFile = imagesDir.pathAppended(imageFile.fileName()); + if (!targetFile.exists()) + imageFile.copyFile(targetFile); + if (targetFile.exists()) + imageFile = targetFile; + } + + m_customPreviewImage = QUrl::fromLocalFile(imageFile.toFSPathString()); + m_currentPreviewImage = m_customPreviewImage; + + setHasUnsavedChanges(true); + + emit currentPreviewImageChanged(); + emit customPreviewImageChanged(); + } + } + }); +} + QString EffectComposerModel::fragmentShader() const { return m_fragmentShader; @@ -1000,6 +1047,9 @@ void EffectComposerModel::saveComposition(const QString &name) return; } + const Utils::FilePath compositionPath = Utils::FilePath::fromString(path); + const Utils::FilePath compositionDir = compositionPath.absolutePath(); + updateExtraMargin(); QJsonObject json; @@ -1007,6 +1057,17 @@ void EffectComposerModel::saveComposition(const QString &name) json.insert("version", 1); json.insert("tool", "EffectComposer"); + Utils::FilePath customPreviewPath = Utils::FilePath::fromUrl(m_customPreviewImage); + if (m_customPreviewImage.isLocalFile()) + customPreviewPath = customPreviewPath.relativePathFrom(compositionDir); + json.insert("customPreviewImage", customPreviewPath.toUrl().toString()); + + QUrl previewUrl = m_currentPreviewImage; + if (m_currentPreviewImage == m_customPreviewImage) + previewUrl = customPreviewPath.toUrl(); + + json.insert("previewImage", previewUrl.toString()); + // Add nodes QJsonArray nodesArray; for (const CompositionNode *node : std::as_const(m_nodes)) { @@ -1034,7 +1095,7 @@ void EffectComposerModel::saveComposition(const QString &name) saveFile.close(); setCurrentComposition(name); - setCompositionPath(Utils::FilePath::fromString(path)); + setCompositionPath(compositionPath); saveResources(name); setHasUnsavedChanges(false); @@ -1083,10 +1144,11 @@ void EffectComposerModel::openComposition(const QString &path) { clear(true); - const QString effectName = QFileInfo(path).baseName(); + Utils::FilePath effectPath = Utils::FilePath::fromString(path); + const QString effectName = effectPath.baseName(); setCurrentComposition(effectName); - setCompositionPath(Utils::FilePath::fromString(path)); + setCompositionPath(effectPath); QFile compFile(path); if (!compFile.open(QIODevice::ReadOnly)) { @@ -1166,6 +1228,39 @@ void EffectComposerModel::openComposition(const QString &path) else resetRootFragmentShader(); + m_currentPreviewImage.clear(); + if (json.contains("previewImage")) { + const QString imageStr = json["previewImage"].toString(); + if (!imageStr.isEmpty()) { + const QUrl imageUrl{imageStr}; + Utils::FilePath imagePath = Utils::FilePath::fromUrl(imageUrl); + if (imageStr.startsWith("images/preview")) { // built-in preview image + m_currentPreviewImage = imageUrl; + } else if (imagePath.isAbsolutePath()) { + if (imagePath.exists()) + m_currentPreviewImage = imageUrl; + } else { + imagePath = effectPath.absolutePath().resolvePath(imagePath); + if (imagePath.exists()) + m_currentPreviewImage = imagePath.toUrl(); + } + } + } + + m_customPreviewImage.clear(); + if (json.contains("customPreviewImage")) { + QUrl imageUrl{json["customPreviewImage"].toString()}; + Utils::FilePath imagePath = Utils::FilePath::fromUrl(imageUrl); + if (imagePath.isAbsolutePath()) { + if (imagePath.exists()) + m_customPreviewImage = imageUrl; + } else { + imagePath = effectPath.absolutePath().resolvePath(imagePath); + if (imagePath.exists()) + m_customPreviewImage = imagePath.toUrl(); + } + } + if (json.contains("nodes") && json["nodes"].isArray()) { beginResetModel(); QHash refCounts; @@ -1194,6 +1289,8 @@ void EffectComposerModel::openComposition(const QString &path) setHasUnsavedChanges(false); emit nodesChanged(); + emit currentPreviewImageChanged(); + emit customPreviewImageChanged(); } void EffectComposerModel::saveResources(const QString &name) @@ -2151,6 +2248,28 @@ void EffectComposerModel::setCurrentComposition(const QString &newCurrentComposi m_shadersCodeEditor.reset(); } +QUrl EffectComposerModel::customPreviewImage() const +{ + return m_customPreviewImage; +} + +QUrl EffectComposerModel::currentPreviewImage() const +{ + return m_currentPreviewImage; +} + +void EffectComposerModel::setCurrentPreviewImage(const QUrl &path) +{ + if (m_currentPreviewImage == path) + return; + + if (!m_nodes.isEmpty()) + setHasUnsavedChanges(true); + + m_currentPreviewImage = path; + emit currentPreviewImageChanged(); +} + Utils::FilePath EffectComposerModel::compositionPath() const { return m_compositionPath; diff --git a/src/plugins/effectcomposer/effectcomposermodel.h b/src/plugins/effectcomposer/effectcomposermodel.h index 1d1389864ed..09aeb724532 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.h +++ b/src/plugins/effectcomposer/effectcomposermodel.h @@ -15,6 +15,7 @@ #include #include #include +#include namespace ProjectExplorer { class Target; @@ -53,6 +54,8 @@ class EffectComposerModel : public QAbstractListModel Q_PROPERTY(bool isEnabled READ isEnabled WRITE setIsEnabled NOTIFY isEnabledChanged) Q_PROPERTY(bool hasValidTarget READ hasValidTarget WRITE setHasValidTarget NOTIFY hasValidTargetChanged) Q_PROPERTY(QString currentComposition READ currentComposition WRITE setCurrentComposition NOTIFY currentCompositionChanged) + Q_PROPERTY(QUrl currentPreviewImage READ currentPreviewImage WRITE setCurrentPreviewImage NOTIFY currentPreviewImageChanged) + Q_PROPERTY(QUrl customPreviewImage READ customPreviewImage NOTIFY customPreviewImageChanged) public: EffectComposerModel(QObject *parent = nullptr); @@ -77,6 +80,7 @@ public: Q_INVOKABLE void assignToSelected(); Q_INVOKABLE QString getUniqueEffectName() const; Q_INVOKABLE bool nameExists(const QString &name) const; + Q_INVOKABLE void chooseCustomPreviewImage(); bool shadersUpToDate() const; void setShadersUpToDate(bool newShadersUpToDate); @@ -116,6 +120,10 @@ public: QString currentComposition() const; void setCurrentComposition(const QString &newCurrentComposition); + QUrl customPreviewImage() const; + QUrl currentPreviewImage() const; + void setCurrentPreviewImage(const QUrl &path); + Utils::FilePath compositionPath() const; void setCompositionPath(const Utils::FilePath &newCompositionPath); @@ -140,6 +148,8 @@ signals: void hasUnsavedChangesChanged(); void assignToSelectedTriggered(const QString &effectPath); void removePropertiesFromScene(QSet props, const QString &typeName); + void currentPreviewImageChanged(); + void customPreviewImageChanged(); private: enum Roles { @@ -242,6 +252,8 @@ private: QString m_effectTypePrefix; Utils::FilePath m_compositionPath; Utils::UniqueObjectLatePtr m_shadersCodeEditor; + QUrl m_currentPreviewImage; + QUrl m_customPreviewImage; const QRegularExpression m_spaceReg = QRegularExpression("\\s+"); }; diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h index 8b3d411c05f..4ae7b45c02b 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -137,7 +137,7 @@ bool useLayerEffect(); bool validateEffect(const QString &effectPath); bool isEffectComposerActivated(); -Utils::FilePath getImagesDefaultDirectory(); +QMLDESIGNERCOMPONENTS_EXPORT Utils::FilePath getImagesDefaultDirectory(); //Item Library and Assets related drop operations QMLDESIGNERCOMPONENTS_EXPORT ModelNode handleItemLibraryEffectDrop(const QString &effectPath, From bb047b04bdde8428e06c26bd295b17f7572cc5d9 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 21 Oct 2024 09:13:29 +0200 Subject: [PATCH 42/44] UnitTests: There is no data directory to copy Change-Id: I3dbbcf94e03c21d1d075f726eee87cdd0cf41cbe Reviewed-by: Marcus Tillmanns Reviewed-by: Tim Jenssen --- tests/unit/tests/unittests/sourcepathstorage/CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/unit/tests/unittests/sourcepathstorage/CMakeLists.txt b/tests/unit/tests/unittests/sourcepathstorage/CMakeLists.txt index 6a2ec39146c..9325ae72324 100644 --- a/tests/unit/tests/unittests/sourcepathstorage/CMakeLists.txt +++ b/tests/unit/tests/unittests/sourcepathstorage/CMakeLists.txt @@ -7,5 +7,3 @@ extend_qtc_test(unittest sourcepathview-test.cpp storagecache-test.cpp ) - -unittest_copy_data_folder() From 52679bbc21c175e2356f3c32572a7e9d4bb3c8dc Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 21 Oct 2024 13:59:38 +0300 Subject: [PATCH 43/44] EffectComposer: Adjust "Set Custom Image" button positioning Change-Id: I9da9cc267d7bf6a32c62e1b6e36797c0e4e6096a Reviewed-by: Mahmoud Badri --- .../effectComposerQmlSources/PreviewImagesComboBox.qml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/PreviewImagesComboBox.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/PreviewImagesComboBox.qml index e4280111892..b75a04001e8 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/PreviewImagesComboBox.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/PreviewImagesComboBox.qml @@ -133,11 +133,14 @@ StudioControls.ComboBox { Item { id: setCustomItem width: parent.width - height: 40 + height: 50 HelperWidgets.Button { anchors.fill: parent - anchors.margins: 2 + anchors.bottomMargin: 2 + anchors.topMargin: col.padding + anchors.leftMargin: col.padding + anchors.rightMargin: col.padding text: qsTr("Set Custom Image") onClicked: { EffectComposerBackend.effectComposerModel.chooseCustomPreviewImage() From 81f846ce1c83aa81dd00b1d8c85ca5508f0b5c78 Mon Sep 17 00:00:00 2001 From: Marco Bubke Date: Mon, 21 Oct 2024 18:24:07 +0200 Subject: [PATCH 44/44] QmlDesigner: Remove rewriter usage The rewriter is only exported for internal purposes. Change-Id: Idf2d2851cae53786dfde6bd1a28a5547d7c12b3e Reviewed-by: Mahmoud Badri --- .../effectcomposer/effectcomposercontextobject.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugins/effectcomposer/effectcomposercontextobject.cpp b/src/plugins/effectcomposer/effectcomposercontextobject.cpp index 95ebe7a3670..68053055b30 100644 --- a/src/plugins/effectcomposer/effectcomposercontextobject.cpp +++ b/src/plugins/effectcomposer/effectcomposercontextobject.cpp @@ -168,11 +168,11 @@ int EffectComposerContextObject::devicePixelRatio() QStringList EffectComposerContextObject::allStatesForId(const QString &id) { - if (m_model && m_model->rewriterView()) { - const QmlDesigner::QmlObjectNode node = m_model->rewriterView()->modelNodeForId(id); - if (node.isValid()) - return node.allStateNames(); - } + if (m_model) { + const QmlDesigner::QmlObjectNode node = m_model->modelNodeForId(id); + if (node.isValid()) + return node.allStateNames(); + } return {}; }