From c3f9d43acaa753149d17bed90114a266158ff683 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Thu, 16 Nov 2023 18:34:39 +0100 Subject: [PATCH 001/101] QmlDesigner: Fix PopupDialog popup location * Restrict popup location to single screen given by global position * Reintroduce PopupDialog title bar drag * Fix global popup show on linux Change-Id: If1923151cb9d0ec4286f27aeae2baa292e017eb5 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Thomas Hartmann --- .../connectionseditor/ConnectionsDialog.qml | 2 +- .../imports/StudioControls/PopupDialog.qml | 45 ++++++++++++++----- .../qmldesignerbase/utils/windowmanager.cpp | 11 +++++ .../qmldesignerbase/utils/windowmanager.h | 1 + 4 files changed, 46 insertions(+), 13 deletions(-) diff --git a/share/qtcreator/qmldesigner/connectionseditor/ConnectionsDialog.qml b/share/qtcreator/qmldesigner/connectionseditor/ConnectionsDialog.qml index 85a847ba5e0..965f31d21ab 100644 --- a/share/qtcreator/qmldesigner/connectionseditor/ConnectionsDialog.qml +++ b/share/qtcreator/qmldesigner/connectionseditor/ConnectionsDialog.qml @@ -49,7 +49,7 @@ StudioControls.PopupDialog { root.close() } function onPopupShouldOpen() { - root.showGlobal() + Qt.callLater(root.showGlobal) } } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml index ae821804a5d..1f62ba81818 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml @@ -33,9 +33,8 @@ QtObject { signal closing(close: var) - function showGlobal() - { - var pos = WindowManager.globalCursorPosition(); + function showGlobal() { + var pos = WindowManager.globalCursorPosition() root.__itemGlobal = Qt.rect(pos.x, pos.y, 300, 20) root.chevronVisible = false root.layout() @@ -57,11 +56,8 @@ QtObject { } function layout() { - // Setup - var screen = Qt.rect(0, //Screen.virtualX, // TODO - 0, //Screen.virtualY, // TODO - Screen.desktopAvailableWidth, - Screen.desktopAvailableHeight) + let position = Qt.point(root.__itemGlobal.x, root.__itemGlobal.y) + var screen = WindowManager.getScreenGeometry(position) // Collect region information let edges = window.getRegions(screen, root.__itemGlobal) @@ -165,9 +161,18 @@ QtObject { var targetCenter = Qt.point(target.x + (target.width * 0.5), target.y + (target.height * 0.5)) + // Just as a reminder why calculating custom right and bottom: + // > Note that for historical reasons this function returns top() + height() - 1; + // > use y() + height() to retrieve the true y-coordinate. + let sourceRight = source.x + source.width + let sourceBottom = source.y + source.height + // TOP let topAnchor = Qt.point(targetCenter.x, target.y) - let topRegion = Qt.rect(source.x, source.y, source.width, Math.max(0, topAnchor.y)) + let topRegion = Qt.rect(source.x, + source.y, + source.width, + (topAnchor.y < source.top) ? 0 : Math.abs(topAnchor.y - source.top)) edges[Qt.TopEdge] = { anchor: topAnchor, @@ -180,7 +185,7 @@ QtObject { let rightAnchor = Qt.point(target.x + target.width, targetCenter.y) let rightRegion = Qt.rect(rightAnchor.x, source.y, - Math.max(0, source.width - rightAnchor.x), + (rightAnchor.x > sourceRight) ? 0 : Math.abs(sourceRight - rightAnchor.x), source.height) edges[Qt.RightEdge] = { @@ -195,7 +200,7 @@ QtObject { let bottomRegion = Qt.rect(source.x, bottomAnchor.y, source.width, - Math.max(0, source.height - bottomAnchor.y)) + (bottomAnchor.y > sourceBottom) ? 0 : Math.abs(sourceBottom - bottomAnchor.y)) edges[Qt.BottomEdge] = { anchor: bottomAnchor, @@ -206,7 +211,10 @@ QtObject { // LEFT let leftAnchor = Qt.point(target.x, targetCenter.y) - let leftRegion = Qt.rect(source.x, source.y, Math.max(0, leftAnchor.x), source.height) + let leftRegion = Qt.rect(source.x, + source.y, + (leftAnchor.x < source.left) ? 0 : Math.abs(leftAnchor.x - source.left), + source.height) edges[Qt.LeftEdge] = { anchor: leftAnchor, @@ -392,6 +400,19 @@ QtObject { width: parent.width height: StudioTheme.Values.titleBarHeight + DragHandler { + id: dragHandler + + target: null + grabPermissions: PointerHandler.CanTakeOverFromAnything + onActiveChanged: { + if (dragHandler.active) + window.startSystemMove() // QTBUG-102488 + + root.chevronVisible = false + } + } + Row { id: row anchors.fill: parent diff --git a/src/plugins/qmldesignerbase/utils/windowmanager.cpp b/src/plugins/qmldesignerbase/utils/windowmanager.cpp index c52d5d469a6..146535ceac1 100644 --- a/src/plugins/qmldesignerbase/utils/windowmanager.cpp +++ b/src/plugins/qmldesignerbase/utils/windowmanager.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include namespace QmlDesignerBase { @@ -43,4 +44,14 @@ QPoint WindowManager::globalCursorPosition() return QCursor::pos(); } +QRect WindowManager::getScreenGeometry(QPoint point) +{ + QScreen *screen = QGuiApplication::screenAt(point); + + if (!screen) + return {}; + + return screen->geometry(); +} + } // namespace QmlDesignerBase diff --git a/src/plugins/qmldesignerbase/utils/windowmanager.h b/src/plugins/qmldesignerbase/utils/windowmanager.h index 3d8e692c1aa..87a0b701463 100644 --- a/src/plugins/qmldesignerbase/utils/windowmanager.h +++ b/src/plugins/qmldesignerbase/utils/windowmanager.h @@ -25,6 +25,7 @@ public: static void registerDeclarativeType(); Q_INVOKABLE QPoint globalCursorPosition(); + Q_INVOKABLE QRect getScreenGeometry(QPoint point); signals: void focusWindowChanged(QWindow *window); From 901b356ea5982a522a3ea3b059c3ea11fd4d16ef Mon Sep 17 00:00:00 2001 From: Amr Essam Date: Fri, 17 Nov 2023 11:33:50 +0200 Subject: [PATCH 002/101] EffectMaker: Fix incorrect QML parsed values Task-number: QDS-11296 Change-Id: I97d725271e61d4e14db23382ff7398353ced845d Reviewed-by: Mahmoud Badri Reviewed-by: Miikka Heikkinen --- src/plugins/effectmakernew/effectmakermodel.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index 2c9dd051638..5852f69bd45 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -682,7 +682,7 @@ void EffectMakerModel::exportResources(const QString &name) if (line.startsWith("vertexShader")) { QString vsLine = " vertexShader: '" + vsFilename + "'"; qmlStringList[i] = vsLine; - } else if (line.startsWith("fragmentShader")) { + } else if (line.startsWith("fragmentShader")) { QString fsLine = " fragmentShader: '" + fsFilename + "'"; qmlStringList[i] = fsLine; } @@ -737,16 +737,18 @@ QString EffectMakerModel::valueAsString(const Uniform &uniform) return QString::number(uniform.value().toDouble()); } else if (uniform.type() == Uniform::Type::Vec2) { QVector2D v2 = uniform.value().value(); - return QString("Qt.point(%1, %2)").arg(v2.x(), v2.y()); + return QString("Qt.point(%1, %2)").arg(v2.x()).arg(v2.y()); } else if (uniform.type() == Uniform::Type::Vec3) { QVector3D v3 = uniform.value().value(); - return QString("Qt.vector3d(%1, %2, %3)").arg(v3.x(), v3.y(), v3.z()); + return QString("Qt.vector3d(%1, %2, %3)").arg(v3.x()).arg(v3.y()).arg(v3.z()); } else if (uniform.type() == Uniform::Type::Vec4) { QVector4D v4 = uniform.value().value(); - return QString("Qt.vector4d(%1, %2, %3, %4)").arg(v4.x(), v4.y(), v4.z(), v4.w()); + return QString("Qt.vector4d(%1, %2, %3, %4)").arg(v4.x()).arg(v4.y()).arg(v4.z()).arg(v4.w()); } else if (uniform.type() == Uniform::Type::Sampler) { return getImageElementName(uniform); - } else if (uniform.type() == Uniform::Type::Define || uniform.type() == Uniform::Type::Color) { + } else if (uniform.type() == Uniform::Type::Color) { + return QString("\"%1\"").arg(uniform.value().toString()); + } else if (uniform.type() == Uniform::Type::Define) { return uniform.value().toString(); } else { qWarning() << QString("Unhandled const variable type: %1").arg(int(uniform.type())).toLatin1(); From 8932f9d4626556cd788937e9e2c4aaae4df31e24 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 17 Nov 2023 10:27:18 +0100 Subject: [PATCH 003/101] QmlDesigner: Add try/catch block There seem to be rare cases in which this fails. Change-Id: I229a9a72394ec25dca1a9cdae0b51aa36291be94 Reviewed-by: Tim Jenssen --- .../components/itemlibrary/itemlibrarywidget.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp index 7703f352b0e..b710a8226f2 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp @@ -251,7 +251,11 @@ void ItemLibraryWidget::handleAddImport(int index) imports.append(dependencyImport); } imports.append(import); - model->changeImports(imports, {}); + try { + model->changeImports(imports, {}); + } catch (const Exception &e) { + e.showException(); + } switchToComponentsView(); updateSearch(); From 18461884e0c86ce6214561a5223220de44485513 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Fri, 17 Nov 2023 12:33:03 +0200 Subject: [PATCH 004/101] QmlDesigner: Fix the bug for overriding Final property Task-number: QDS-11301 Change-Id: I11a9941a344f7091405bd8e4cd5de10bf66c6c2e Reviewed-by: Thomas Hartmann --- .../collectionEditorQmlSource/CollectionItem.qml | 6 +++--- .../collectionEditorQmlSource/ModelSourceItem.qml | 4 ++-- .../imports/StudioControls/SectionLabel.qml | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionItem.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionItem.qml index 589a1433965..23d0c7af93b 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionItem.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionItem.qml @@ -54,16 +54,16 @@ Item { Text { id: moveTool - property StudioTheme.ControlStyle style: StudioTheme.Values.viewBarButtonStyle + property StudioTheme.ControlStyle textStyle: StudioTheme.Values.viewBarButtonStyle - Layout.preferredWidth: moveTool.style.squareControlSize.width + Layout.preferredWidth: moveTool.textStyle.squareControlSize.width Layout.preferredHeight: nameHolder.height Layout.leftMargin: 12 Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter text: StudioTheme.Constants.dragmarks font.family: StudioTheme.Constants.iconFont.family - font.pixelSize: moveTool.style.baseIconFontSize + font.pixelSize: moveTool.textStyle.baseIconFontSize color: root.textColor horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml index 365fc930c5f..d04181fd590 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml @@ -74,9 +74,9 @@ Item { Text { id: expandButton - property StudioTheme.ControlStyle style: StudioTheme.Values.viewBarButtonStyle + property StudioTheme.ControlStyle textStyle: StudioTheme.Values.viewBarButtonStyle - Layout.preferredWidth: expandButton.style.squareControlSize.width + Layout.preferredWidth: expandButton.textStyle.squareControlSize.width Layout.preferredHeight: nameHolder.height Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLabel.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLabel.qml index b8586d96213..4e52000e986 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLabel.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/SectionLabel.qml @@ -9,11 +9,11 @@ import StudioTheme 1.0 as StudioTheme T.Label { id: control - property StudioTheme.ControlStyle style: StudioTheme.Values.controlStyle + property StudioTheme.ControlStyle controlStyle: StudioTheme.Values.controlStyle width: Math.max(Math.min(240, parent.width - 220), 90) - color: control.style.text.idle - font.pixelSize: control.style.baseFontSize + color: control.controlStyle.text.idle + font.pixelSize: control.controlStyle.baseFontSize elide: Text.ElideRight Layout.preferredWidth: width From 32e9f3cfd4b67e2988c8e478c1bc2551440d8d36 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 17 Nov 2023 15:26:10 +0100 Subject: [PATCH 005/101] QmlDesigner: Rename boolean to bool boolean is not a QML type and Qt 6.5.4 does check this. Change-Id: I09055cfecf8f91766c8c4f2806150fefa7301741 Reviewed-by: Tim Jenssen --- .../imports/StudioControls/PopupDialog.qml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml index 1f62ba81818..cbeb113701e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml @@ -135,7 +135,7 @@ QtObject { return Qt.LeftEdge // Default } - function contains(a: rect, b: rect): boolean { + function contains(a: rect, b: rect): bool { let halfSizeA = Qt.size(a.width * 0.5, a.height * 0.5) let halfSizeB = Qt.size(b.width * 0.5, b.height * 0.5) From 9a8fa56a669d4c34076b820a8a5aacc2d5e3b57b Mon Sep 17 00:00:00 2001 From: Aleksei German Date: Wed, 15 Nov 2023 18:59:51 +0100 Subject: [PATCH 006/101] QmlDesigner: Fix for Style ComboBox Task-number: QDS-11257 Change-Id: Ie50b9f585914c8f6345d61a8e6c5347998b3fc63 Reviewed-by: Aleksei German Reviewed-by: Qt CI Patch Build Bot --- src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp index 5a9431677da..37f512edb93 100644 --- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp @@ -513,7 +513,7 @@ void ToolBarBackend::setCurrentStyle(int index) const QString qmlFile = view->model()->fileUrl().toLocalFile(); - ChangeStyleWidgetAction::changeCurrentStyle(item.styleName, qmlFile); + ChangeStyleWidgetAction::changeCurrentStyle(item.displayName, qmlFile); view->resetPuppet(); } From c09635e8501b9e9422080cb180a0f146b4d2b66d Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 17 Nov 2023 16:57:40 +0100 Subject: [PATCH 007/101] QmlDesigner: Use QML/Designer/UseExperimentalFeatures44 for ModelView Change-Id: I4de7c2c0b64cbdda65d5258168b72fe13f6dbd07 Reviewed-by: Thomas Hartmann --- .../components/componentcore/viewmanager.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp index 9ba4bfd26b1..ade7a521a89 100644 --- a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp @@ -29,6 +29,8 @@ #include #include +#include + #include #include @@ -39,6 +41,14 @@ namespace QmlDesigner { +static bool enableModelEditor() +{ + Utils::QtcSettings *settings = Core::ICore::settings(); + const Utils::Key enableModelManagerKey = "QML/Designer/UseExperimentalFeatures44"; + + return settings->value(enableModelManagerKey, false).toBool(); +} + static Q_LOGGING_CATEGORY(viewBenchmark, "qtc.viewmanager.attach", QtWarningMsg) class ViewManagerData @@ -203,8 +213,10 @@ QList ViewManager::standardViews() const &d->materialBrowserView, &d->textureEditorView, &d->statesEditorView, - &d->designerActionManagerView, - &d->collectionView}; + &d->designerActionManagerView}; + + if (enableModelEditor()) + list.append(&d->collectionView); if (QmlDesignerPlugin::instance() ->settings() @@ -386,7 +398,8 @@ QList ViewManager::widgetInfos() const widgetInfoList.append(d->materialBrowserView.widgetInfo()); widgetInfoList.append(d->textureEditorView.widgetInfo()); widgetInfoList.append(d->statesEditorView.widgetInfo()); - widgetInfoList.append(d->collectionView.widgetInfo()); + if (enableModelEditor()) + widgetInfoList.append(d->collectionView.widgetInfo()); #ifdef CHECK_LICENSE if (checkLicense() == FoundLicense::enterprise) From 48c1d9466ce641d8a98edc7d70fb1cbda06c5e86 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Fri, 17 Nov 2023 17:05:52 +0100 Subject: [PATCH 008/101] QmlDesigner: Use QML/Designer/UseExperimentalFeatures44 for EffectMaker Change-Id: I233d1b39cc336beb18a837cbba26605528876e63 Reviewed-by: Amr Elsayed Reviewed-by: Mahmoud Badri --- .../effectmakernew/effectmakerplugin.cpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/plugins/effectmakernew/effectmakerplugin.cpp b/src/plugins/effectmakernew/effectmakerplugin.cpp index 3890d3c9d65..c126cc34012 100644 --- a/src/plugins/effectmakernew/effectmakerplugin.cpp +++ b/src/plugins/effectmakernew/effectmakerplugin.cpp @@ -27,15 +27,26 @@ namespace EffectMaker { +static bool enableEffectMaker() +{ + Utils::QtcSettings *settings = Core::ICore::settings(); + const Utils::Key enableModelManagerKey = "QML/Designer/UseExperimentalFeatures44"; + + return settings->value(enableModelManagerKey, false).toBool(); +} + bool EffectMakerPlugin::delayedInitialize() { if (m_delayedInitialized) return true; - auto *designerPlugin = QmlDesigner::QmlDesignerPlugin::instance(); - auto &viewManager = designerPlugin->viewManager(); - viewManager.registerView(std::make_unique( - QmlDesigner::QmlDesignerPlugin::externalDependenciesForPluginInitializationOnly())); + if (enableEffectMaker()) { + auto *designerPlugin = QmlDesigner::QmlDesignerPlugin::instance(); + auto &viewManager = designerPlugin->viewManager(); + + viewManager.registerView(std::make_unique( + QmlDesigner::QmlDesignerPlugin::externalDependenciesForPluginInitializationOnly())); + } m_delayedInitialized = true; From 84cf414a1af58281ceaeda9f2d9534e5c418d399 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Fri, 17 Nov 2023 16:16:20 +0100 Subject: [PATCH 009/101] QmlDesigner: Fix color editor details model Task-number: QDS-11268 Change-Id: I043c5a4144778d29c54df9e448a86c855270f427 Reviewed-by: Brook Cronin Reviewed-by: Thomas Hartmann --- .../imports/HelperWidgets/ColorEditorPopup.qml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditorPopup.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditorPopup.qml index c5e0ef63ee0..29c506e8c52 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditorPopup.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditorPopup.qml @@ -552,9 +552,9 @@ Column { textRole: "text" valueRole: "value" model: [ - { value: ColorPicker.Mode.HSVA, text: "HSVA" }, - { value: ColorPicker.Mode.RGBA, text: "RGBA" }, - { value: ColorPicker.Mode.HSLA, text: "HSLA" } + { value: StudioControls.ColorPicker.Mode.HSVA, text: "HSVA" }, + { value: StudioControls.ColorPicker.Mode.RGBA, text: "RGBA" }, + { value: StudioControls.ColorPicker.Mode.HSLA, text: "HSLA" } ] onActivated: colorPicker.mode = colorMode.currentValue @@ -597,7 +597,7 @@ Column { Row { id: rgbaRow - visible: colorPicker.mode === ColorPicker.Mode.RGBA + visible: colorPicker.mode === StudioControls.ColorPicker.Mode.RGBA spacing: StudioTheme.Values.controlGap DoubleSpinBox { @@ -683,7 +683,7 @@ Column { Row { id: hslaRow - visible: colorPicker.mode === ColorPicker.Mode.HSLA + visible: colorPicker.mode === StudioControls.ColorPicker.Mode.HSLA spacing: StudioTheme.Values.controlGap DoubleSpinBox { @@ -749,7 +749,7 @@ Column { Row { id: hsvaRow - visible: colorPicker.mode === ColorPicker.Mode.HSVA + visible: colorPicker.mode === StudioControls.ColorPicker.Mode.HSVA spacing: StudioTheme.Values.controlGap DoubleSpinBox { From 5316586a0af327568f796d4b29fd44b35da25c80 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Fri, 17 Nov 2023 14:48:35 +0100 Subject: [PATCH 010/101] QmlDesigner: Fix popover position * Remove chevron Change-Id: Icd27f26e75c09561b2ec5fb8cf1f80dad7dd5b86 Reviewed-by: Thomas Hartmann Reviewed-by: Brook Cronin --- .../imports/HelperWidgets/ColorEditor.qml | 1 - .../imports/StudioControls/PopupDialog.qml | 46 +++++++++++-------- 2 files changed, 28 insertions(+), 19 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml index 4ff7c30c2bf..48748345e63 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml @@ -184,7 +184,6 @@ SecondColumnLayout { property string gradientPropertyName width: 260 - maximumHeight: Screen.desktopAvailableHeight * 0.7 function commitToGradient() { if (!loader.active) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml index cbeb113701e..4bfc0614b4b 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml @@ -25,9 +25,10 @@ QtObject { property alias flags: window.flags property alias visible: window.visible + property int anchorGap: 10 property int edge: Qt.LeftEdge property int actualEdge: root.edge - property alias chevronVisible: chevron.visible + //property alias chevronVisible: chevron.visible property rect __itemGlobal: Qt.rect(0, 0, 100, 100) @@ -36,7 +37,7 @@ QtObject { function showGlobal() { var pos = WindowManager.globalCursorPosition() root.__itemGlobal = Qt.rect(pos.x, pos.y, 300, 20) - root.chevronVisible = false + //root.chevronVisible = false root.layout() window.show() window.raise() @@ -45,7 +46,7 @@ QtObject { function show(target: Item) { var originGlobal = target.mapToGlobal(0, 0) root.__itemGlobal = Qt.rect(originGlobal.x, originGlobal.y, target.width, target.height) - root.chevronVisible = true + //root.chevronVisible = true root.layout() window.show() window.raise() @@ -74,8 +75,8 @@ QtObject { let anchor = edges[edge].anchor let popoverRect = window.popoverGeometry(edge, anchor, edges[edge].region) - if (chevron.visible) - chevron.layout(edge, popoverRect, anchor) + //if (chevron.visible) + // chevron.layout(edge, popoverRect, anchor) window.x = popoverRect.x window.y = popoverRect.y @@ -84,7 +85,7 @@ QtObject { property Window window: Window { id: window - property int margin: 20 + property int margin: 0 //20 width: root.width + (2 * window.margin) height: root.height + (2 * window.margin) @@ -168,7 +169,7 @@ QtObject { let sourceBottom = source.y + source.height // TOP - let topAnchor = Qt.point(targetCenter.x, target.y) + let topAnchor = Qt.point(targetCenter.x, target.y - root.anchorGap) let topRegion = Qt.rect(source.x, source.y, source.width, @@ -182,7 +183,7 @@ QtObject { } // RIGHT - let rightAnchor = Qt.point(target.x + target.width, targetCenter.y) + let rightAnchor = Qt.point(target.x + target.width + root.anchorGap, targetCenter.y) let rightRegion = Qt.rect(rightAnchor.x, source.y, (rightAnchor.x > sourceRight) ? 0 : Math.abs(sourceRight - rightAnchor.x), @@ -196,7 +197,7 @@ QtObject { } // BOTTOM - let bottomAnchor = Qt.point(targetCenter.x, target.y + target.height) + let bottomAnchor = Qt.point(targetCenter.x, target.y + target.height + root.anchorGap) let bottomRegion = Qt.rect(source.x, bottomAnchor.y, source.width, @@ -210,7 +211,7 @@ QtObject { } // LEFT - let leftAnchor = Qt.point(target.x, targetCenter.y) + let leftAnchor = Qt.point(target.x - root.anchorGap, targetCenter.y) let leftRegion = Qt.rect(source.x, source.y, (leftAnchor.x < source.left) ? 0 : Math.abs(leftAnchor.x - source.left), @@ -229,7 +230,9 @@ QtObject { function popoverGeometry(edge: int, anchor: point, region: rect) { if (edge === Qt.TopEdge) { let height = Math.min(window.height, region.height) - return Qt.rect(Math.max(0, Math.min(anchor.x - (window.width * 0.5), region.width - window.width)), + return Qt.rect(Math.max(region.x, + Math.min(anchor.x - (window.width * 0.5), + region.x + region.width - window.width)), anchor.y - height, Math.min(window.width, region.width), height) @@ -238,14 +241,18 @@ QtObject { if (edge === Qt.RightEdge) { let width = Math.min(window.width, region.width) return Qt.rect(anchor.x, - Math.max(0, Math.min(anchor.y - (window.height * 0.5), region.height - window.height)), + Math.max(region.y, + Math.min(anchor.y - (window.height * 0.5), + region.y + region.height - window.height)), width, Math.min(window.height, region.height)) } if (edge === Qt.BottomEdge) { let height = Math.min(window.height, region.height) - return Qt.rect(Math.max(0, Math.min(anchor.x - (window.width * 0.5), region.width - window.width)), + return Qt.rect(Math.max(region.x, + Math.min(anchor.x - (window.width * 0.5), + region.x + region.width - window.width)), anchor.y, Math.min(window.width, region.width), height) @@ -254,7 +261,9 @@ QtObject { if (edge === Qt.LeftEdge) { let width = Math.min(window.width, region.width) return Qt.rect(anchor.x - width, - Math.max(0, Math.min(anchor.y - (window.height * 0.5), region.height - window.height)), + Math.max(region.y, + Math.min(anchor.y - (window.height * 0.5), + region.y + region.height - window.height)), width, Math.min(window.height, region.height)) } @@ -312,7 +321,10 @@ QtObject { } } } - +/* + // The chevron will be reactivated when we fixed all the issues that where found during testing. + // * Potential Qt bug: black background instead of transparent border due to GPU selection on Windows + // * Ghost chevron on macOS after dragging the window Shape { id: chevron @@ -389,7 +401,7 @@ QtObject { PathLine { id: end; x: 0; y: 0 } } } - +*/ Column { id: column anchors.fill: parent @@ -408,8 +420,6 @@ QtObject { onActiveChanged: { if (dragHandler.active) window.startSystemMove() // QTBUG-102488 - - root.chevronVisible = false } } From a2b195580b5577e24c7ec5c07640e7ea2639ad61 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 17 Nov 2023 13:19:00 +0200 Subject: [PATCH 011/101] EffectMaker: Fix popup geometry Effect Maker preview and node combo box popups will now stay within the screen boundaries of the screen the parent combo box belongs to. Fixes: QDS-10512 Change-Id: Ibbfb706499c4b17e27ff5ae471fef8bb9f7384cb Reviewed-by: Mahmoud Badri --- .../EffectNodesComboBox.qml | 52 +++++++++++++------ .../PreviewImagesComboBox.qml | 52 +++++++++++++------ .../effectmakernew/effectmakerwidget.cpp | 14 +++++ .../effectmakernew/effectmakerwidget.h | 2 + 4 files changed, 86 insertions(+), 34 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml index 0827b20c1e3..0aca7a89089 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml @@ -23,18 +23,48 @@ StudioControls.ComboBox { required property Item mainRoot + readonly property int popupHeight: Math.min(800, row.height + 2) + + function calculateWindowGeometry() { + var globalPos = EffectMakerBackend.rootView.globalPos(mainRoot.mapFromItem(root, 0, 0)) + var screenRect = EffectMakerBackend.rootView.screenRect(); + + window.width = row.width + 2 // 2: scrollView left and right 1px margins + + var newX = globalPos.x + root.width - window.width + if (newX < screenRect.x) + newX = globalPos.x + + var newY = Math.min(screenRect.y + screenRect.height, + Math.max(screenRect.y, globalPos.y + root.height - 1)) + + // Check if we have more space above or below the control, and put control on that side, + // unless we have enough room for maximum size popup under the control + var newHeight + var screenY = newY - screenRect.y + if (screenRect.height - screenY > screenY || screenRect.height - screenY > root.popupHeight) { + newHeight = Math.min(root.popupHeight, screenRect.height - screenY) + } else { + newHeight = Math.min(root.popupHeight, screenY - root.height) + newY = newY - newHeight - root.height + 1 + } + + window.height = newHeight + window.x = newX + window.y = newY + } + Connections { target: root.popup function onAboutToShow() { - var a = mainRoot.mapToGlobal(0, 0) - var b = root.mapToItem(mainRoot, 0, 0) - - window.x = a.x + b.x + root.width - window.width - window.y = a.y + b.y + root.height - 1 + root.calculateWindowGeometry() window.show() window.requestActivate() + + // Geometry can get corrupted by first show after screen change, so recalc it + root.calculateWindowGeometry() } function onAboutToHide() { @@ -45,8 +75,6 @@ StudioControls.ComboBox { Window { id: window - width: row.width + 2 // 2: scrollView left and right 1px margins - height: Math.min(800, Math.min(row.height + 2, Screen.height - y - 40)) // 40: some bottom margin to cover OS bottom toolbar flags: Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint onActiveFocusItemChanged: { @@ -67,16 +95,6 @@ StudioControls.ComboBox { Row { id: row - onWidthChanged: { - // Needed to update on first window showing, as row.width only gets - // correct value after the window is shown, so first showing is off - - var a = mainRoot.mapToGlobal(0, 0) - var b = root.mapToItem(mainRoot, 0, 0) - - window.x = a.x + b.x + root.width - row.width - } - padding: 10 spacing: 10 diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml index bcf4efbd4d9..02e43ea10c7 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml @@ -30,18 +30,48 @@ StudioControls.ComboBox { "images/preview4.png"] property string selectedImage: images[0] + readonly property int popupHeight: Math.min(800, col.height + 2) + + function calculateWindowGeometry() { + var globalPos = EffectMakerBackend.rootView.globalPos(mainRoot.mapFromItem(root, 0, 0)) + var screenRect = EffectMakerBackend.rootView.screenRect(); + + window.width = col.width + 2 // 2: scrollView left and right 1px margins + + var newX = globalPos.x + root.width - window.width + if (newX < screenRect.x) + newX = globalPos.x + + var newY = Math.min(screenRect.y + screenRect.height, + Math.max(screenRect.y, globalPos.y + root.height - 1)) + + // Check if we have more space above or below the control, and put control on that side, + // unless we have enough room for maximum size popup under the control + var newHeight + var screenY = newY - screenRect.y + if (screenRect.height - screenY > screenY || screenRect.height - screenY > root.popupHeight) { + newHeight = Math.min(root.popupHeight, screenRect.height - screenY) + } else { + newHeight = Math.min(root.popupHeight, screenY - root.height) + newY = newY - newHeight - root.height + 1 + } + + window.height = newHeight + window.x = newX + window.y = newY + } + Connections { target: root.popup function onAboutToShow() { - var a = mainRoot.mapToGlobal(0, 0) - var b = root.mapToItem(mainRoot, 0, 0) - - window.x = a.x + b.x + root.width - window.width - window.y = a.y + b.y + root.height - 1 + root.calculateWindowGeometry() window.show() window.requestActivate() + + // Geometry can get corrupted by first show after screen change, so recalc it + root.calculateWindowGeometry() } function onAboutToHide() { @@ -65,8 +95,6 @@ StudioControls.ComboBox { Window { id: window - width: col.width + 2 // 2: scrollView left and right 1px margins - height: Math.min(800, Math.min(col.height + 2, Screen.height - y - 40)) // 40: some bottom margin to cover OS bottom toolbar flags: Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint onActiveFocusItemChanged: { @@ -88,16 +116,6 @@ StudioControls.ComboBox { Column { id: col - onWidthChanged: { - // Needed to update on first window showing, as row.width only gets - // correct value after the window is shown, so first showing is off - - var a = mainRoot.mapToGlobal(0, 0) - var b = root.mapToItem(mainRoot, 0, 0) - - window.x = a.x + b.x + root.width - col.width - } - padding: 10 spacing: 10 diff --git a/src/plugins/effectmakernew/effectmakerwidget.cpp b/src/plugins/effectmakernew/effectmakerwidget.cpp index 738c0a00168..724ab04f892 100644 --- a/src/plugins/effectmakernew/effectmakerwidget.cpp +++ b/src/plugins/effectmakernew/effectmakerwidget.cpp @@ -119,6 +119,20 @@ void EffectMakerWidget::focusSection(int section) Q_UNUSED(section) } +QRect EffectMakerWidget::screenRect() const +{ + if (m_quickWidget && m_quickWidget->screen()) + return m_quickWidget->screen()->availableGeometry(); + return {}; +} + +QPoint EffectMakerWidget::globalPos(const QPoint &point) const +{ + if (m_quickWidget) + return m_quickWidget->mapToGlobal(point); + return point; +} + QSize EffectMakerWidget::sizeHint() const { return {420, 420}; diff --git a/src/plugins/effectmakernew/effectmakerwidget.h b/src/plugins/effectmakernew/effectmakerwidget.h index 24efac7b586..3c43d732e40 100644 --- a/src/plugins/effectmakernew/effectmakerwidget.h +++ b/src/plugins/effectmakernew/effectmakerwidget.h @@ -41,6 +41,8 @@ public: Q_INVOKABLE void addEffectNode(const QString &nodeQenPath); Q_INVOKABLE void focusSection(int section); + Q_INVOKABLE QRect screenRect() const; + Q_INVOKABLE QPoint globalPos(const QPoint &point) const; QSize sizeHint() const override; From a3283587ddb571d872cc9b838064ad296466ee79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esa=20T=C3=B6rm=C3=A4nen?= Date: Thu, 16 Nov 2023 15:43:40 +0200 Subject: [PATCH 012/101] Doc: Update Creating UIs for MCUs page Removed the references to 3D design tools (Blender, Maya) and 3D UI design assets as the 3D view is not supported for developing MCU projects. Task-number: QDS-11231 Change-Id: Idfd2f2d5c513836aba802a7cfed8f8b66b3369f5 Reviewed-by: Yasser Grimes Reviewed-by: Leena Miettinen --- .../mcus/qtdesignstudio-creating-uis-for-mcus.qdoc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/doc/qtdesignstudio/src/mcus/qtdesignstudio-creating-uis-for-mcus.qdoc b/doc/qtdesignstudio/src/mcus/qtdesignstudio-creating-uis-for-mcus.qdoc index dbcb90269ba..2a02f879ee8 100644 --- a/doc/qtdesignstudio/src/mcus/qtdesignstudio-creating-uis-for-mcus.qdoc +++ b/doc/qtdesignstudio/src/mcus/qtdesignstudio-creating-uis-for-mcus.qdoc @@ -9,12 +9,12 @@ \title Creating UIs for MCUs As a technical artist or a designer, you can use specialized UI design tools, - such as Adobe Photoshop, Sketch, Figma, Blender, or Maya, to create the - original UI design files for your MCU application. After the initial design - work, export your design from the design tools, and import your 2D and 3D UI - design assets into \QDS, which can convert them into code for developers. - For more information on managing the original assets created with - specialized UI design tools, see \l {Asset Creation with Other Tools}. + such as Adobe Photoshop, Sketch, or Figma, to create the original UI design + files for your MCU application. After the initial design work, export your + design from the design tools, and import your 2D UI design assets into \QDS, + which can convert them into code for developers. For more information on + managing the original assets created with specialized UI design tools, see + \l {Asset Creation with Other Tools}. Once your UI design assets are in \QDS, use it to \l {Wireframing} {wireframe} your MCU application, to visualize its structure. To modify the look and feel From e740bc076c3c81179b3027f58459e1f3ffd9f7c2 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Fri, 17 Nov 2023 18:24:35 +0200 Subject: [PATCH 013/101] EffectMaker: Load effect nodes from share folder Change-Id: Ie7b1c95d6eb277c01310d9badc1b755e0517385c Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Miikka Heikkinen --- .../effectmakernew/effectmakernodesmodel.cpp | 41 ++++++------------- .../effectmakernew/effectmakernodesmodel.h | 5 +-- 2 files changed, 14 insertions(+), 32 deletions(-) diff --git a/src/plugins/effectmakernew/effectmakernodesmodel.cpp b/src/plugins/effectmakernew/effectmakernodesmodel.cpp index dc028aef8e8..dce99bba26e 100644 --- a/src/plugins/effectmakernew/effectmakernodesmodel.cpp +++ b/src/plugins/effectmakernew/effectmakernodesmodel.cpp @@ -3,6 +3,9 @@ #include "effectmakernodesmodel.h" +#include + +#include #include #include @@ -38,44 +41,27 @@ QVariant EffectMakerNodesModel::data(const QModelIndex &index, int role) const return m_categories.at(index.row())->property(roleNames().value(role)); } -void EffectMakerNodesModel::findNodesPath() +QString EffectMakerNodesModel::nodesSourcesPath() const { - if (m_nodesPath.exists() || m_probeNodesDir) - return; - - QDir nodesDir; - - if (!qEnvironmentVariable("EFFECT_MAKER_NODES_PATH").isEmpty()) - nodesDir.setPath(qEnvironmentVariable("EFFECT_MAKER_NODES_PATH")); - else if (Utils::HostOsInfo::isMacHost()) - nodesDir.setPath(QCoreApplication::applicationDirPath() + "/../Resources/effect_maker_nodes"); - - // search for nodesDir from exec dir and up - if (nodesDir.dirName() == ".") { - m_probeNodesDir = true; // probe only once - nodesDir.setPath(QCoreApplication::applicationDirPath()); - while (!nodesDir.cd("effect_maker_nodes") && nodesDir.cdUp()) - ; // do nothing - - if (nodesDir.dirName() != "effect_maker_nodes") // bundlePathDir not found - return; - } - - m_nodesPath = Utils::FilePath::fromString(nodesDir.path()); +#ifdef SHARE_QML_PATH + if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return QLatin1String(SHARE_QML_PATH) + "/effectMakerNodes"; +#endif + return Core::ICore::resourcePath("qmldesigner/effectMakerNodes").toString(); } void EffectMakerNodesModel::loadModel() { - findNodesPath(); + auto nodesPath = Utils::FilePath::fromString(nodesSourcesPath()); - if (!m_nodesPath.exists()) { + if (!nodesPath.exists()) { qWarning() << __FUNCTION__ << "Effects not found."; return; } m_categories = {}; - QDirIterator itCategories(m_nodesPath.toString(), QDir::Dirs | QDir::NoDotAndDotDot); + QDirIterator itCategories(nodesPath.toString(), QDir::Dirs | QDir::NoDotAndDotDot); while (itCategories.hasNext()) { itCategories.next(); @@ -85,7 +71,7 @@ void EffectMakerNodesModel::loadModel() QString catName = itCategories.fileName(); QList effects = {}; - Utils::FilePath categoryPath = m_nodesPath.resolvePath(itCategories.fileName()); + Utils::FilePath categoryPath = nodesPath.resolvePath(itCategories.fileName()); QDirIterator itEffects(categoryPath.toString(), {"*.qen"}, QDir::Files); while (itEffects.hasNext()) { itEffects.next(); @@ -112,4 +98,3 @@ void EffectMakerNodesModel::resetModel() } } // namespace EffectMaker - diff --git a/src/plugins/effectmakernew/effectmakernodesmodel.h b/src/plugins/effectmakernew/effectmakernodesmodel.h index 28a4e8484f0..56400982da3 100644 --- a/src/plugins/effectmakernew/effectmakernodesmodel.h +++ b/src/plugins/effectmakernew/effectmakernodesmodel.h @@ -5,8 +5,6 @@ #include "effectnodescategory.h" -#include - #include namespace EffectMaker { @@ -33,10 +31,9 @@ public: QList categories() const { return m_categories; } private: - void findNodesPath(); + QString nodesSourcesPath() const; QList m_categories; - Utils::FilePath m_nodesPath; bool m_probeNodesDir = false; }; From 38205996affa8b3232e7d27ac02455f167906bd9 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 14 Nov 2023 12:43:46 +0200 Subject: [PATCH 014/101] EffectMaker: Add the default image to UrlChooser combo for image values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: QDS-11221 Change-Id: Ib788c6950c9fc59fd87e199ab6c54bdd274cc8a2 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Mahmoud Badri Reviewed-by: Amr Elsayed Reviewed-by: Henning Gründl --- .../effectMakerQmlSources/ValueImage.qml | 14 ++++++++++++++ .../imports/HelperWidgets/UrlChooser.qml | 11 +++++++++-- src/plugins/effectmakernew/uniform.h | 1 + .../propertyeditor/fileresourcesmodel.cpp | 7 +++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueImage.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueImage.qml index 571fac50002..832350ef177 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueImage.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/ValueImage.qml @@ -19,5 +19,19 @@ Row { actionIndicatorVisible: false onAbsoluteFilePathChanged: uniformValue = absoluteFilePath + + function defaultAsString() { + let urlStr = uniformDefaultValue.toString() + urlStr = urlStr.replace(/^(file:\/{3})/, "") + + // Prepend slash if there is no drive letter + if (urlStr.length > 1 && urlStr[1] !== ':') + urlStr = '/' + urlStr; + + return urlStr + } + + defaultItems: [uniformDefaultValue.split('/').pop()] + defaultPaths: [defaultAsString(uniformDefaultValue)] } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml index 485640bcf84..9b0252c02c0 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml @@ -22,6 +22,10 @@ Row { // by QtQuick3D to add built-in primitives to the model. property var defaultItems + // These paths will be used for default items if they are defined. Otherwise, default item + // itself is used as the path. + property var defaultPaths + // Current item property string absoluteFilePath: "" @@ -422,8 +426,10 @@ Row { if (root.defaultItems !== undefined) { for (var i = 0; i < root.defaultItems.length; ++i) { comboBox.listModel.append({ - absoluteFilePath: "", - relativeFilePath: root.defaultItems[i], + absoluteFilePath: root.defaultPaths ? root.defaultPaths[i] + : "", + relativeFilePath: root.defaultPaths ? root.defaultPaths[i] + : root.defaultItems[i], name: root.defaultItems[i], group: 0 }) @@ -454,6 +460,7 @@ Row { } onDefaultItemsChanged: root.createModel() + onDefaultPathsChanged: root.createModel() Component.onCompleted: { root.createModel() diff --git a/src/plugins/effectmakernew/uniform.h b/src/plugins/effectmakernew/uniform.h index f5731af00a8..943942639c9 100644 --- a/src/plugins/effectmakernew/uniform.h +++ b/src/plugins/effectmakernew/uniform.h @@ -25,6 +25,7 @@ class Uniform : public QObject Q_PROPERTY(QVariant uniformBackendValue READ backendValue NOTIFY uniformBackendValueChanged) Q_PROPERTY(QVariant uniformMinValue MEMBER m_minValue CONSTANT) Q_PROPERTY(QVariant uniformMaxValue MEMBER m_maxValue CONSTANT) + Q_PROPERTY(QVariant uniformDefaultValue MEMBER m_defaultValue CONSTANT) public: enum class Type diff --git a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp index aae0867c915..3c419a3e82d 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/fileresourcesmodel.cpp @@ -158,6 +158,13 @@ QString FileResourcesModel::resolve(const QString &relative) const if (!QUrl::fromUserInput(relative, m_docPath.path()).isLocalFile()) return relative; + const QUrl relUrl(relative); + if (relUrl.isLocalFile()) { + QString localFile = relUrl.toLocalFile(); + if (QDir::isAbsolutePath(localFile)) + return localFile; + } + return QFileInfo(m_docPath, relative).absoluteFilePath(); } From 414649e385e84a85a0312b8bf66e08301f7ab977 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Wed, 15 Nov 2023 10:24:01 +0200 Subject: [PATCH 015/101] QmlDesigner: Remove the export popup Task-number: QDS-11242 Change-Id: I3ef24a41e58162eeb34fcf0f220d5854410fbb73 Reviewed-by: Miikka Heikkinen Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Mahmoud Badri --- .../CollectionDetailsToolbar.qml | 42 +++++-------------- .../collectiondetailsmodel.cpp | 15 +++++-- 2 files changed, 23 insertions(+), 34 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml index 93839872ba2..436ca8a0ab5 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml @@ -115,29 +115,7 @@ Item { icon: StudioTheme.Constants.export_medium tooltip: qsTr("Export the model to a new file") enabled: root.model.collectionName !== "" - onClicked: exportMenu.popup() - } - - StudioControls.Menu { - id: exportMenu - - StudioControls.MenuItem { - text: qsTr("Export as JSON") - onTriggered: - { - fileDialog.defaultSuffix = "json" - fileDialog.open() - } - } - - StudioControls.MenuItem { - text: qsTr("Export as CSV") - onTriggered: - { - fileDialog.defaultSuffix = "csv" - fileDialog.open() - } - } + onClicked: fileDialog.open() } } } @@ -145,17 +123,19 @@ Item { PlatformWidgets.FileDialog { id: fileDialog + fileMode: PlatformWidgets.FileDialog.SaveFile - onAccepted: - { - var fileAddress = file.toString() - if (fileAddress.indexOf("json") !== -1) - root.model.exportCollection(fileAddress, root.model.collectionName, "JSON") - else if (fileAddress.indexOf("csv") !== -1) - root.model.exportCollection(fileAddress, root.model.collectionName, "CSV") + nameFilters: ["JSON Files (*.json)", + "Comma-Separated Values (*.csv)" + ] - fileDialog.reject() + selectedNameFilter.index: 0 + + onAccepted: { + let filePath = fileDialog.file.toString() + let exportType = fileDialog.selectedNameFilter.index === 0 ? "JSON" : "CSV" + root.model.exportCollection(filePath, root.model.collectionName, exportType) } } diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp index 2374726f92c..796290afddc 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -409,14 +410,22 @@ void CollectionDetailsModel::loadCollection(const ModelNode &sourceNode, const Q bool CollectionDetailsModel::exportCollection(const QString &path, const QString &collectionName, const QString &exportType) { QUrl url(path); - QString fileAddress = url.isLocalFile() ? url.toLocalFile() : path; + QString filePath; + if (url.isLocalFile()) { + QFileInfo fileInfo(url.toLocalFile()); + if (fileInfo.suffix().toLower() != exportType.toLower()) + fileInfo.setFile(QString("%1.%2").arg(url.toLocalFile(), exportType.toLower())); + filePath = fileInfo.absoluteFilePath(); + } else { + filePath = path; + } if (exportType == "JSON") { QJsonArray content = m_currentCollection.getJsonCollection(); - return saveCollectionAsJson(fileAddress, content, collectionName); + return saveCollectionAsJson(filePath, content, collectionName); } else if (exportType == "CSV") { QString content = m_currentCollection.getCsvCollection(); - return saveCollectionAsCsv(fileAddress, content); + return saveCollectionAsCsv(filePath, content); } return false; From af656a3b531fd26270a2a2cc39268717491af820 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Thu, 16 Nov 2023 13:58:40 +0200 Subject: [PATCH 016/101] EffectMaker: Fix copying asset files during export Fixes: QDS-11290 Change-Id: I54d7f618bcf1bed44d105ceb4e48fd6820d6b6ea Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Amr Elsayed Reviewed-by: Mahmoud Badri --- src/plugins/effectmakernew/effectmakermodel.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index 5852f69bd45..b078d563aa0 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -702,7 +702,11 @@ void EffectMakerModel::exportResources(const QString &name) QString imagePath = uniform->value().toString(); QFileInfo fi(imagePath); QString imageFilename = fi.fileName(); - sources.append(imagePath.remove(0, 7)); // Removes "file://" + if (imagePath.startsWith("file:")) { + QUrl url(imagePath); + imagePath = url.toLocalFile(); + } + sources.append(imagePath); dests.append(imageFilename); } } From 9d0fd52a7ccce6f37b9b107a38b55d4a456f3d4f Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 20 Nov 2023 16:35:35 +0200 Subject: [PATCH 017/101] EffectMaker: Fix combo box open/close behavior Fixed inconsistent opening and closing of preview and add effect popups, when clicking on the content part of the combo box. Also, pressing Escape now closes opened combobox popups. Fixes: QDS-11307 Change-Id: I3b3fddbaa743c77fd60833378ab809b17a8f1a84 Reviewed-by: Amr Elsayed Reviewed-by: Mahmoud Badri --- .../EffectNodesComboBox.qml | 8 ++++++- .../PreviewImagesComboBox.qml | 22 ++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml index 0aca7a89089..42265970787 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml @@ -78,7 +78,7 @@ StudioControls.ComboBox { flags: Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint onActiveFocusItemChanged: { - if (!window.activeFocusItem && !root.indicator.hover && root.popup.opened) + if (!window.activeFocusItem && !root.hovered && root.popup.opened) root.popup.close() } @@ -87,6 +87,7 @@ StudioControls.ComboBox { color: StudioTheme.Values.themePanelBackground border.color: StudioTheme.Values.themeInteraction border.width: 1 + focus: true HelperWidgets.ScrollView { anchors.fill: parent @@ -126,6 +127,11 @@ StudioControls.ComboBox { } } } + + Keys.onPressed: function(event) { + if (event.key === Qt.Key_Escape && root.popup.opened) + root.popup.close() + } } } } diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml index 02e43ea10c7..feadaa1d940 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/PreviewImagesComboBox.qml @@ -90,6 +90,20 @@ StudioControls.ComboBox { anchors.fill: parent anchors.margins: 1 } + + MouseArea { + anchors.fill: parent + enabled: true + acceptedButtons: Qt.LeftButton + cursorShape: Qt.PointingHandCursor + onPressed: (mouse) => { + if (root.popup.opened) + root.popup.close() + else + root.popup.open() + mouse.accepted = true + } + } } Window { @@ -98,7 +112,7 @@ StudioControls.ComboBox { flags: Qt.Dialog | Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint onActiveFocusItemChanged: { - if (!window.activeFocusItem && !root.indicator.hover && root.popup.opened) + if (!window.activeFocusItem && !root.hovered && root.popup.opened) root.popup.close() } @@ -107,6 +121,7 @@ StudioControls.ComboBox { color: StudioTheme.Values.themePanelBackground border.color: StudioTheme.Values.themeInteraction border.width: 1 + focus: true HelperWidgets.ScrollView { anchors.fill: parent @@ -153,6 +168,11 @@ StudioControls.ComboBox { } } } + + Keys.onPressed: function(event) { + if (event.key === Qt.Key_Escape && root.popup.opened) + root.popup.close() + } } } } From a5a1152a76d93e64cfc85446ea7eefae1f78609b Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Mon, 13 Nov 2023 18:28:10 +0200 Subject: [PATCH 018/101] QmlDesigner: Support having diffrent url types by the collection editor Task-number: QDS-11222 Change-Id: I94aac8a6cc5eb86d338b02a24886388188dc5def Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../collectiondetailsmodel.cpp | 3 +- .../collectioneditorutils.cpp | 14 ++++++ .../collectioneditor/collectioneditorutils.h | 2 + .../collectioneditor/collectionlistmodel.cpp | 2 +- .../collectionsourcemodel.cpp | 14 ++---- .../collectioneditor/collectionview.cpp | 10 +++- .../collectioneditor/collectionwidget.cpp | 46 ++++++------------- .../collectioneditor/collectionwidget.h | 10 ++-- 8 files changed, 50 insertions(+), 51 deletions(-) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp index 796290afddc..2ef2e211710 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp @@ -4,6 +4,7 @@ #include "collectiondetailsmodel.h" #include "collectioneditorconstants.h" +#include "collectioneditorutils.h" #include "modelnode.h" #include "variantproperty.h" @@ -385,7 +386,7 @@ QStringList CollectionDetailsModel::typesList() void CollectionDetailsModel::loadCollection(const ModelNode &sourceNode, const QString &collection) { - QString fileName = sourceNode.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY).value().toString(); + QString fileName = CollectionEditor::getSourceCollectionPath(sourceNode); CollectionReference newReference{sourceNode, collection}; bool alreadyOpen = m_openedCollections.contains(newReference); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp index 1e47f6460f6..c7b3d9a23da 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp @@ -7,6 +7,8 @@ #include "bindingproperty.h" #include "nodemetainfo.h" #include "propertymetainfo.h" +#include "qmldesignerplugin.h" +#include "variantproperty.h" #include @@ -111,4 +113,16 @@ bool canAcceptCollectionAsModel(const ModelNode &node) && modelProperty.propertyType().isVariant(); } +QString getSourceCollectionPath(const ModelNode &node) +{ + QUrl nodeSource = node.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY).value().toUrl(); + QString sourcePath = nodeSource.isLocalFile() ? nodeSource.toLocalFile() : nodeSource.toString(); + return QmlDesignerPlugin::instance() + ->currentDesignDocument() + ->fileName() + .parentDir() + .resolvePath(sourcePath) + .toFSPathString(); +} + } // namespace QmlDesigner::CollectionEditor diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h index 464e9e49689..1f7bdb87977 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h @@ -11,6 +11,8 @@ bool variantIslessThan(const QVariant &a, const QVariant &b, CollectionDetails:: QString getSourceCollectionType(const QmlDesigner::ModelNode &node); +QString getSourceCollectionPath(const QmlDesigner::ModelNode &node); + void assignCollectionSourceToNode(AbstractView *view, const ModelNode &modelNode, const ModelNode &collectionSourceNode = {}); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp index bc0e1dc6662..d910569f0d2 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionlistmodel.cpp @@ -121,7 +121,7 @@ ModelNode CollectionListModel::sourceNode() const QString CollectionListModel::sourceAddress() const { - return m_sourceNode.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY).value().toString(); + return CollectionEditor::getSourceCollectionPath(m_sourceNode); } bool CollectionListModel::contains(const QString &collectionName) const diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp index 74cf8d41b43..d7e31607908 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp @@ -26,7 +26,7 @@ QSharedPointer loadCollection( QSharedPointer initialCollection = {}) { using namespace QmlDesigner::CollectionEditor; - QString sourceFileAddress = sourceNode.variantProperty(SOURCEFILE_PROPERTY).value().toString(); + QString sourceFileAddress = getSourceCollectionPath(sourceNode); QSharedPointer collectionsList; auto setupCollectionList = [&sourceNode, &initialCollection, &collectionsList]() { @@ -286,9 +286,7 @@ bool CollectionSourceModel::addCollectionToSource(const ModelNode &node, if (collectionExists(node, collectionName)) return returnError(tr("Model does not exist.")); - QString sourceFileAddress = node.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY) - .value() - .toString(); + QString sourceFileAddress = CollectionEditor::getSourceCollectionPath(node); QFileInfo sourceFileInfo(sourceFileAddress); if (!sourceFileInfo.isFile()) @@ -442,9 +440,7 @@ void CollectionSourceModel::onCollectionNameChanged(const QString &oldName, cons return; } - QString sourceFileAddress = node.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY) - .value() - .toString(); + QString sourceFileAddress = CollectionEditor::getSourceCollectionPath(node); QFileInfo sourceFileInfo(sourceFileAddress); if (!sourceFileInfo.isFile()) { @@ -533,9 +529,7 @@ void CollectionSourceModel::onCollectionsRemoved(const QStringList &removedColle return; } - QString sourceFileAddress = node.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY) - .value() - .toString(); + QString sourceFileAddress = CollectionEditor::getSourceCollectionPath(node); QFileInfo sourceFileInfo(sourceFileAddress); if (!sourceFileInfo.isFile()) { diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp index e3c8d26519c..f9354ddfb0f 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp @@ -147,7 +147,15 @@ void CollectionView::addResource(const QUrl &url, const QString &name, const QSt { executeInTransaction(Q_FUNC_INFO, [this, &url, &name, &type]() { ensureStudioModelImport(); - QString sourceAddress = url.isLocalFile() ? url.toLocalFile() : url.toString(); + QString sourceAddress; + if (url.isLocalFile()) { + Utils::FilePath fp = QmlDesignerPlugin::instance()->currentDesignDocument()->fileName().parentDir(); + sourceAddress = Utils::FilePath::calcRelativePath(url.toLocalFile(), + fp.absoluteFilePath().toString()); + } else { + sourceAddress = url.toString(); + } + const NodeMetaInfo resourceMetaInfo = type.compare("json", Qt::CaseInsensitive) == 0 ? jsonCollectionMetaInfo() : csvCollectionMetaInfo(); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp index 8f6168dfb2d..5b5836863ba 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp @@ -39,21 +39,6 @@ QString collectionViewResourcesPath() return Core::ICore::resourcePath("qmldesigner/collectionEditorQmlSource").toString(); } -QString urlToLocalPath(const QUrl &url) -{ - QString localPath; - - if (url.isLocalFile()) - localPath = url.toLocalFile(); - - if (url.scheme() == QLatin1String("qrc")) { - const QString &path = url.path(); - localPath = QStringLiteral(":") + path; - } - - return localPath; -} - QString getPreferredCollectionName(const QUrl &url, const QString &collectionName) { if (collectionName.isEmpty()) { @@ -162,32 +147,27 @@ QSize CollectionWidget::minimumSizeHint() const return {300, 400}; } -bool CollectionWidget::loadJsonFile(const QString &jsonFileAddress, const QString &collectionName) +bool CollectionWidget::loadJsonFile(const QUrl &url, const QString &collectionName) { - if (!isJsonFile(jsonFileAddress)) + if (!isJsonFile(url)) return false; - m_view->addResource(jsonFileAddress, - getPreferredCollectionName(jsonFileAddress, collectionName), - "json"); + m_view->addResource(url, getPreferredCollectionName(url, collectionName), "json"); return true; } -bool CollectionWidget::loadCsvFile(const QString &csvFileAddress, const QString &collectionName) +bool CollectionWidget::loadCsvFile(const QUrl &url, const QString &collectionName) { - m_view->addResource(csvFileAddress, - getPreferredCollectionName(csvFileAddress, collectionName), - "csv"); + m_view->addResource(url, getPreferredCollectionName(url, collectionName), "csv"); return true; } -bool CollectionWidget::isJsonFile(const QString &jsonFileAddress) const +bool CollectionWidget::isJsonFile(const QUrl &url) const { - QUrl jsonUrl(jsonFileAddress); - QString fileAddress = jsonUrl.isLocalFile() ? jsonUrl.toLocalFile() : jsonUrl.toString(); - QFile file(fileAddress); + QString filePath = url.isLocalFile() ? url.toLocalFile() : url.toString(); + QFile file(filePath); if (!file.exists() || !file.open(QFile::ReadOnly)) return false; @@ -200,10 +180,9 @@ bool CollectionWidget::isJsonFile(const QString &jsonFileAddress) const return true; } -bool CollectionWidget::isCsvFile(const QString &csvFilePath) const +bool CollectionWidget::isCsvFile(const QUrl &url) const { - QUrl csvUrl(csvFilePath); - QString filePath = csvUrl.isLocalFile() ? csvUrl.toLocalFile() : csvUrl.toString(); + QString filePath = url.isLocalFile() ? url.toLocalFile() : url.toString(); QFile file(filePath); return file.exists() && file.fileName().endsWith(".csv"); @@ -211,14 +190,15 @@ bool CollectionWidget::isCsvFile(const QString &csvFilePath) const bool CollectionWidget::addCollection(const QString &collectionName, const QString &collectionType, - const QString &sourceAddress, + const QUrl &sourceUrl, const QVariant &sourceNode) { const ModelNode node = sourceNode.value(); bool isNewCollection = !node.isValid(); if (isNewCollection) { - QString sourcePath = ::urlToLocalPath(sourceAddress); + QString sourcePath = sourceUrl.isLocalFile() ? sourceUrl.toLocalFile() : sourceUrl.toString(); + if (collectionType == "json") { QJsonObject jsonObject; QJsonObject initialObject; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h index 5bf728660cb..6be4fabd6ac 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h @@ -34,13 +34,13 @@ public: virtual QSize minimumSizeHint() const; - Q_INVOKABLE bool loadJsonFile(const QString &jsonFileAddress, const QString &collectionName = {}); - Q_INVOKABLE bool loadCsvFile(const QString &csvFileAddress, const QString &collectionName = {}); - Q_INVOKABLE bool isJsonFile(const QString &jsonFileAddress) const; - Q_INVOKABLE bool isCsvFile(const QString &csvFileAddress) const; + Q_INVOKABLE bool loadJsonFile(const QUrl &url, const QString &collectionName = {}); + Q_INVOKABLE bool loadCsvFile(const QUrl &url, const QString &collectionName = {}); + Q_INVOKABLE bool isJsonFile(const QUrl &url) const; + Q_INVOKABLE bool isCsvFile(const QUrl &url) const; Q_INVOKABLE bool addCollection(const QString &collectionName, const QString &collectionType, - const QString &sourceAddress, + const QUrl &sourceUrl, const QVariant &sourceNode); Q_INVOKABLE void assignSourceNodeToSelectedItem(const QVariant &sourceNode); From 42405ffa743488e2da95a81c8a0b1d7c21f75dda Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Fri, 17 Nov 2023 11:34:50 +0200 Subject: [PATCH 019/101] QmlDesigner: Fix the bug for saving collection - The node resolved path was wrong. - Also the saving method is cleaned up. Change-Id: Ic905c20e5899fcc23c97a8d42a1fdf7c0c8e1089 Reviewed-by: Mahmoud Badri --- .../CollectionDetailsToolbar.qml | 8 +---- .../collectiondetailsmodel.cpp | 34 +++++++++++++++++-- .../collectioneditor/collectiondetailsmodel.h | 7 +++- .../collectionsourcemodel.cpp | 5 --- .../collectioneditor/collectionsourcemodel.h | 2 -- 5 files changed, 38 insertions(+), 18 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml index 436ca8a0ab5..e627a6b6db4 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml @@ -102,13 +102,7 @@ Item { icon: StudioTheme.Constants.updateContent_medium tooltip: qsTr("Update existing file with changes") enabled: root.model.collectionName !== "" - onClicked: - { - if (root.backend.selectedSourceAddress().indexOf("json") !== -1) - root.model.exportCollection(root.backend.selectedSourceAddress(), root.model.collectionName, "JSON") - else - root.model.exportCollection(root.backend.selectedSourceAddress(), root.model.collectionName, "CSV") - } + onClicked: root.model.saveCurrentCollection() } IconButton { diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp index 2ef2e211710..a39da321e92 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp @@ -408,9 +408,10 @@ void CollectionDetailsModel::loadCollection(const ModelNode &sourceNode, const Q } } -bool CollectionDetailsModel::exportCollection(const QString &path, const QString &collectionName, const QString &exportType) +bool CollectionDetailsModel::exportCollection(const QUrl &url, + const QString &collectionName, + const QString &exportType) { - QUrl url(path); QString filePath; if (url.isLocalFile()) { QFileInfo fileInfo(url.toLocalFile()); @@ -418,7 +419,7 @@ bool CollectionDetailsModel::exportCollection(const QString &path, const QString fileInfo.setFile(QString("%1.%2").arg(url.toLocalFile(), exportType.toLower())); filePath = fileInfo.absoluteFilePath(); } else { - filePath = path; + filePath = url.toString(); } if (exportType == "JSON") { @@ -432,6 +433,11 @@ bool CollectionDetailsModel::exportCollection(const QString &path, const QString return false; } +bool CollectionDetailsModel::saveCurrentCollection() +{ + return saveCollection(m_currentCollection); +} + void CollectionDetailsModel::updateEmpty() { bool isEmptyNow = rowCount() == 0; @@ -606,6 +612,28 @@ void CollectionDetailsModel::setCollectionName(const QString &newCollectionName) } } +bool CollectionDetailsModel::saveCollection(CollectionDetails &collection) +{ + if (!collection.isValid() || !m_openedCollections.contains(collection.reference())) + return false; + + const ModelNode node = collection.reference().node; + bool saved = false; + + if (CollectionEditor::getSourceCollectionType(node) == "json") { + saved = saveCollectionAsJson(CollectionEditor::getSourceCollectionPath(node), + collection.getJsonCollection(), + collection.reference().name); + } else if (CollectionEditor::getSourceCollectionType(node) == "csv") { + saved = saveCollectionAsCsv(CollectionEditor::getSourceCollectionPath(node), + collection.getCsvCollection()); + } + if (saved) + collection.markSaved(); + + return saved; +} + bool CollectionDetailsModel::saveCollectionAsJson(const QString &path, const QJsonArray &content, const QString &collectionName) { QFile sourceFile(path); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h index 38c59d8fe92..eca3c697200 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h @@ -63,7 +63,11 @@ public: void loadCollection(const ModelNode &sourceNode, const QString &collection); - Q_INVOKABLE bool exportCollection(const QString &path, const QString &collectionName, const QString &exportType); + Q_INVOKABLE bool exportCollection(const QUrl &url, + const QString &collectionName, + const QString &exportType); + + Q_INVOKABLE bool saveCurrentCollection(); signals: void collectionNameChanged(const QString &collectionName); @@ -81,6 +85,7 @@ private: void setCollectionName(const QString &newCollectionName); void loadJsonCollection(const QString &source, const QString &collection); void loadCsvCollection(const QString &source, const QString &collectionName); + bool saveCollection(CollectionDetails &collection); bool saveCollectionAsJson(const QString &path, const QJsonArray &content, const QString &collectionName); bool saveCollectionAsCsv(const QString &path, const QString &content); QVariant variantFromString(const QString &value); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp index d7e31607908..df7e90f3312 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp @@ -393,11 +393,6 @@ void CollectionSourceModel::updateNodeSource(const ModelNode &node) updateCollectionList(index); } -QString CollectionSourceModel::selectedSourceAddress() const -{ - return index(m_selectedIndex).data(SourceRole).toString(); -} - void CollectionSourceModel::onSelectedCollectionChanged(int collectionIndex) { CollectionListModel *collectionList = qobject_cast(sender()); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h index 39c82ec5b31..28c36d03e01 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h @@ -67,8 +67,6 @@ public: void updateNodeName(const ModelNode &node); void updateNodeSource(const ModelNode &node); - Q_INVOKABLE QString selectedSourceAddress() const; - signals: void selectedIndexChanged(int idx); void collectionSelected(const ModelNode &sourceNode, const QString &collectionName); From 16e06a0af0e73c144c762f75f00d49655c048a29 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Wed, 15 Nov 2023 19:07:28 +0200 Subject: [PATCH 020/101] QmlDesigner: Move the action for adding a collection to json The action should be moved to the tool menu of the Json Collection Task-number: QDS-11256 Change-Id: Ieb2c9cc4f4b992f1ac3225bbbd90e3d14afdc711 Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../CollectionView.qml | 6 ++ .../ModelSourceItem.qml | 88 +++++++++++++++++++ .../NewCollectionDialog.qml | 8 +- .../collectioneditorutils.cpp | 12 +++ .../collectioneditor/collectioneditorutils.h | 6 ++ .../collectionsourcemodel.cpp | 2 +- .../collectioneditor/collectionwidget.cpp | 7 +- 7 files changed, 115 insertions(+), 14 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml index 70eb32c9c86..c6873460e4b 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml @@ -131,6 +131,12 @@ Item { onDeleteItem: root.model.removeRow(index) hasSelectedTarget: root.rootView.targetNodeSelected onAssignToSelected: root.rootView.assignSourceNodeToSelectedItem(sourceNode) + onAddCollection: (collectionName) => { + root.rootView.addCollection(collectionName, + sourceCollectionType, + "", + sourceNode) + } } } } diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml index d04181fd590..00f4b804e41 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml @@ -20,10 +20,12 @@ Item { property var collectionModel property bool expanded: false + readonly property bool isJsonModel: sourceCollectionType === "json" signal selectItem(int itemIndex) signal deleteItem() signal assignToSelected() + signal addCollection(string collectionName) function toggleExpanded() { if (collectionListView.count > 0) @@ -169,6 +171,12 @@ Item { closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside + StudioControls.MenuItem { + text: qsTr("Add a model") + visible: root.isJsonModel && internalModels !== undefined + onTriggered: newCollectionDialog.open() + } + StudioControls.MenuItem { text: qsTr("Delete") shortcut: StandardKey.Delete @@ -193,6 +201,21 @@ Item { implicitHeight: StudioTheme.Values.sectionColumnSpacing } + component NameField: Text { + Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + horizontalAlignment: Qt.AlignRight + verticalAlignment: Qt.AlignCenter + color: StudioTheme.Values.themeTextColor + font.family: StudioTheme.Constants.font.family + font.pixelSize: StudioTheme.Values.baseIconFontSize + } + + component ErrorField: Text { + color: StudioTheme.Values.themeError + font.family: StudioTheme.Constants.font.family + font.pixelSize: StudioTheme.Values.baseIconFontSize + } + StudioControls.Dialog { id: deleteDialog @@ -292,6 +315,71 @@ Item { } } + StudioControls.Dialog { + id: newCollectionDialog + + title: qsTr("Add a new model") + + onOpened: newCollectionName.text = qsTr("Model") + + onAccepted: root.addCollection(newCollectionName.text) + + contentItem: ColumnLayout { + spacing: 2 + + NameField { + text: qsTr("The model name") + } + + StudioControls.TextField { + id: newCollectionName + + readonly property bool isValid: newCollectionName.text !== "" && !newCollectionName.alreadyExists + property bool alreadyExists + + Layout.fillWidth: true + + actionIndicator.visible: false + translationIndicator.visible: false + validator: RegularExpressionValidator { + regularExpression: /^\w+$/ + } + + Keys.onEnterPressed: createCollectionButton.onClicked() + Keys.onReturnPressed: createCollectionButton.onClicked() + Keys.onEscapePressed: newCollectionDialog.reject() + + onTextChanged: newCollectionName.alreadyExists = internalModels.contains(newCollectionName.text) + } + + ErrorField { + text: qsTr("The model name already exists %1").arg(newCollectionName.text) + visible: newCollectionName.alreadyExists + } + + Spacer{} + + RowLayout { + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + spacing: StudioTheme.Values.sectionRowSpacing + + HelperWidgets.Button { + id: createCollectionButton + + Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + text: qsTr("Add") + enabled: newCollectionName.isValid + onClicked: newCollectionDialog.accept() + } + + HelperWidgets.Button { + text: qsTr("Cancel") + onClicked: newCollectionDialog.reject() + } + } + } + } + RegularExpressionValidator { id: newNameValidator regularExpression: /^\w+$/ diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml index ee5dba02706..bfe985a0f52 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml @@ -14,7 +14,7 @@ import CollectionEditor 1.0 StudioControls.Dialog { id: root - enum SourceType { NewJson, NewCsv, ExistingCollection, NewCollectionToJson } + enum SourceType { NewJson, NewCsv, ExistingCollection } required property var backendValue required property var sourceModel @@ -72,11 +72,6 @@ StudioControls.Dialog { newCollectionPath.enabled = true jsonCollections.enabled = false typeMode.collectionType = "existing" - } else if (typeMode.currentValue === NewCollectionDialog.SourceType.NewCollectionToJson) { - newCollectionFileDialog.nameFilters = [""] - newCollectionPath.enabled = false - jsonCollections.enabled = true - typeMode.collectionType = "json" } } @@ -135,7 +130,6 @@ StudioControls.Dialog { ListElement { text: qsTr("New JSON model group"); value: NewCollectionDialog.SourceType.NewJson} ListElement { text: qsTr("New CSV model"); value: NewCollectionDialog.SourceType.NewCsv} ListElement { text: qsTr("Import an existing model group"); value: NewCollectionDialog.SourceType.ExistingCollection} - ListElement { text: qsTr("Add a model to an available JSON model group"); value: NewCollectionDialog.SourceType.NewCollectionToJson} } textRole: "text" diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp index c7b3d9a23da..0d857401e28 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp @@ -15,6 +15,8 @@ #include #include +#include +#include #include namespace { @@ -125,4 +127,14 @@ QString getSourceCollectionPath(const ModelNode &node) .toFSPathString(); } +QJsonArray defaultCollectionArray() +{ + QJsonObject initialObject; + QJsonArray initialCollection; + + initialObject.insert("Column1", ""); + initialCollection.append(initialObject); + return initialCollection; +} + } // namespace QmlDesigner::CollectionEditor diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h index 1f7bdb87977..de0be4c72a4 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h @@ -5,6 +5,10 @@ #include "collectiondetails.h" +QT_BEGIN_NAMESPACE +class QJsonArray; +QT_END_NAMESPACE + namespace QmlDesigner::CollectionEditor { bool variantIslessThan(const QVariant &a, const QVariant &b, CollectionDetails::DataType type); @@ -19,4 +23,6 @@ void assignCollectionSourceToNode(AbstractView *view, bool canAcceptCollectionAsModel(const ModelNode &node); +QJsonArray defaultCollectionArray(); + } // namespace QmlDesigner::CollectionEditor diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp index df7e90f3312..12f8dd099c9 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp @@ -305,7 +305,7 @@ bool CollectionSourceModel::addCollectionToSource(const ModelNode &node, if (document.isObject()) { QJsonObject sourceObject = document.object(); - sourceObject.insert(collectionName, QJsonArray{}); + sourceObject.insert(collectionName, CollectionEditor::defaultCollectionArray()); document.setObject(sourceObject); if (!jsonFile.resize(0)) return returnError(tr("Can't clean \"%1\".").arg(sourceFileInfo.absoluteFilePath())); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp index 5b5836863ba..54eeedf7352 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp @@ -201,12 +201,7 @@ bool CollectionWidget::addCollection(const QString &collectionName, if (collectionType == "json") { QJsonObject jsonObject; - QJsonObject initialObject; - QJsonArray initialCollection; - - initialObject.insert("Column1", ""); - initialCollection.append(initialObject); - jsonObject.insert(collectionName, initialCollection); + jsonObject.insert(collectionName, CollectionEditor::defaultCollectionArray()); QFile sourceFile(sourcePath); if (!sourceFile.open(QFile::WriteOnly)) { From 9a55e5c3de572cae71c3711853b4ffc928474afb Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Sat, 18 Nov 2023 01:23:24 +0200 Subject: [PATCH 021/101] QmlDesigner: Import a model to the default JSON model group Task-number: QDS-11312 Change-Id: Ib97273a15db4c7fb46ed01debf99602b71ec7630 Reviewed-by: Mahmoud Badri --- .../CollectionView.qml | 29 +--- .../{CsvImport.qml => ImportDialog.qml} | 36 +++-- .../collectionEditorQmlSource/JsonImport.qml | 145 ------------------ src/plugins/qmldesigner/CMakeLists.txt | 1 + .../collectioneditorutils.cpp | 12 ++ .../collectioneditor/collectioneditorutils.h | 3 + .../collectionimporttools.cpp | 105 +++++++++++++ .../collectioneditor/collectionimporttools.h | 16 ++ .../collectionsourcemodel.cpp | 5 +- .../collectioneditor/collectionsourcemodel.h | 1 + .../collectioneditor/collectionview.cpp | 1 + .../collectioneditor/collectionwidget.cpp | 90 ++++++++++- .../collectioneditor/collectionwidget.h | 11 ++ 13 files changed, 270 insertions(+), 185 deletions(-) rename share/qtcreator/qmldesigner/collectionEditorQmlSource/{CsvImport.qml => ImportDialog.qml} (83%) delete mode 100644 share/qtcreator/qmldesigner/collectionEditorQmlSource/JsonImport.qml create mode 100644 src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.cpp create mode 100644 src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml index c6873460e4b..363d8bab309 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml @@ -24,15 +24,8 @@ Item { warningDialog.open() } - JsonImport { - id: jsonImporter - - backendValue: root.rootView - anchors.centerIn: parent - } - - CsvImport { - id: csvImporter + ImportDialog { + id: importDialog backendValue: root.rootView anchors.centerIn: parent @@ -82,26 +75,14 @@ Item { leftPadding: 15 } - IconTextButton { + HelperWidgets.IconButton { Layout.alignment: Qt.AlignRight | Qt.AlignVCenter icon: StudioTheme.Constants.import_medium - text: qsTr("JSON") - tooltip: qsTr("Import JSON") + tooltip: qsTr("Import a model") radius: StudioTheme.Values.smallRadius - onClicked: jsonImporter.open() - } - - IconTextButton { - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - - icon: StudioTheme.Constants.import_medium - text: qsTr("CSV") - tooltip: qsTr("Import CSV") - radius: StudioTheme.Values.smallRadius - - onClicked: csvImporter.open() + onClicked: importDialog.open() } } diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CsvImport.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ImportDialog.qml similarity index 83% rename from share/qtcreator/qmldesigner/collectionEditorQmlSource/CsvImport.qml rename to share/qtcreator/qmldesigner/collectionEditorQmlSource/ImportDialog.qml index 6bcd6e97a3a..bf28695ec9b 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CsvImport.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ImportDialog.qml @@ -13,7 +13,7 @@ import StudioTheme as StudioTheme StudioControls.Dialog { id: root - title: qsTr("Import A CSV File") + title: qsTr("Import a model") anchors.centerIn: parent closePolicy: Popup.CloseOnEscape modal: true @@ -23,8 +23,8 @@ StudioControls.Dialog { property bool fileExists: false onOpened: { - collectionName.text = "Collection_" - fileName.text = qsTr("New CSV File") + collectionName.text = "Model" + fileName.text = qsTr("Model path") fileName.selectAll() fileName.forceActiveFocus() } @@ -40,6 +40,14 @@ StudioControls.Dialog { PlatformWidgets.FileDialog { id: fileDialog + nameFilters : ["All Model Files (*.json *.csv)", + "JSON Files (*.json)", + "Comma-Separated Values (*.csv)"] + + title: qsTr("Select a model file") + fileMode: PlatformWidgets.FileDialog.OpenFile + acceptLabel: qsTr("Open") + onAccepted: fileName.text = fileDialog.file } @@ -61,7 +69,7 @@ StudioControls.Dialog { spacing: 2 Text { - text: qsTr("File name: ") + text: qsTr("File name") color: StudioTheme.Values.themeTextColor } @@ -80,11 +88,11 @@ StudioControls.Dialog { translationIndicator.visible: false validator: fileNameValidator - Keys.onEnterPressed: btnCreate.onClicked() - Keys.onReturnPressed: btnCreate.onClicked() + Keys.onEnterPressed: btnImport.onClicked() + Keys.onReturnPressed: btnImport.onClicked() Keys.onEscapePressed: root.reject() - onTextChanged: root.fileExists = root.backendValue.isCsvFile(fileName.text) + onTextChanged: root.fileExists = root.backendValue.isValidUrlToImport(fileName.text) } HelperWidgets.Button { @@ -100,7 +108,7 @@ StudioControls.Dialog { Spacer {} Text { - text: qsTr("The model name: ") + text: qsTr("The model name") color: StudioTheme.Values.themeTextColor } @@ -115,8 +123,8 @@ StudioControls.Dialog { regularExpression: /^\w+$/ } - Keys.onEnterPressed: btnCreate.onClicked() - Keys.onReturnPressed: btnCreate.onClicked() + Keys.onEnterPressed: btnImport.onClicked() + Keys.onReturnPressed: btnImport.onClicked() Keys.onEscapePressed: root.reject() } @@ -179,15 +187,17 @@ StudioControls.Dialog { Layout.alignment: Qt.AlignRight | Qt.AlignVCenter HelperWidgets.Button { - id: btnCreate + id: btnImport text: qsTr("Import") enabled: root.fileExists && collectionName.text !== "" onClicked: { - let csvLoaded = root.backendValue.loadCsvFile(fileName.text, collectionName.text) + let collectionImported = root.backendValue.importCollectionToDataStore( + collectionName.text, + fileName.text) - if (csvLoaded) + if (collectionImported) root.accept() else creationFailedDialog.open() diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/JsonImport.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/JsonImport.qml deleted file mode 100644 index fec1155927b..00000000000 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/JsonImport.qml +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright (C) 2023 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 - -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import QtQuickDesignerTheme 1.0 -import Qt.labs.platform as PlatformWidgets -import HelperWidgets 2.0 as HelperWidgets -import StudioControls 1.0 as StudioControls -import StudioTheme as StudioTheme - -StudioControls.Dialog { - id: root - - title: qsTr("Import Models") - anchors.centerIn: parent - closePolicy: Popup.CloseOnEscape - modal: true - - required property var backendValue - property bool fileExists: false - - onOpened: { - fileName.text = qsTr("New JSON File") - fileName.selectAll() - fileName.forceActiveFocus() - } - - onRejected: { - fileName.text = "" - } - - RegularExpressionValidator { - id: fileNameValidator - regularExpression: /^(\w[^*> +#include +#include +#include +#include +#include +#include + +namespace QmlDesigner::CollectionEditor::ImportTools { + +QJsonArray loadAsSingleJsonCollection(const QUrl &url) +{ + QFile file(url.isLocalFile() ? url.toLocalFile() : url.toString()); + QJsonArray collection; + QByteArray jsonData; + if (file.open(QFile::ReadOnly)) + jsonData = file.readAll(); + + file.close(); + if (jsonData.isEmpty()) + return {}; + + QJsonParseError parseError; + QJsonDocument document = QJsonDocument::fromJson(jsonData, &parseError); + if (parseError.error != QJsonParseError::NoError) + return {}; + + auto refineJsonArray = [](const QJsonArray &array) -> QJsonArray { + QJsonArray resultArray; + for (const QJsonValue &collectionData : array) { + if (!collectionData.isObject()) + resultArray.push_back(collectionData); + } + return resultArray; + }; + + if (document.isArray()) { + collection = refineJsonArray(document.array()); + } else if (document.isObject()) { + QJsonObject documentObject = document.object(); + const QStringList mainKeys = documentObject.keys(); + + bool arrayFound = false; + for (const QString &key : mainKeys) { + const QJsonValue &value = documentObject.value(key); + if (value.isArray()) { + arrayFound = true; + collection = refineJsonArray(value.toArray()); + break; + } + } + + if (!arrayFound) { + QJsonObject singleObject; + for (const QString &key : mainKeys) { + const QJsonValue value = documentObject.value(key); + + if (!value.isObject()) + singleObject.insert(key, value); + } + collection.push_back(singleObject); + } + } + return collection; +} + +QJsonArray loadAsCsvCollection(const QUrl &url) +{ + QFile sourceFile(url.isLocalFile() ? url.toLocalFile() : url.toString()); + QStringList headers; + QJsonArray elements; + + if (sourceFile.open(QFile::ReadOnly)) { + QTextStream stream(&sourceFile); + + if (!stream.atEnd()) + headers = stream.readLine().split(','); + + for (QString &header : headers) + header = header.trimmed(); + + if (!headers.isEmpty()) { + while (!stream.atEnd()) { + const QStringList recordDataList = stream.readLine().split(','); + int column = -1; + QJsonObject recordData; + for (const QString &cellData : recordDataList) { + if (++column == headers.size()) + break; + recordData.insert(headers.at(column), cellData); + } + elements.append(recordData); + } + } + } + + return elements; +} + +} // namespace QmlDesigner::CollectionEditor::ImportTools diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h b/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h new file mode 100644 index 00000000000..4ee98284893 --- /dev/null +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h @@ -0,0 +1,16 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +QT_BEGIN_NAMESPACE +class QJsonArray; +class QUrl; +QT_END_NAMESPACE + +namespace QmlDesigner::CollectionEditor::ImportTools { + +QJsonArray loadAsSingleJsonCollection(const QUrl &url); +QJsonArray loadAsCsvCollection(const QUrl &url); + +} // namespace QmlDesigner::CollectionEditor::ImportTools diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp index 12f8dd099c9..098bbdaaa70 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp @@ -268,6 +268,7 @@ bool CollectionSourceModel::collectionExists(const ModelNode &node, const QStrin bool CollectionSourceModel::addCollectionToSource(const ModelNode &node, const QString &collectionName, + const QJsonArray &newCollectionData, QString *errorString) { auto returnError = [errorString](const QString &msg) -> bool { @@ -284,7 +285,7 @@ bool CollectionSourceModel::addCollectionToSource(const ModelNode &node, return returnError(tr("Node should be a JSON model.")); if (collectionExists(node, collectionName)) - return returnError(tr("Model does not exist.")); + return returnError(tr("A model with the identical name already exists.")); QString sourceFileAddress = CollectionEditor::getSourceCollectionPath(node); @@ -305,7 +306,7 @@ bool CollectionSourceModel::addCollectionToSource(const ModelNode &node, if (document.isObject()) { QJsonObject sourceObject = document.object(); - sourceObject.insert(collectionName, CollectionEditor::defaultCollectionArray()); + sourceObject.insert(collectionName, newCollectionData); document.setObject(sourceObject); if (!jsonFile.resize(0)) return returnError(tr("Can't clean \"%1\".").arg(sourceFileInfo.absoluteFilePath())); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h index 28c36d03e01..f0dd517ee10 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h @@ -54,6 +54,7 @@ public: bool collectionExists(const ModelNode &node, const QString &collectionName) const; bool addCollectionToSource(const ModelNode &node, const QString &collectionName, + const QJsonArray &newCollectionData, QString *errorString = nullptr); ModelNode sourceNodeAt(int idx); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp index f9354ddfb0f..de82734b353 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp @@ -23,6 +23,7 @@ #include namespace { + inline bool isStudioCollectionModel(const QmlDesigner::ModelNode &node) { using namespace QmlDesigner::CollectionEditor; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp index 54eeedf7352..2aae651c4ee 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp @@ -6,6 +6,7 @@ #include "collectiondetailsmodel.h" #include "collectiondetailssortfiltermodel.h" #include "collectioneditorutils.h" +#include "collectionimporttools.h" #include "collectionsourcemodel.h" #include "collectionview.h" #include "qmldesignerconstants.h" @@ -188,6 +189,20 @@ bool CollectionWidget::isCsvFile(const QUrl &url) const return file.exists() && file.fileName().endsWith(".csv"); } +bool CollectionWidget::isValidUrlToImport(const QUrl &url) const +{ + using Utils::FilePath; + FilePath fileInfo = FilePath::fromUserInput(url.isLocalFile() ? url.toLocalFile() + : url.toString()); + if (fileInfo.suffix() == "json") + return isJsonFile(url); + + if (fileInfo.suffix() == "csv") + return isCsvFile(url); + + return false; +} + bool CollectionWidget::addCollection(const QString &collectionName, const QString &collectionType, const QUrl &sourceUrl, @@ -243,7 +258,10 @@ bool CollectionWidget::addCollection(const QString &collectionName, } } else if (collectionType == "json") { QString errorMsg; - bool added = m_sourceModel->addCollectionToSource(node, collectionName, &errorMsg); + bool added = m_sourceModel->addCollectionToSource(node, + collectionName, + CollectionEditor::defaultCollectionArray(), + &errorMsg); if (!added) warn(tr("Can not add a model to the JSON file"), errorMsg); return added; @@ -252,6 +270,50 @@ bool CollectionWidget::addCollection(const QString &collectionName, return false; } +bool CollectionWidget::importToJson(const QVariant &sourceNode, + const QString &collectionName, + const QUrl &url) +{ + using CollectionEditor::SourceFormat; + using Utils::FilePath; + const ModelNode node = sourceNode.value(); + const SourceFormat nodeFormat = CollectionEditor::getSourceCollectionFormat(node); + QTC_ASSERT(node.isValid() && nodeFormat == SourceFormat::Json, return false); + + FilePath fileInfo = FilePath::fromUserInput(url.isLocalFile() ? url.toLocalFile() + : url.toString()); + bool added = false; + QString errorMsg; + QJsonArray loadedCollection; + + if (fileInfo.suffix() == "json") + loadedCollection = CollectionEditor::ImportTools::loadAsSingleJsonCollection(url); + else if (fileInfo.suffix() == "csv") + loadedCollection = CollectionEditor::ImportTools::loadAsCsvCollection(url); + + if (!loadedCollection.isEmpty()) { + const QString newCollectionName = generateUniqueCollectionName(node, collectionName); + added = m_sourceModel->addCollectionToSource(node, newCollectionName, loadedCollection, &errorMsg); + } else { + errorMsg = tr("The imported model is empty or is not supported."); + } + + if (!added) + warn(tr("Can not add a model to the JSON file"), errorMsg); + return added; +} + +bool CollectionWidget::importCollectionToDataStore(const QString &collectionName, const QUrl &url) +{ + using Utils::FilePath; + const ModelNode node = dataStoreNode(); + if (node.isValid()) + return importToJson(QVariant::fromValue(node), collectionName, url); + + warn(tr("Can not import to the main model"), tr("The data store is not available.")); + return false; +} + void CollectionWidget::assignSourceNodeToSelectedItem(const QVariant &sourceNode) { ModelNode sourceModel = sourceNode.value(); @@ -268,6 +330,16 @@ void CollectionWidget::assignSourceNodeToSelectedItem(const QVariant &sourceNode CollectionEditor::assignCollectionSourceToNode(m_view, targetNode, sourceModel); } +ModelNode CollectionWidget::dataStoreNode() const +{ + for (int i = 0; i < m_sourceModel->rowCount(); ++i) { + const ModelNode node = m_sourceModel->sourceNodeAt(i); + if (CollectionEditor::getSourceCollectionFormat(node) == CollectionEditor::SourceFormat::Json) + return node; + } + return {}; +} + void CollectionWidget::warn(const QString &title, const QString &body) { QMetaObject::invokeMethod(m_quickWidget->rootObject(), @@ -285,4 +357,20 @@ void CollectionWidget::setTargetNodeSelected(bool selected) emit targetNodeSelectedChanged(m_targetNodeSelected); } +QString CollectionWidget::generateUniqueCollectionName(const ModelNode &node, const QString &name) +{ + if (!m_sourceModel->collectionExists(node, name)) + return name; + + static QRegularExpression reg("^(?[\\w\\d\\.\\_\\-]+)\\_(?\\d+)$"); + QRegularExpressionMatch match = reg.match(name); + if (match.hasMatch()) { + int nextNumber = match.captured("number").toInt() + 1; + return generateUniqueCollectionName( + node, QString("%1_%2").arg(match.captured("mainName")).arg(nextNumber)); + } else { + return generateUniqueCollectionName(node, QString("%1_1").arg(name)); + } +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h index 6be4fabd6ac..142fe9fbd51 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h @@ -38,13 +38,22 @@ public: Q_INVOKABLE bool loadCsvFile(const QUrl &url, const QString &collectionName = {}); Q_INVOKABLE bool isJsonFile(const QUrl &url) const; Q_INVOKABLE bool isCsvFile(const QUrl &url) const; + Q_INVOKABLE bool isValidUrlToImport(const QUrl &url) const; Q_INVOKABLE bool addCollection(const QString &collectionName, const QString &collectionType, const QUrl &sourceUrl, const QVariant &sourceNode); + Q_INVOKABLE bool importToJson(const QVariant &sourceNode, + const QString &collectionName, + const QUrl &url); + + Q_INVOKABLE bool importCollectionToDataStore(const QString &collectionName, const QUrl &url); + Q_INVOKABLE void assignSourceNodeToSelectedItem(const QVariant &sourceNode); + Q_INVOKABLE ModelNode dataStoreNode() const; + void warn(const QString &title, const QString &body); void setTargetNodeSelected(bool selected); @@ -52,6 +61,8 @@ signals: void targetNodeSelectedChanged(bool); private: + QString generateUniqueCollectionName(const ModelNode &node, const QString &name); + QPointer m_view; QPointer m_sourceModel; QPointer m_collectionDetailsModel; From 96ddb5da8b47926bce1389f1bd4190844904e521 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Mon, 20 Nov 2023 15:04:15 +0200 Subject: [PATCH 022/101] QmlDesigner: Remove the options from adding model dialog Task-number: QDS-11234 Change-Id: I064d2fed81a8f2592cfefae2c603b2d790b6bfb3 Reviewed-by: Mahmoud Badri --- .../NewCollectionDialog.qml | 162 +----------------- .../collectioneditor/collectionwidget.cpp | 20 +++ .../collectioneditor/collectionwidget.h | 2 + 3 files changed, 25 insertions(+), 159 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml index bfe985a0f52..50ae55ab722 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml @@ -19,10 +19,7 @@ StudioControls.Dialog { required property var backendValue required property var sourceModel - readonly property alias collectionType: typeMode.collectionType readonly property bool isValid: collectionName.isValid - && jsonCollections.isValid - && newCollectionPath.isValid title: qsTr("Add a new Model") anchors.centerIn: parent @@ -31,8 +28,6 @@ StudioControls.Dialog { onOpened: { collectionName.text = qsTr("Model") - updateType() - updateJsonSourceIndex() updateCollectionExists() } @@ -41,52 +36,12 @@ StudioControls.Dialog { } onAccepted: { - if (root.isValid) { - root.backendValue.addCollection(collectionName.text, - root.collectionType, - newCollectionPath.text, - jsonCollections.currentValue) - - } - } - - function updateType() { - newCollectionPath.text = "" - if (typeMode.currentValue === NewCollectionDialog.SourceType.NewJson) { - newCollectionFileDialog.nameFilters = ["JSON Files (*.json)"] - newCollectionFileDialog.fileMode = PlatformWidgets.FileDialog.SaveFile - newCollectionPath.enabled = true - jsonCollections.enabled = false - typeMode.collectionType = "json" - } else if (typeMode.currentValue === NewCollectionDialog.SourceType.NewCsv) { - newCollectionFileDialog.nameFilters = ["Comma-Separated Values (*.csv)"] - newCollectionFileDialog.fileMode = PlatformWidgets.FileDialog.SaveFile - newCollectionPath.enabled = true - jsonCollections.enabled = false - typeMode.collectionType = "csv" - } else if (typeMode.currentValue === NewCollectionDialog.SourceType.ExistingCollection) { - newCollectionFileDialog.nameFilters = ["All Model Group Files (*.json *.csv)", - "JSON Files (*.json)", - "Comma-Separated Values (*.csv)"] - newCollectionFileDialog.fileMode = PlatformWidgets.FileDialog.OpenFile - newCollectionPath.enabled = true - jsonCollections.enabled = false - typeMode.collectionType = "existing" - } - } - - function updateJsonSourceIndex() { - if (!jsonCollections.enabled) { - jsonCollections.currentIndex = -1 - return - } - - if (jsonCollections.currentIndex === -1 && jsonCollections.model.rowCount()) - jsonCollections.currentIndex = 0 + if (root.isValid) + root.backendValue.addCollectionToDataStore(collectionName.text); } function updateCollectionExists() { - collectionName.alreadyExists = sourceModel.collectionExists(jsonCollections.currentValue, + collectionName.alreadyExists = sourceModel.collectionExists(backendValue.dataStoreNode(), collectionName.text) } @@ -114,117 +69,6 @@ StudioControls.Dialog { contentItem: ColumnLayout { spacing: 5 - NameField { - text: qsTr("Type") - } - - StudioControls.ComboBox { - id: typeMode - - property string collectionType - - Layout.minimumWidth: 300 - Layout.fillWidth: true - - model: ListModel { - ListElement { text: qsTr("New JSON model group"); value: NewCollectionDialog.SourceType.NewJson} - ListElement { text: qsTr("New CSV model"); value: NewCollectionDialog.SourceType.NewCsv} - ListElement { text: qsTr("Import an existing model group"); value: NewCollectionDialog.SourceType.ExistingCollection} - } - - textRole: "text" - valueRole: "value" - actionIndicatorVisible: false - - onCurrentValueChanged: root.updateType() - } - - Spacer {} - - RowLayout { - visible: newCollectionPath.enabled - - NameField { - text: qsTr("File location") - visible: newCollectionPath.enabled - } - - Text { - id: newCollectionPath - - readonly property bool isValid: !newCollectionPath.enabled || newCollectionPath.text !== "" - - Layout.fillWidth: true - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - elide: Text.ElideRight - font.family: StudioTheme.Constants.font.family - font.pixelSize: StudioTheme.Values.baseIconFontSize - color: StudioTheme.Values.themePlaceholderTextColor - } - - HelperWidgets.Button { - Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter - text: qsTr("Select") - - onClicked: newCollectionFileDialog.open() - - PlatformWidgets.FileDialog { - id: newCollectionFileDialog - - title: qsTr("Select source file") - fileMode: PlatformWidgets.FileDialog.OpenFile - acceptLabel: newCollectionFileDialog.fileMode === PlatformWidgets.FileDialog.OpenFile - ? qsTr("Open") - : qsTr("Add") - - onAccepted: newCollectionPath.text = newCollectionFileDialog.currentFile - } - } - } - - ErrorField { - visible: !newCollectionPath.isValid - text: qsTr("Select a file to continue") - } - - Spacer { visible: newCollectionPath.enabled } - - NameField { - text: qsTr("JSON model group") - visible: jsonCollections.enabled - } - - StudioControls.ComboBox { - id: jsonCollections - - readonly property bool isValid: !jsonCollections.enabled || jsonCollections.currentIndex !== -1 - - Layout.fillWidth: true - - implicitWidth: 300 - textRole: "sourceName" - valueRole: "sourceNode" - visible: jsonCollections.enabled - actionIndicatorVisible: false - - model: CollectionJsonSourceFilterModel { - sourceModel: root.sourceModel - onRowsInserted: root.updateJsonSourceIndex() - onModelReset: root.updateJsonSourceIndex() - onRowsRemoved: root.updateJsonSourceIndex() - } - - onEnabledChanged: root.updateJsonSourceIndex() - onCurrentValueChanged: root.updateCollectionExists() - } - - ErrorField { - visible: !jsonCollections.isValid - text: qsTr("Add a JSON resource to continue") - } - - Spacer {visible: jsonCollections.visible } - NameField { text: qsTr("The model name") visible: collectionName.enabled diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp index 2aae651c4ee..7e5d4268302 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp @@ -314,6 +314,26 @@ bool CollectionWidget::importCollectionToDataStore(const QString &collectionName return false; } +bool CollectionWidget::addCollectionToDataStore(const QString &collectionName) +{ + const ModelNode node = dataStoreNode(); + if (!node.isValid()) { + warn(tr("Can not import to the main model"), tr("The default model node is not available.")); + return false; + } + + QString errorMsg; + bool added = m_sourceModel->addCollectionToSource(node, + generateUniqueCollectionName(node, + collectionName), + CollectionEditor::defaultCollectionArray(), + &errorMsg); + if (!added) + warn(tr("Failed to add a model to the default model group"), errorMsg); + + return added; +} + void CollectionWidget::assignSourceNodeToSelectedItem(const QVariant &sourceNode) { ModelNode sourceModel = sourceNode.value(); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h index 142fe9fbd51..03cf49aa7e3 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h @@ -50,6 +50,8 @@ public: Q_INVOKABLE bool importCollectionToDataStore(const QString &collectionName, const QUrl &url); + Q_INVOKABLE bool addCollectionToDataStore(const QString &collectionName); + Q_INVOKABLE void assignSourceNodeToSelectedItem(const QVariant &sourceNode); Q_INVOKABLE ModelNode dataStoreNode() const; From 10792b1eb31b80fdad97f5fdaf820b59ef2a5346 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 20 Nov 2023 17:38:25 +0200 Subject: [PATCH 023/101] EffectMaker: Fix effect node deletion Now the correct node is deleted. Fixes: QDS-11330 Change-Id: Id7402ea6b4f258d32e851de2118e53f26a6c632a Reviewed-by: Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Patch Build Bot --- .../effectMakerQmlSources/EffectCompositionNode.qml | 4 +++- .../qmldesigner/effectMakerQmlSources/EffectMaker.qml | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml index 56a508377ec..cf9c3d668b0 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml @@ -12,6 +12,8 @@ import EffectMakerBackend HelperWidgets.Section { id: root + property int modelIndex: 0 + caption: nodeName category: "EffectMaker" @@ -21,7 +23,7 @@ HelperWidgets.Section { closeButtonToolTip: qsTr("Remove") onCloseButtonClicked: { - EffectMakerBackend.effectMakerModel.removeNode(root.index) + EffectMakerBackend.effectMakerModel.removeNode(root.modelIndex) } showEyeButton: true diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index a60b41acf31..3476b084552 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -96,6 +96,7 @@ Item { delegate: EffectCompositionNode { width: root.width + modelIndex: index Behavior on y { PropertyAnimation { From b14037f5372961b65f400a6884fcc1f28ed096e7 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Tue, 21 Nov 2023 10:58:26 +0200 Subject: [PATCH 024/101] QmlDesigner: Add clearList icon to icon font Change-Id: Ib60120dccca106e723d7eb2fe21ef574de62605a Reviewed-by: Miikka Heikkinen --- .../imports/StudioTheme/InternalConstants.qml | 590 +++++++++--------- .../imports/StudioTheme/icons.ttf | Bin 65152 -> 65816 bytes .../components/componentcore/theme.h | 2 + 3 files changed, 298 insertions(+), 294 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml index 1f7351a8a00..92a9206f5bd 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml @@ -79,300 +79,302 @@ QtObject { readonly property string centerHorizontal: "\u0060" readonly property string centerVertical: "\u0061" readonly property string cleanLogs_medium: "\u0062" - readonly property string closeCross: "\u0063" - readonly property string closeFile_large: "\u0064" - readonly property string closeLink: "\u0065" - readonly property string close_small: "\u0066" - readonly property string code: "\u0067" - readonly property string codeEditor_medium: "\u0068" - readonly property string codeview_medium: "\u0069" - readonly property string colorPopupClose: "\u006A" - readonly property string colorSelection_medium: "\u006B" - readonly property string columnsAndRows: "\u006C" - readonly property string comboBox_medium: "\u006D" - readonly property string cone_medium: "\u006E" - readonly property string cone_small: "\u006F" - readonly property string connection_small: "\u0070" - readonly property string connections_medium: "\u0071" - readonly property string copyLink: "\u0072" - readonly property string copyStyle: "\u0073" - readonly property string copy_small: "\u0074" - readonly property string cornerA: "\u0075" - readonly property string cornerB: "\u0076" - readonly property string cornersAll: "\u0077" - readonly property string createComponent_large: "\u0078" - readonly property string createComponent_small: "\u0079" - readonly property string createObject_medium: "\u007A" - readonly property string create_medium: "\u007B" - readonly property string create_small: "\u007C" - readonly property string cube_medium: "\u007D" - readonly property string cube_small: "\u007E" - readonly property string curveDesigner: "\u007F" - readonly property string curveDesigner_medium: "\u0080" - readonly property string curveEditor: "\u0081" - readonly property string customMaterialEditor: "\u0082" - readonly property string cylinder_medium: "\u0083" - readonly property string cylinder_small: "\u0084" - readonly property string decisionNode: "\u0085" - readonly property string deleteColumn: "\u0086" - readonly property string deleteMaterial: "\u0087" - readonly property string deleteRow: "\u0088" - readonly property string deleteTable: "\u0089" - readonly property string delete_medium: "\u008A" - readonly property string delete_small: "\u008B" - readonly property string deletecolumn_medium: "\u008C" - readonly property string deletepermanently_medium: "\u008D" - readonly property string deleterow_medium: "\u008E" - readonly property string designMode_large: "\u008F" - readonly property string detach: "\u0090" - readonly property string directionalLight_small: "\u0091" - readonly property string distributeBottom: "\u0092" - readonly property string distributeCenterHorizontal: "\u0093" - readonly property string distributeCenterVertical: "\u0094" - readonly property string distributeLeft: "\u0095" - readonly property string distributeOriginBottomRight: "\u0096" - readonly property string distributeOriginCenter: "\u0097" - readonly property string distributeOriginNone: "\u0098" - readonly property string distributeOriginTopLeft: "\u0099" - readonly property string distributeRight: "\u009A" - readonly property string distributeSpacingHorizontal: "\u009B" - readonly property string distributeSpacingVertical: "\u009D" - readonly property string distributeTop: "\u009E" - readonly property string download: "\u009F" - readonly property string downloadUnavailable: "\u00A0" - readonly property string downloadUpdate: "\u00A1" - readonly property string downloaded: "\u00A2" - readonly property string dragmarks: "\u00A3" - readonly property string duplicate_small: "\u00A4" - readonly property string edit: "\u00A5" - readonly property string editComponent_large: "\u00A6" - readonly property string editComponent_small: "\u00A7" - readonly property string editLightOff_medium: "\u00A8" - readonly property string editLightOn_medium: "\u00A9" - readonly property string edit_medium: "\u00AA" - readonly property string edit_small: "\u00AB" - readonly property string effects: "\u00AC" - readonly property string events_small: "\u00AE" - readonly property string export_medium: "\u00AF" - readonly property string eyeDropper: "\u00B0" - readonly property string favorite: "\u00B1" - readonly property string fitAll_medium: "\u00B2" - readonly property string fitSelected_small: "\u00B3" - readonly property string fitSelection_medium: "\u00B4" - readonly property string fitToView_medium: "\u00B5" - readonly property string flowAction: "\u00B6" - readonly property string flowTransition: "\u00B7" - readonly property string fontStyleBold: "\u00B8" - readonly property string fontStyleItalic: "\u00B9" - readonly property string fontStyleStrikethrough: "\u00BA" - readonly property string fontStyleUnderline: "\u00BB" - readonly property string forward_medium: "\u00BC" - readonly property string globalOrient_medium: "\u00BD" - readonly property string gradient: "\u00BE" - readonly property string gridView: "\u00BF" - readonly property string grid_medium: "\u00C0" - readonly property string group_small: "\u00C1" - readonly property string help: "\u00C2" - readonly property string home_large: "\u00C3" - readonly property string idAliasOff: "\u00C4" - readonly property string idAliasOn: "\u00C5" - readonly property string import_medium: "\u00C6" - readonly property string imported: "\u00C7" - readonly property string importedModels_small: "\u00C8" - readonly property string infinity: "\u00C9" - readonly property string invisible_medium: "\u00CA" - readonly property string invisible_small: "\u00CB" - readonly property string jumpToCode_medium: "\u00CC" - readonly property string jumpToCode_small: "\u00CD" - readonly property string keyframe: "\u00CE" - readonly property string languageList_medium: "\u00CF" - readonly property string layouts_small: "\u00D0" - readonly property string lights_small: "\u00D1" - readonly property string linear_medium: "\u00D2" - readonly property string linkTriangle: "\u00D3" - readonly property string linked: "\u00D4" - readonly property string listView: "\u00D5" - readonly property string listView_medium: "\u00D6" - readonly property string list_medium: "\u00D7" - readonly property string localOrient_medium: "\u00D8" - readonly property string lockOff: "\u00D9" - readonly property string lockOn: "\u00DA" - readonly property string loopPlayback_medium: "\u00DB" - readonly property string materialBrowser_medium: "\u00DC" - readonly property string materialPreviewEnvironment: "\u00DD" - readonly property string materialPreviewModel: "\u00DE" - readonly property string material_medium: "\u00DF" - readonly property string maxBar_small: "\u00E0" - readonly property string mergeCells: "\u00E1" - readonly property string merge_small: "\u00E2" - readonly property string minus: "\u00E3" - readonly property string mirror: "\u00E4" - readonly property string more_medium: "\u00E5" - readonly property string mouseArea_small: "\u00E6" - readonly property string moveDown_medium: "\u00E7" - readonly property string moveInwards_medium: "\u00E8" - readonly property string moveUp_medium: "\u00E9" - readonly property string moveUpwards_medium: "\u00EA" - readonly property string move_medium: "\u00EB" - readonly property string newMaterial: "\u00EC" - readonly property string nextFile_large: "\u00ED" - readonly property string normalBar_small: "\u00EE" - readonly property string openLink: "\u00EF" - readonly property string openMaterialBrowser: "\u00F0" - readonly property string orientation: "\u00F1" - readonly property string orthCam_medium: "\u00F2" - readonly property string orthCam_small: "\u00F3" - readonly property string paddingEdge: "\u00F4" - readonly property string paddingFrame: "\u00F5" - readonly property string particleAnimation_medium: "\u00F6" - readonly property string pasteStyle: "\u00F7" - readonly property string paste_small: "\u00F8" - readonly property string pause: "\u00F9" - readonly property string pause_medium: "\u00FA" - readonly property string perspectiveCam_medium: "\u00FB" - readonly property string perspectiveCam_small: "\u00FC" - readonly property string pin: "\u00FD" - readonly property string plane_medium: "\u00FE" - readonly property string plane_small: "\u00FF" - readonly property string play: "\u0100" - readonly property string playFill_medium: "\u0101" - readonly property string playOutline_medium: "\u0102" - readonly property string plus: "\u0103" - readonly property string pointLight_small: "\u0104" - readonly property string positioners_small: "\u0105" - readonly property string previewEnv_medium: "\u0106" - readonly property string previousFile_large: "\u0107" - readonly property string promote: "\u0108" - readonly property string properties_medium: "\u0109" - readonly property string readOnly: "\u010A" - readonly property string recent_medium: "\u010B" - readonly property string recordFill_medium: "\u010C" - readonly property string recordOutline_medium: "\u010D" - readonly property string redo: "\u010E" - readonly property string reload_medium: "\u010F" - readonly property string remove_medium: "\u0110" - readonly property string remove_small: "\u0111" - readonly property string rename_small: "\u0112" - readonly property string replace_small: "\u0113" - readonly property string resetView_small: "\u0114" - readonly property string restartParticles_medium: "\u0115" - readonly property string reverseOrder_medium: "\u0116" - readonly property string roatate_medium: "\u0117" - readonly property string rotationFill: "\u0118" - readonly property string rotationOutline: "\u0119" - readonly property string runProjFill_large: "\u011A" - readonly property string runProjOutline_large: "\u011B" - readonly property string s_anchors: "\u011C" - readonly property string s_annotations: "\u011D" - readonly property string s_arrange: "\u011E" - readonly property string s_boundingBox: "\u011F" - readonly property string s_component: "\u0120" - readonly property string s_connections: "\u0121" - readonly property string s_edit: "\u0122" - readonly property string s_enterComponent: "\u0123" - readonly property string s_eventList: "\u0124" - readonly property string s_group: "\u0125" - readonly property string s_layouts: "\u0126" - readonly property string s_merging: "\u0127" - readonly property string s_mouseArea: "\u0128" - readonly property string s_positioners: "\u0129" - readonly property string s_selection: "\u012A" - readonly property string s_snapping: "\u012B" - readonly property string s_timeline: "\u012C" - readonly property string s_visibility: "\u012D" - readonly property string saveLogs_medium: "\u012E" - readonly property string scale_medium: "\u012F" - readonly property string search: "\u0130" - readonly property string search_small: "\u0131" - readonly property string sectionToggle: "\u0132" - readonly property string selectFill_medium: "\u0133" - readonly property string selectOutline_medium: "\u0134" - readonly property string selectParent_small: "\u0135" - readonly property string selection_small: "\u0136" - readonly property string settings_medium: "\u0137" - readonly property string signal_small: "\u0138" - readonly property string snapping_conf_medium: "\u0139" - readonly property string snapping_medium: "\u013A" - readonly property string snapping_small: "\u013B" - readonly property string sortascending_medium: "\u013C" - readonly property string sortdescending_medium: "\u013D" - readonly property string sphere_medium: "\u013E" - readonly property string sphere_small: "\u013F" - readonly property string splitColumns: "\u0140" - readonly property string splitRows: "\u0141" - readonly property string splitScreen_medium: "\u0142" - readonly property string spotLight_small: "\u0143" - readonly property string stackedContainer_small: "\u0144" - readonly property string startNode: "\u0145" - readonly property string step_medium: "\u0146" - readonly property string stop_medium: "\u0147" - readonly property string tableView_medium: "\u0148" - readonly property string testIcon: "\u0149" - readonly property string textAlignBottom: "\u014A" - readonly property string textAlignCenter: "\u014B" - readonly property string textAlignJustified: "\u014C" - readonly property string textAlignLeft: "\u014D" - readonly property string textAlignMiddle: "\u014E" - readonly property string textAlignRight: "\u014F" - readonly property string textAlignTop: "\u0150" - readonly property string textBulletList: "\u0151" - readonly property string textFullJustification: "\u0152" - readonly property string textNumberedList: "\u0153" - readonly property string textures_medium: "\u0154" - readonly property string tickIcon: "\u0155" - readonly property string tickMark_small: "\u0156" - readonly property string timeline_small: "\u0157" - readonly property string toEndFrame_medium: "\u0158" - readonly property string toNextFrame_medium: "\u0159" - readonly property string toPrevFrame_medium: "\u015A" - readonly property string toStartFrame_medium: "\u015B" - readonly property string topToolbar_annotations: "\u015C" - readonly property string topToolbar_closeFile: "\u015D" - readonly property string topToolbar_designMode: "\u015E" - readonly property string topToolbar_enterComponent: "\u015F" - readonly property string topToolbar_home: "\u0160" - readonly property string topToolbar_makeComponent: "\u0161" - readonly property string topToolbar_navFile: "\u0162" - readonly property string topToolbar_runProject: "\u0163" - readonly property string translationCreateFiles: "\u0164" - readonly property string translationCreateReport: "\u0165" - readonly property string translationExport: "\u0166" - readonly property string translationImport: "\u0167" - readonly property string translationSelectLanguages: "\u0168" - readonly property string translationTest: "\u0169" - readonly property string transparent: "\u016A" - readonly property string triState: "\u016B" - readonly property string triangleArcA: "\u016C" - readonly property string triangleArcB: "\u016D" - readonly property string triangleCornerA: "\u016E" - readonly property string triangleCornerB: "\u016F" - readonly property string unLinked: "\u0170" - readonly property string undo: "\u0171" - readonly property string unify_medium: "\u0172" - readonly property string unpin: "\u0173" - readonly property string upDownIcon: "\u0174" - readonly property string upDownSquare2: "\u0175" - readonly property string updateAvailable_medium: "\u0176" - readonly property string updateContent_medium: "\u0177" - readonly property string visibilityOff: "\u0178" - readonly property string visibilityOn: "\u0179" - readonly property string visible_medium: "\u017A" - readonly property string visible_small: "\u017B" - readonly property string warning_medium: "\u017C" - readonly property string wildcard: "\u017D" - readonly property string wizardsAutomotive: "\u017E" - readonly property string wizardsDesktop: "\u017F" - readonly property string wizardsGeneric: "\u0180" - readonly property string wizardsMcuEmpty: "\u0181" - readonly property string wizardsMcuGraph: "\u0182" - readonly property string wizardsMobile: "\u0183" - readonly property string wizardsUnknown: "\u0184" - readonly property string zoomAll: "\u0185" - readonly property string zoomIn: "\u0186" - readonly property string zoomIn_medium: "\u0187" - readonly property string zoomOut: "\u0188" - readonly property string zoomOut_medium: "\u0189" - readonly property string zoomSelection: "\u018A" + readonly property string clearList_large: "\u0063" + readonly property string clearList_medium: "\u0064" + readonly property string closeCross: "\u0065" + readonly property string closeFile_large: "\u0066" + readonly property string closeLink: "\u0067" + readonly property string close_small: "\u0068" + readonly property string code: "\u0069" + readonly property string codeEditor_medium: "\u006A" + readonly property string codeview_medium: "\u006B" + readonly property string colorPopupClose: "\u006C" + readonly property string colorSelection_medium: "\u006D" + readonly property string columnsAndRows: "\u006E" + readonly property string comboBox_medium: "\u006F" + readonly property string cone_medium: "\u0070" + readonly property string cone_small: "\u0071" + readonly property string connection_small: "\u0072" + readonly property string connections_medium: "\u0073" + readonly property string copyLink: "\u0074" + readonly property string copyStyle: "\u0075" + readonly property string copy_small: "\u0076" + readonly property string cornerA: "\u0077" + readonly property string cornerB: "\u0078" + readonly property string cornersAll: "\u0079" + readonly property string createComponent_large: "\u007A" + readonly property string createComponent_small: "\u007B" + readonly property string createObject_medium: "\u007C" + readonly property string create_medium: "\u007D" + readonly property string create_small: "\u007E" + readonly property string cube_medium: "\u007F" + readonly property string cube_small: "\u0080" + readonly property string curveDesigner: "\u0081" + readonly property string curveDesigner_medium: "\u0082" + readonly property string curveEditor: "\u0083" + readonly property string customMaterialEditor: "\u0084" + readonly property string cylinder_medium: "\u0085" + readonly property string cylinder_small: "\u0086" + readonly property string decisionNode: "\u0087" + readonly property string deleteColumn: "\u0088" + readonly property string deleteMaterial: "\u0089" + readonly property string deleteRow: "\u008A" + readonly property string deleteTable: "\u008B" + readonly property string delete_medium: "\u008C" + readonly property string delete_small: "\u008D" + readonly property string deletecolumn_medium: "\u008E" + readonly property string deletepermanently_medium: "\u008F" + readonly property string deleterow_medium: "\u0090" + readonly property string designMode_large: "\u0091" + readonly property string detach: "\u0092" + readonly property string directionalLight_small: "\u0093" + readonly property string distributeBottom: "\u0094" + readonly property string distributeCenterHorizontal: "\u0095" + readonly property string distributeCenterVertical: "\u0096" + readonly property string distributeLeft: "\u0097" + readonly property string distributeOriginBottomRight: "\u0098" + readonly property string distributeOriginCenter: "\u0099" + readonly property string distributeOriginNone: "\u009A" + readonly property string distributeOriginTopLeft: "\u009B" + readonly property string distributeRight: "\u009D" + readonly property string distributeSpacingHorizontal: "\u009E" + readonly property string distributeSpacingVertical: "\u009F" + readonly property string distributeTop: "\u00A0" + readonly property string download: "\u00A1" + readonly property string downloadUnavailable: "\u00A2" + readonly property string downloadUpdate: "\u00A3" + readonly property string downloaded: "\u00A4" + readonly property string dragmarks: "\u00A5" + readonly property string duplicate_small: "\u00A6" + readonly property string edit: "\u00A7" + readonly property string editComponent_large: "\u00A8" + readonly property string editComponent_small: "\u00A9" + readonly property string editLightOff_medium: "\u00AA" + readonly property string editLightOn_medium: "\u00AB" + readonly property string edit_medium: "\u00AC" + readonly property string edit_small: "\u00AE" + readonly property string effects: "\u00AF" + readonly property string events_small: "\u00B0" + readonly property string export_medium: "\u00B1" + readonly property string eyeDropper: "\u00B2" + readonly property string favorite: "\u00B3" + readonly property string fitAll_medium: "\u00B4" + readonly property string fitSelected_small: "\u00B5" + readonly property string fitSelection_medium: "\u00B6" + readonly property string fitToView_medium: "\u00B7" + readonly property string flowAction: "\u00B8" + readonly property string flowTransition: "\u00B9" + readonly property string fontStyleBold: "\u00BA" + readonly property string fontStyleItalic: "\u00BB" + readonly property string fontStyleStrikethrough: "\u00BC" + readonly property string fontStyleUnderline: "\u00BD" + readonly property string forward_medium: "\u00BE" + readonly property string globalOrient_medium: "\u00BF" + readonly property string gradient: "\u00C0" + readonly property string gridView: "\u00C1" + readonly property string grid_medium: "\u00C2" + readonly property string group_small: "\u00C3" + readonly property string help: "\u00C4" + readonly property string home_large: "\u00C5" + readonly property string idAliasOff: "\u00C6" + readonly property string idAliasOn: "\u00C7" + readonly property string import_medium: "\u00C8" + readonly property string imported: "\u00C9" + readonly property string importedModels_small: "\u00CA" + readonly property string infinity: "\u00CB" + readonly property string invisible_medium: "\u00CC" + readonly property string invisible_small: "\u00CD" + readonly property string jumpToCode_medium: "\u00CE" + readonly property string jumpToCode_small: "\u00CF" + readonly property string keyframe: "\u00D0" + readonly property string languageList_medium: "\u00D1" + readonly property string layouts_small: "\u00D2" + readonly property string lights_small: "\u00D3" + readonly property string linear_medium: "\u00D4" + readonly property string linkTriangle: "\u00D5" + readonly property string linked: "\u00D6" + readonly property string listView: "\u00D7" + readonly property string listView_medium: "\u00D8" + readonly property string list_medium: "\u00D9" + readonly property string localOrient_medium: "\u00DA" + readonly property string lockOff: "\u00DB" + readonly property string lockOn: "\u00DC" + readonly property string loopPlayback_medium: "\u00DD" + readonly property string materialBrowser_medium: "\u00DE" + readonly property string materialPreviewEnvironment: "\u00DF" + readonly property string materialPreviewModel: "\u00E0" + readonly property string material_medium: "\u00E1" + readonly property string maxBar_small: "\u00E2" + readonly property string mergeCells: "\u00E3" + readonly property string merge_small: "\u00E4" + readonly property string minus: "\u00E5" + readonly property string mirror: "\u00E6" + readonly property string more_medium: "\u00E7" + readonly property string mouseArea_small: "\u00E8" + readonly property string moveDown_medium: "\u00E9" + readonly property string moveInwards_medium: "\u00EA" + readonly property string moveUp_medium: "\u00EB" + readonly property string moveUpwards_medium: "\u00EC" + readonly property string move_medium: "\u00ED" + readonly property string newMaterial: "\u00EE" + readonly property string nextFile_large: "\u00EF" + readonly property string normalBar_small: "\u00F0" + readonly property string openLink: "\u00F1" + readonly property string openMaterialBrowser: "\u00F2" + readonly property string orientation: "\u00F3" + readonly property string orthCam_medium: "\u00F4" + readonly property string orthCam_small: "\u00F5" + readonly property string paddingEdge: "\u00F6" + readonly property string paddingFrame: "\u00F7" + readonly property string particleAnimation_medium: "\u00F8" + readonly property string pasteStyle: "\u00F9" + readonly property string paste_small: "\u00FA" + readonly property string pause: "\u00FB" + readonly property string pause_medium: "\u00FC" + readonly property string perspectiveCam_medium: "\u00FD" + readonly property string perspectiveCam_small: "\u00FE" + readonly property string pin: "\u00FF" + readonly property string plane_medium: "\u0100" + readonly property string plane_small: "\u0101" + readonly property string play: "\u0102" + readonly property string playFill_medium: "\u0103" + readonly property string playOutline_medium: "\u0104" + readonly property string plus: "\u0105" + readonly property string pointLight_small: "\u0106" + readonly property string positioners_small: "\u0107" + readonly property string previewEnv_medium: "\u0108" + readonly property string previousFile_large: "\u0109" + readonly property string promote: "\u010A" + readonly property string properties_medium: "\u010B" + readonly property string readOnly: "\u010C" + readonly property string recent_medium: "\u010D" + readonly property string recordFill_medium: "\u010E" + readonly property string recordOutline_medium: "\u010F" + readonly property string redo: "\u0110" + readonly property string reload_medium: "\u0111" + readonly property string remove_medium: "\u0112" + readonly property string remove_small: "\u0113" + readonly property string rename_small: "\u0114" + readonly property string replace_small: "\u0115" + readonly property string resetView_small: "\u0116" + readonly property string restartParticles_medium: "\u0117" + readonly property string reverseOrder_medium: "\u0118" + readonly property string roatate_medium: "\u0119" + readonly property string rotationFill: "\u011A" + readonly property string rotationOutline: "\u011B" + readonly property string runProjFill_large: "\u011C" + readonly property string runProjOutline_large: "\u011D" + readonly property string s_anchors: "\u011E" + readonly property string s_annotations: "\u011F" + readonly property string s_arrange: "\u0120" + readonly property string s_boundingBox: "\u0121" + readonly property string s_component: "\u0122" + readonly property string s_connections: "\u0123" + readonly property string s_edit: "\u0124" + readonly property string s_enterComponent: "\u0125" + readonly property string s_eventList: "\u0126" + readonly property string s_group: "\u0127" + readonly property string s_layouts: "\u0128" + readonly property string s_merging: "\u0129" + readonly property string s_mouseArea: "\u012A" + readonly property string s_positioners: "\u012B" + readonly property string s_selection: "\u012C" + readonly property string s_snapping: "\u012D" + readonly property string s_timeline: "\u012E" + readonly property string s_visibility: "\u012F" + readonly property string saveLogs_medium: "\u0130" + readonly property string scale_medium: "\u0131" + readonly property string search: "\u0132" + readonly property string search_small: "\u0133" + readonly property string sectionToggle: "\u0134" + readonly property string selectFill_medium: "\u0135" + readonly property string selectOutline_medium: "\u0136" + readonly property string selectParent_small: "\u0137" + readonly property string selection_small: "\u0138" + readonly property string settings_medium: "\u0139" + readonly property string signal_small: "\u013A" + readonly property string snapping_conf_medium: "\u013B" + readonly property string snapping_medium: "\u013C" + readonly property string snapping_small: "\u013D" + readonly property string sortascending_medium: "\u013E" + readonly property string sortdescending_medium: "\u013F" + readonly property string sphere_medium: "\u0140" + readonly property string sphere_small: "\u0141" + readonly property string splitColumns: "\u0142" + readonly property string splitRows: "\u0143" + readonly property string splitScreen_medium: "\u0144" + readonly property string spotLight_small: "\u0145" + readonly property string stackedContainer_small: "\u0146" + readonly property string startNode: "\u0147" + readonly property string step_medium: "\u0148" + readonly property string stop_medium: "\u0149" + readonly property string tableView_medium: "\u014A" + readonly property string testIcon: "\u014B" + readonly property string textAlignBottom: "\u014C" + readonly property string textAlignCenter: "\u014D" + readonly property string textAlignJustified: "\u014E" + readonly property string textAlignLeft: "\u014F" + readonly property string textAlignMiddle: "\u0150" + readonly property string textAlignRight: "\u0151" + readonly property string textAlignTop: "\u0152" + readonly property string textBulletList: "\u0153" + readonly property string textFullJustification: "\u0154" + readonly property string textNumberedList: "\u0155" + readonly property string textures_medium: "\u0156" + readonly property string tickIcon: "\u0157" + readonly property string tickMark_small: "\u0158" + readonly property string timeline_small: "\u0159" + readonly property string toEndFrame_medium: "\u015A" + readonly property string toNextFrame_medium: "\u015B" + readonly property string toPrevFrame_medium: "\u015C" + readonly property string toStartFrame_medium: "\u015D" + readonly property string topToolbar_annotations: "\u015E" + readonly property string topToolbar_closeFile: "\u015F" + readonly property string topToolbar_designMode: "\u0160" + readonly property string topToolbar_enterComponent: "\u0161" + readonly property string topToolbar_home: "\u0162" + readonly property string topToolbar_makeComponent: "\u0163" + readonly property string topToolbar_navFile: "\u0164" + readonly property string topToolbar_runProject: "\u0165" + readonly property string translationCreateFiles: "\u0166" + readonly property string translationCreateReport: "\u0167" + readonly property string translationExport: "\u0168" + readonly property string translationImport: "\u0169" + readonly property string translationSelectLanguages: "\u016A" + readonly property string translationTest: "\u016B" + readonly property string transparent: "\u016C" + readonly property string triState: "\u016D" + readonly property string triangleArcA: "\u016E" + readonly property string triangleArcB: "\u016F" + readonly property string triangleCornerA: "\u0170" + readonly property string triangleCornerB: "\u0171" + readonly property string unLinked: "\u0172" + readonly property string undo: "\u0173" + readonly property string unify_medium: "\u0174" + readonly property string unpin: "\u0175" + readonly property string upDownIcon: "\u0176" + readonly property string upDownSquare2: "\u0177" + readonly property string updateAvailable_medium: "\u0178" + readonly property string updateContent_medium: "\u0179" + readonly property string visibilityOff: "\u017A" + readonly property string visibilityOn: "\u017B" + readonly property string visible_medium: "\u017C" + readonly property string visible_small: "\u017D" + readonly property string warning_medium: "\u017E" + readonly property string wildcard: "\u017F" + readonly property string wizardsAutomotive: "\u0180" + readonly property string wizardsDesktop: "\u0181" + readonly property string wizardsGeneric: "\u0182" + readonly property string wizardsMcuEmpty: "\u0183" + readonly property string wizardsMcuGraph: "\u0184" + readonly property string wizardsMobile: "\u0185" + readonly property string wizardsUnknown: "\u0186" + readonly property string zoomAll: "\u0187" + readonly property string zoomIn: "\u0188" + readonly property string zoomIn_medium: "\u0189" + readonly property string zoomOut: "\u018A" + readonly property string zoomOut_medium: "\u018B" + readonly property string zoomSelection: "\u018C" readonly property font iconFont: Qt.font({ "family": controlIcons.name, diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf index c622c1950af00d87bcc5bd0c6007d1f297d169a8..e5a2ca18235a69b6c7b3a4b55aa0a0b8bb1f82c9 100644 GIT binary patch delta 1570 zcmZqp%RHlrrJjM2fq{XSp@D&!A;8To#CIWA#!?1GhCd7p3^M+~`bLop(kvJl7$X=M z7!s0m6AQG$b;KALSmrP=Foh+Tl_)SMGF37#uzg`*U|>m4EH3!}pMjZykpaZ#NYANE zYl=Akn1O-w3IoHn9T};KDVlwajnb5jqhuT*7Vc+kVZz;wAFzqn*hOmQOv!{Y=72H8nq zKQJ;dNM7*|kLS1f%D~P1f`Ng7;bD`!G>o3aXv>&8*^V)mv1jre#`Vk$3=EsSm};3A zdp4h7*~wJDPdGrhO?Z#+ClNi729bB7A);ks5@H5obz+;u9*L`n=ZHU&kdnxgSR}DS z;+LeKlz~){)DdYu=_=_@GA=S3WHn^x$o`XylA9oROrAsDPCiF|odSnKm%=GUKP3yL zY06H@Vaj>RZOU_$4=I09;ZZSCaZ^cBsZ*Jx@wWeNmj~bg=n%X+GPwFn}Cp6SF ziZpg<@@W=n?$P4XQq#)PI-+f$eMtL-j+IW9PJ_-Vogcaix>dT@^mz2P=snXf)4yUM zVi01mz+j)DgW)8@H%1;tO-6@|ZW+%qeqdr^(quBj*7S)dj0x)*9Af*2ip^Y_x1LZ1&k|*=E_Evoo@@vkS6& zW-n%6Vc%o_!XeAyjiZTUmg5q~O^#Z0DTeJj?lpOM=S*ms_q}u1>Bs zu9I9>xv{vVxJ`0ra1U_rbKmFw!h_4h!DExhGtU^$Z(bf=9ra!pyv@94d7tqS@hR|` z;d95=#JA1&lplv*jNb)+7JnOmFaJFMHU3`$0s?gcF9kIPT?^I;o)y9sk`l5k!}<%#_hmlby^K3FE+ExsoHP=Z=QO2VQo! zE8`y4fA*wGFqW6G^NFyRm9dNPfk-%;SwT*8HOP|HqH_0Ev$3sa?T`~)BPv%9Ccz?X z9Y{*nu(GaUWxR`OjxayeOi<261fD#D5rYMT2ZJ9&9775N1EaFImLGn$)$e9MR&e)UWyX2u4r#^&mZ?Bd80;84dc${fMi#>K_K%gfo`#=*xU%-P<~ zDJ;p=*2X0%%=ssgu~bS`Rq9{2w5qBUV<{seC*Qtr$7EzUS^B{*#@x+f53ez?Fl8}iZ+`Q56N{X1a!zVukxyoENqkOX bQF^Lgaapm4EH3!}pMjZy;a>~`0|Q5T zPG#D%3eHLf2F^1K3|B%jQWH}&>lNG?7#Qv_Fff>9WTZ~4mr1>slb@WpSnfsz0|VO^ z1_q`Zxrr48jHemCGcYh(FfcGEfq{YPazTD^iFrb?D+9xWFANN_ zsbD`aGB7CZdZH80Z}XLboB0I;0|Udus=Q_xJ&DnlF?+HdV=QCWMPIijyH8~zRE4doEYw{8DGZbVL*%VWh1e8>i zY?MNjvXmw$9a6fb%%CiyY@qC;oS?i-`JalHN|(x&dQ}tE8r1`8LTc00zNkB>cc|ad zaM0+|xS{by(?WBS=0B|oTHCZav@Nv#v}b4^(|)Jpp|eEimTr^o7CjfeMS73)mGtxU zdkpvt5)5`3iWvqNPB2_ylwq{an8`T6IL&yC36DvM$q`c-(*)CHW?W`#%;n6BEF>(P zEV?Y-Sh85w%UOC@7Ff=+JYo6GO2ul5)di~`)@If{)<0}4Z06W9*z(va*lw|XV&`TT zWw*`V!hV+nlY@mrkwb&SEQdV~uN-q6H#qS)nK@-REpyg$?sHz@e8WY+#mgnZrNZTs ztC4Gh>p3?$w-~n`w{31W-1*!a+_!jWc^vT+^9=Kx=fzU*mEkqZ>yfvecbfMqA10p= zpBX;ae6@V%`Cjtl@{{nh@vHJX{Pf&ctZHL2&RaLh%J!}k#nNhqO_tyqGm*$iux065SGm& zsaT8H8L_Y8MB@Ct;wHp>i8qQbh<}qHme7(gCt+K{g@iYWN{I=HGm`j{7A5UVx|Gb4 z?3R2Y#Vn;HWl_qbRFgEJw4Stm>1OFmGB`2{GEQakWX5IA$h?)MwfPFCt;*(7gYz4i z4H--)yFaqyGBnjSG}JXRFfyJj@Hk-d{YQ%!vo|+AzQ(jU=Gi8e&E~HUh$=BK{{PRw T#J~Vf%?$V0wDMqS7e)gB8qPfg diff --git a/src/plugins/qmldesigner/components/componentcore/theme.h b/src/plugins/qmldesigner/components/componentcore/theme.h index c18f5a9b91d..356a51a2969 100644 --- a/src/plugins/qmldesigner/components/componentcore/theme.h +++ b/src/plugins/qmldesigner/components/componentcore/theme.h @@ -87,6 +87,8 @@ public: centerHorizontal, centerVertical, cleanLogs_medium, + clearList_large, + clearList_medium, closeCross, closeFile_large, closeLink, From 54c9a38baa164f9460522ed85103b8b4c3e8f6ad Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Tue, 21 Nov 2023 11:29:34 +0200 Subject: [PATCH 025/101] QmlDesigner: Fix the build error for CollectionImportTools Change-Id: I946df14af3e4425203ea7ea04807205442c3119d Reviewed-by: Tim Jenssen Reviewed-by: Qt CI Patch Build Bot --- .../components/collectioneditor/collectionimporttools.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h b/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h index 4ee98284893..6ee4f590f76 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.h @@ -3,6 +3,8 @@ #pragma once +#include + QT_BEGIN_NAMESPACE class QJsonArray; class QUrl; From 659772baa400e3de4581c34670c602994093944a Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Mon, 20 Nov 2023 16:26:34 +0100 Subject: [PATCH 026/101] QmlDesigner: Fix navigator column width Fix the navigators column width for Qt 6.5.4 and at the same time make the icon columns tighter. Task-number: QDS-11314 Change-Id: I87397eca104e4bfb835090229672e2d3d42dee6e Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Tim Jenssen --- .../navigator/iconcheckboxitemdelegate.cpp | 8 +++++-- .../components/navigator/navigatorview.cpp | 22 ++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/plugins/qmldesigner/components/navigator/iconcheckboxitemdelegate.cpp b/src/plugins/qmldesigner/components/navigator/iconcheckboxitemdelegate.cpp index c24aa1933bf..5b36bee7f97 100644 --- a/src/plugins/qmldesigner/components/navigator/iconcheckboxitemdelegate.cpp +++ b/src/plugins/qmldesigner/components/navigator/iconcheckboxitemdelegate.cpp @@ -83,12 +83,16 @@ void IconCheckboxItemDelegate::paint(QPainter *painter, QTC_ASSERT(window, return); const QSize iconSize(16, 16); - const QPoint iconPosition(styleOption.rect.left() + (styleOption.rect.width() - iconSize.width()) / 2, - styleOption.rect.top() + 2 + delegateMargin); + QPoint iconPosition(styleOption.rect.left() + (styleOption.rect.width() - iconSize.width()) / 2, + styleOption.rect.top() + 2 + delegateMargin); const QIcon::State state = isChecked(modelIndex) ? QIcon::State::On : QIcon::State::Off; const QPixmap iconPixmap = m_icon.pixmap(window, iconSize, mode, state); + // Shift the lock icon (last column) slightly to the left due to vertical scrollbar width + if (modelIndex.column() == NavigatorTreeModel::ColumnType::Lock) + iconPosition.rx() -= 4; + painter->save(); if (isThisOrAncestorLocked(modelIndex)) diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp index a4a7ead0426..a0c5ebacd26 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp @@ -128,10 +128,22 @@ void NavigatorView::modelAttached(Model *model) QTreeView *treeView = treeWidget(); - treeView->header()->setSectionResizeMode(NavigatorTreeModel::ColumnType::Name, QHeaderView::Stretch); - treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Alias, 26); - treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Visibility, 26); - treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Lock, 26); + treeView->header()->setSectionResizeMode(NavigatorTreeModel::ColumnType::Name, + QHeaderView::Stretch); + treeView->header()->setSectionResizeMode(NavigatorTreeModel::ColumnType::Alias, + QHeaderView::Fixed); + treeView->header()->setSectionResizeMode(NavigatorTreeModel::ColumnType::Visibility, + QHeaderView::Fixed); + treeView->header()->setSectionResizeMode(NavigatorTreeModel::ColumnType::Lock, QHeaderView::Fixed); + + treeView->header()->setStretchLastSection(false); + treeView->header()->setMinimumSectionSize(24); + treeView->header()->setDefaultSectionSize(24); + + treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Alias, 24); + treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Visibility, 24); + // Make last column a bit wider to compensate the shift to the left due to vertical scrollbar + treeView->header()->resizeSection(NavigatorTreeModel::ColumnType::Lock, 32); treeView->setIndentation(20); m_currentModelInterface->setFilter(false); @@ -760,7 +772,7 @@ void NavigatorView::setupWidget() connect(m_widget.data(), &NavigatorWidget::textFilterChanged, this, &NavigatorView::textFilterChanged); const QString fontName = "qtds_propertyIconFont.ttf"; - const QSize size = QSize(28, 28); + const QSize size = QSize(32, 32); const QString visibilityOnUnicode = Theme::getIconUnicode(Theme::Icon::visibilityOn); const QString visibilityOffUnicode = Theme::getIconUnicode(Theme::Icon::visibilityOff); From 77678c7bcef3953cbfe61f99dbd00f1dc4f441bf Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 21 Nov 2023 12:43:49 +0200 Subject: [PATCH 027/101] EffectMaker: Add clear all nodes button Fixes: QDS-11335 Change-Id: I5d0e0e11baabe780c19234410814a9f6eb45130d Reviewed-by: Mahmoud Badri --- .../effectMakerQmlSources/EffectMaker.qml | 17 ++++++++++++++++- .../EffectNodesComboBox.qml | 2 -- src/plugins/effectmakernew/effectmakermodel.cpp | 13 +++++++++++-- src/plugins/effectmakernew/effectmakermodel.h | 1 + 4 files changed, 28 insertions(+), 5 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index 3476b084552..fd2ec56fd4f 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -55,6 +55,21 @@ Item { mainRoot: root anchors.verticalCenter: parent.verticalCenter + x: 5 + width: parent.width - 50 + } + + HelperWidgets.AbstractButton { + anchors.right: parent.right + anchors.rightMargin: 5 + anchors.verticalCenter: parent.verticalCenter + + style: StudioTheme.Values.viewBarButtonStyle + buttonIcon: StudioTheme.Constants.clearList_medium + tooltip: qsTr("Remove all effect nodes.") + enabled: !EffectMakerBackend.effectMakerModel.isEmpty + + onClicked: EffectMakerBackend.effectMakerModel.removeAllNodes() } HelperWidgets.AbstractButton { @@ -64,7 +79,7 @@ Item { style: StudioTheme.Values.viewBarButtonStyle buttonIcon: StudioTheme.Constants.code - tooltip: qsTr("Open Shader in Code Editor") + tooltip: qsTr("Open Shader in Code Editor.") visible: false // TODO: to be implemented onClicked: {} // TODO diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml index 42265970787..a2187d4aba7 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNodesComboBox.qml @@ -12,8 +12,6 @@ StudioControls.ComboBox { id: root actionIndicatorVisible: false - x: 5 - width: parent.width - 50 model: [qsTr("+ Add Effect")] diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index b078d563aa0..4595fec59c5 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -129,8 +129,7 @@ void EffectMakerModel::moveNode(int fromIdx, int toIdx) void EffectMakerModel::removeNode(int idx) { beginRemoveRows({}, idx, idx); - CompositionNode *node = m_nodes.at(idx); - m_nodes.removeAt(idx); + CompositionNode *node = m_nodes.takeAt(idx); delete node; endRemoveRows(); @@ -140,6 +139,16 @@ void EffectMakerModel::removeNode(int idx) bakeShaders(); } +void EffectMakerModel::removeAllNodes() +{ + beginResetModel(); + qDeleteAll(m_nodes); + m_nodes.clear(); + endResetModel(); + + setIsEmpty(true); +} + QString EffectMakerModel::fragmentShader() const { return m_fragmentShader; diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h index 96eb0e19b46..b844acf0d08 100644 --- a/src/plugins/effectmakernew/effectmakermodel.h +++ b/src/plugins/effectmakernew/effectmakermodel.h @@ -63,6 +63,7 @@ public: Q_INVOKABLE void moveNode(int fromIdx, int toIdx); Q_INVOKABLE void removeNode(int idx); + Q_INVOKABLE void removeAllNodes(); bool shadersUpToDate() const; void setShadersUpToDate(bool newShadersUpToDate); From 701d4b2146bfbc28cd99944aa0253a45f3cc3c0d Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Mon, 20 Nov 2023 21:21:54 +0100 Subject: [PATCH 028/101] QmlDesigner: fix crash Task-number: QDS-11300 Change-Id: I1fe6966445284e3e9ca5596d8f5ec866f37acc39 Reviewed-by: Mahmoud Badri Reviewed-by: Tim Jenssen --- .../qmldesigner/components/texteditor/texteditorwidget.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp index 93976f10d9e..fa639c39a01 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp +++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp @@ -78,6 +78,10 @@ void TextEditorWidget::setTextEditor( }); m_textEditor->editorWidget()->installEventFilter(this); + // do not call the eventfilter when the m_textEditor is gone + connect(m_textEditor->editorWidget(), &QObject::destroyed, this, [this](QObject *) { + m_textEditor->editorWidget()->removeEventFilter(this); + }); } } From fc456a74d43cdd8f0cba12802eec1881d827eb48 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 21 Nov 2023 15:01:00 +0200 Subject: [PATCH 029/101] EffectMaker: Fix crash after opening saved effect when nodes exist Clear and removeAllNodes functions were consolidated into one clear() function, which now properly resets the entire model. This makes UI properly synced to actual model state when composition is opened, so the phantom nodes will no longer appear. Fixes: QDS-11347 Change-Id: I204760cca6af669daa43a18bfb199dfbf14b73cb Reviewed-by: Amr Elsayed Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Patch Build Bot --- .../effectMakerQmlSources/EffectMaker.qml | 2 +- .../effectmakernew/effectmakermodel.cpp | 20 +------------------ src/plugins/effectmakernew/effectmakermodel.h | 4 +--- 3 files changed, 3 insertions(+), 23 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index fd2ec56fd4f..3f962478e0b 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -69,7 +69,7 @@ Item { tooltip: qsTr("Remove all effect nodes.") enabled: !EffectMakerBackend.effectMakerModel.isEmpty - onClicked: EffectMakerBackend.effectMakerModel.removeAllNodes() + onClicked: EffectMakerBackend.effectMakerModel.clear() } HelperWidgets.AbstractButton { diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index 4595fec59c5..d52e8858ca7 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -139,7 +139,7 @@ void EffectMakerModel::removeNode(int idx) bakeShaders(); } -void EffectMakerModel::removeAllNodes() +void EffectMakerModel::clear() { beginResetModel(); qDeleteAll(m_nodes); @@ -180,24 +180,6 @@ const QString &EffectMakerModel::qmlComponentString() const return m_qmlComponentString; } -void EffectMakerModel::clear() -{ - if (m_nodes.isEmpty()) - return; - - beginRemoveRows({}, 0, m_nodes.count()); - - for (CompositionNode *node : std::as_const(m_nodes)) - delete node; - - m_nodes.clear(); - - endRemoveRows(); - - setIsEmpty(true); - bakeShaders(); -} - const QList EffectMakerModel::allUniforms() { QList uniforms = {}; diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h index b844acf0d08..60d291f7520 100644 --- a/src/plugins/effectmakernew/effectmakermodel.h +++ b/src/plugins/effectmakernew/effectmakermodel.h @@ -63,7 +63,7 @@ public: Q_INVOKABLE void moveNode(int fromIdx, int toIdx); Q_INVOKABLE void removeNode(int idx); - Q_INVOKABLE void removeAllNodes(); + Q_INVOKABLE void clear(); bool shadersUpToDate() const; void setShadersUpToDate(bool newShadersUpToDate); @@ -76,8 +76,6 @@ public: const QString &qmlComponentString() const; - void clear(); - Q_INVOKABLE void updateQmlComponent(); Q_INVOKABLE void resetEffectError(int type); From ef6dfc1c76edd7f01c34ba5c17031b330458dbac Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Tue, 21 Nov 2023 17:01:50 +0200 Subject: [PATCH 030/101] QmlDesigner: Center the model editor's empty message Change-Id: I2d26d2a89bdd822a4c9172bbe4b652be642a0d34 Reviewed-by: Miikka Heikkinen Reviewed-by: Ali Kianian Reviewed-by: Qt CI Patch Build Bot --- .../collectionEditorQmlSource/CollectionDetailsView.qml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml index 5b88ebc2619..42e145bd905 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml @@ -306,14 +306,11 @@ Rectangle { } Text { - anchors.fill: parent + anchors.centerIn: parent text: qsTr("Select a model to continue") visible: !topRow.visible - textFormat: Text.RichText color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.mediumFontSize - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap } TextMetrics { From f2eee58e00b67319ca8e2877ba63bf3b751a77b9 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Tue, 21 Nov 2023 17:28:51 +0100 Subject: [PATCH 031/101] ADS: Set default minimum size on empty dock widget * Set a default minimum size on empty dock widgets. Dock widgets are empty if their content minimum size isEmpty (width or height <= 0) * Replace 0 with nullptr as return value * Fix some code formatting Task-number: QDS-11255 Change-Id: Ifa7320fd57e73367f71087232dedd939d19ae490 Reviewed-by: Tim Jenssen Reviewed-by: Qt CI Patch Build Bot --- src/libs/advanceddockingsystem/ads_globals.h | 10 ++-- .../advanceddockingsystem/docksplitter.cpp | 3 +- src/plugins/qmldesigner/designmodewidget.cpp | 60 ++++++++++++------- 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/libs/advanceddockingsystem/ads_globals.h b/src/libs/advanceddockingsystem/ads_globals.h index 8541e3d9da7..6fc590f4718 100644 --- a/src/libs/advanceddockingsystem/ads_globals.h +++ b/src/libs/advanceddockingsystem/ads_globals.h @@ -161,8 +161,8 @@ bool isSideBarArea(DockWidgetArea area); /** * Searches for the parent widget of the given type. Returns the parent widget of the given - * widget or 0 if the widget is not child of any widget of type T. - * It is not safe to use this function in in DockWidget because only the current dock widget has a + * widget or nullptr if the widget is not child of any widget of type T. + * It is not safe to use this function in DockWidget, because only the current dock widget has a * parent. All dock widgets that are not the current dock widget in a dock area have no parent. */ template @@ -171,12 +171,12 @@ T findParent(const QWidget *widget) QWidget *parentWidget = widget->parentWidget(); while (parentWidget) { T parentImpl = qobject_cast(parentWidget); - if (parentImpl) { + if (parentImpl) return parentImpl; - } + parentWidget = parentWidget->parentWidget(); } - return 0; + return nullptr; } /** diff --git a/src/libs/advanceddockingsystem/docksplitter.cpp b/src/libs/advanceddockingsystem/docksplitter.cpp index a9207e0c08d..4446170e2ec 100644 --- a/src/libs/advanceddockingsystem/docksplitter.cpp +++ b/src/libs/advanceddockingsystem/docksplitter.cpp @@ -50,9 +50,8 @@ bool DockSplitter::hasVisibleContent() const { // TODO Cache or precalculate this to speed up for (int i = 0; i < count(); ++i) { - if (!widget(i)->isHidden()) { + if (!widget(i)->isHidden()) return true; - } } return false; diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp index 1387f42f9c9..460b613b26b 100644 --- a/src/plugins/qmldesigner/designmodewidget.cpp +++ b/src/plugins/qmldesigner/designmodewidget.cpp @@ -70,6 +70,27 @@ static void hideToolButtons(QList &buttons) button->hide(); } +static void ensureMinimumSize(QWidget *widget) +{ + if (widget->minimumSize().isEmpty()) + widget->setMinimumSize(widget->minimumSize().expandedTo(QSize(60, 60))); +} + +static ADS::DockWidget *createDockWidget(QWidget *widget, + const QString &uniqueId, + const QString &title, + ADS::DockWidget::eMinimumSizeHintMode minimumSizeHintMode) +{ + ADS::DockWidget *dockWidget = new ADS::DockWidget(uniqueId); + dockWidget->setWidget(widget, ADS::DockWidget::ForceNoScrollArea); + dockWidget->setWindowTitle(title); + dockWidget->setMinimumSizeHintMode(minimumSizeHintMode); + + widget->setObjectName(uniqueId); // Set unique id as object name + + return dockWidget; +} + namespace QmlDesigner { namespace Internal { @@ -308,15 +329,10 @@ void DesignModeWidget::setup() sheet += "QLabel { background-color: creatorTheme.DSsectionHeadBackground; }"; navigationView.widget->setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(sheet))); - // Create DockWidget - ADS::DockWidget *dockWidget = new ADS::DockWidget(uniqueId); - dockWidget->setWidget(navigationView.widget, ADS::DockWidget::ForceNoScrollArea); - dockWidget->setWindowTitle(title); - dockWidget->setMinimumSizeHintMode(m_minimumSizeHintMode); - m_dockManager->addDockWidget(ADS::NoDockWidgetArea, dockWidget); + ensureMinimumSize(navigationView.widget); - // Set unique id as object name - navigationView.widget->setObjectName(uniqueId); + auto dockWidget = createDockWidget(navigationView.widget, uniqueId, title, m_minimumSizeHintMode); + m_dockManager->addDockWidget(ADS::NoDockWidgetArea, dockWidget); // Create menu action auto command = Core::ActionManager::registerAction(dockWidget->toggleViewAction(), @@ -328,19 +344,17 @@ void DesignModeWidget::setup() // Afterwards get all the other widgets for (const WidgetInfo &widgetInfo : viewManager().widgetInfos()) { - // Create DockWidget - ADS::DockWidget *dockWidget = new ADS::DockWidget(widgetInfo.uniqueId); - dockWidget->setWidget(widgetInfo.widget, ADS::DockWidget::ForceNoScrollArea); - dockWidget->setWindowTitle(widgetInfo.tabName); - dockWidget->setMinimumSizeHintMode(m_minimumSizeHintMode); + ensureMinimumSize(widgetInfo.widget); + + auto dockWidget = createDockWidget(widgetInfo.widget, + widgetInfo.uniqueId, + widgetInfo.tabName, + m_minimumSizeHintMode); m_dockManager->addDockWidget(ADS::NoDockWidgetArea, dockWidget); // Add to view widgets m_viewWidgets.append(widgetInfo.widget); - // Set unique id as object name - widgetInfo.widget->setObjectName(widgetInfo.uniqueId); - // Create menu action auto command = Core::ActionManager::registerAction(dockWidget->toggleViewAction(), actionToggle.withSuffix( @@ -354,14 +368,14 @@ void DesignModeWidget::setup() { const QString uniqueId = "OutputPane"; auto outputPanePlaceholder = new Core::OutputPanePlaceHolder(Core::Constants::MODE_DESIGN); - m_outputPaneDockWidget = new ADS::DockWidget(uniqueId); - m_outputPaneDockWidget->setWidget(outputPanePlaceholder, ADS::DockWidget::ForceNoScrollArea); - m_outputPaneDockWidget->setWindowTitle(tr("Output")); - m_outputPaneDockWidget->setMinimumSizeHintMode(m_minimumSizeHintMode); - m_dockManager->addDockWidget(ADS::NoDockWidgetArea, m_outputPaneDockWidget); - // Set unique id as object name - outputPanePlaceholder->setObjectName(uniqueId); + ensureMinimumSize(outputPanePlaceholder); + + m_outputPaneDockWidget = createDockWidget(outputPanePlaceholder, + uniqueId, + tr("Output"), + m_minimumSizeHintMode); + m_dockManager->addDockWidget(ADS::NoDockWidgetArea, m_outputPaneDockWidget); // Create menu action auto command = Core::ActionManager::registerAction(m_outputPaneDockWidget->toggleViewAction(), From 1ed6674d1ec88b36ee97b47f82168d868ded26ea Mon Sep 17 00:00:00 2001 From: Aleksei German Date: Tue, 21 Nov 2023 18:28:41 +0100 Subject: [PATCH 032/101] QmlDesigner: Fix crash in QmlDesigner::TextEditor Change-Id: Ic511e5812bbe015f90f88f947faa50bb3461ae38 Reviewed-by: Tim Jenssen --- .../components/texteditor/texteditorwidget.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp index fa639c39a01..97ef6c4b689 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp +++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp @@ -78,10 +78,6 @@ void TextEditorWidget::setTextEditor( }); m_textEditor->editorWidget()->installEventFilter(this); - // do not call the eventfilter when the m_textEditor is gone - connect(m_textEditor->editorWidget(), &QObject::destroyed, this, [this](QObject *) { - m_textEditor->editorWidget()->removeEventFilter(this); - }); } } @@ -206,6 +202,10 @@ void TextEditorWidget::setBlockCursorSelectionSynchronisation(bool b) bool TextEditorWidget::eventFilter(QObject *, QEvent *event) { + //do not call the eventfilter when the m_textEditor is gone + if (!TextEditor::TextEditorWidget::fromEditor(m_textEditor.get())) + return false; + static std::vector overrideKeys = { Qt::Key_Delete, Qt::Key_Backspace, Qt::Key_Insert, Qt::Key_Escape }; From 50fe4051e34781f45f21e698927eba6b02484d5f Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Wed, 22 Nov 2023 15:39:35 +0200 Subject: [PATCH 033/101] QmlDesigner: Add the Collection Singleton to the QDS template Change-Id: I8bad907766dfa0f630cee935d2b587fc613b0922 Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Patch Build Bot --- .../projects/application-3d/wizard.json | 8 +++++ .../projects/application/wizard.json | 8 +++++ .../projects/desktop-launcher/wizard.json | 8 +++++ .../name/CMakeLists.importmodule.txt.tpl | 1 + .../shared-plugin/name/DataStore.json.tpl | 30 +++++++++++++++++++ .../shared-plugin/name/DataStore.qml.tpl | 12 ++++++++ .../name/importmodule.qmldir.tpl | 2 +- .../projects/shared-plugin/name/qmldir | 1 + .../projects/qtquickapplication/wizard.json | 10 +++++++ 9 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.json.tpl create mode 100644 share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml.tpl 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 d5b1fef1e45..232dfd43199 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json @@ -367,6 +367,14 @@ "source": "../shared-plugin/name/Constants.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/Constants.qml" }, + { + "source": "../shared-plugin/name/DataStore.json.tpl", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.json" + }, + { + "source": "../shared-plugin/name/DataStore.qml.tpl", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" + }, { "source": "../shared-plugin/name/DirectoryFontLoader.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DirectoryFontLoader.qml" diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json index 0708838a5ae..2c5d6067505 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json @@ -380,6 +380,14 @@ "source": "../shared-plugin/name/Constants.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/Constants.qml" }, + { + "source": "../shared-plugin/name/DataStore.json.tpl", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.json" + }, + { + "source": "../shared-plugin/name/DataStore.qml.tpl", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" + }, { "source": "../shared-plugin/name/DirectoryFontLoader.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DirectoryFontLoader.qml" diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json index 913eb0bf28b..81bbcb73f22 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json @@ -367,6 +367,14 @@ "source": "../shared-plugin/name/Constants.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/Constants.qml" }, + { + "source": "../shared-plugin/name/DataStore.json.tpl", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.json" + }, + { + "source": "../shared-plugin/name/DataStore.qml.tpl", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" + }, { "source": "../shared-plugin/name/DirectoryFontLoader.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DirectoryFontLoader.qml" diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/CMakeLists.importmodule.txt.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/CMakeLists.importmodule.txt.tpl index 517b91355a7..5606f3c7b14 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/CMakeLists.importmodule.txt.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/CMakeLists.importmodule.txt.tpl @@ -13,6 +13,7 @@ qt6_add_qml_module(%{ImportModuleName} RESOURCE_PREFIX "/qt/qml" QML_FILES Constants.qml + DataStore.qml DirectoryFontLoader.qml EventListModel.qml EventListSimulator.qml diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.json.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.json.tpl new file mode 100644 index 00000000000..8ebda6fb7e6 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.json.tpl @@ -0,0 +1,30 @@ +{ + "book": [ + { + "author": "Nigel Rees", + "category": "reference", + "price": 8.95, + "title": "Sayings of the Century" + }, + { + "author": "Evelyn Waugh", + "category": "fiction", + "price": 12.99, + "title": "Sword of Honor" + }, + { + "author": "Herman Melville", + "category": "fiction", + "isbn": "0-553-21311-3", + "price": 8.99, + "title": "Moby Dick" + }, + { + "author": "J. R. R. Tolkien", + "category": "fiction", + "isbn": "0-395-19395-8", + "price": 22.99, + "title": "The Lord of the Rings" + } + ] +} diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml.tpl new file mode 100644 index 00000000000..0f9c24373c7 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml.tpl @@ -0,0 +1,12 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +pragma Singleton +import QtQuick.Studio.Utils + +JsonListModel { + property alias allModels: models + id: models + + source: Qt.resolvedUrl("DataStore.json") +} diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/importmodule.qmldir.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/importmodule.qmldir.tpl index d374931eab8..a0ec2f17cfc 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/importmodule.qmldir.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/importmodule.qmldir.tpl @@ -1,6 +1,6 @@ Module %{ImportModuleName} +singleton DataStore 1.0 DataStore.qml singleton Constants 1.0 Constants.qml EventListSimulator 1.0 EventListSimulator.qml EventListModel 1.0 EventListModel.qml DirectoryFontLoader 1.0 DirectoryFontLoader.qml - diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/qmldir b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/qmldir index 3ba5adcc643..b5924a433cc 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/qmldir +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/qmldir @@ -1,4 +1,5 @@ singleton Constants 1.0 Constants.qml +singleton DataStore 1.0 DataStore.qml EventListModel 1.0 EventListModel.qml EventListSimulator 1.0 EventListSimulator.qml DirectoryFontLoader 1.0 DirectoryFontLoader.qml diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json index 2e885c2bb63..64502bd1246 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json @@ -242,6 +242,16 @@ "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/Constants.qml", "condition": "%{QdsProjectStyle}" }, + { + "source": "%{QdsWizardPath}/shared-plugin/name/DataStore.json.tpl", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.json", + "condition": "%{QdsProjectStyle}" + }, + { + "source": "%{QdsWizardPath}/shared-plugin/name/DataStore.qml.tpl", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml", + "condition": "%{QdsProjectStyle}" + }, { "source": "%{QdsWizardPath}/shared-plugin/name/DirectoryFontLoader.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DirectoryFontLoader.qml", From 3930deff2914c0440768bc81a109131e9a34f880 Mon Sep 17 00:00:00 2001 From: Johanna Vanhatapio Date: Tue, 14 Nov 2023 12:56:26 +0200 Subject: [PATCH 034/101] Doc: Describe the split view in 3D Fixes: QDS-1109 Change-Id: I849bd54109a9caaf9de989099495aa02dfd60a5f Reviewed-by: Mats Honkamaa --- doc/qtdesignstudio/images/icons/split-view.png | Bin 0 -> 326 bytes .../images/studio-3d-split-view.webp | Bin 0 -> 33988 bytes .../qtdesignstudio-3d-editor.qdoc | 15 +++++++++++++++ 3 files changed, 15 insertions(+) create mode 100644 doc/qtdesignstudio/images/icons/split-view.png create mode 100644 doc/qtdesignstudio/images/studio-3d-split-view.webp diff --git a/doc/qtdesignstudio/images/icons/split-view.png b/doc/qtdesignstudio/images/icons/split-view.png new file mode 100644 index 0000000000000000000000000000000000000000..f07ab82478f1e5d927d4a7957d3c40d04eb95f9d GIT binary patch literal 326 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7I14-?iy0WWg+Z8+Vb&Z8 z1_lQ95>H=O_UGK<9GWI#Sx>zg7#N;Z=;a(Jzm4uVJr6VLbwQs$bd6<0ew)+*%XbX|`S?a|mixq!yD!;Xq*Pj15R^8tE c`9=OzJ=L_Gwm!QV7#J8lUHx3vIVCg!0HBt9jsO4v literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/images/studio-3d-split-view.webp b/doc/qtdesignstudio/images/studio-3d-split-view.webp new file mode 100644 index 0000000000000000000000000000000000000000..630fdb48fe40dc3e3dd692406bc64a41f34b0952 GIT binary patch literal 33988 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%0D4_f9PxR7{JD;c@-SklBT(`)9)0-bo61ejJhW*6- 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 UGnma6kdzwED8RtRkOJZZ00(wYqyPW_ literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc index 39b0b05b048..7848fb0d07e 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc @@ -104,6 +104,16 @@ selected, the camera is pointed at the world origin. This does not affect the camera zoom level. + To view the scene in a split view of four different point of views, select + \inlineimage icons/split-view.png. + + \image studio-3d-split-view.webp "Split view in the 3D view" + + To select one of the four panes, click on it. The selected pane is marked with + a blue frame. Use the world axis helper to change the point of view for each pane + independently. Navigate each split by panning, rotating, and zooming, as + described above. + \image studio-3d-editor-axis-helper.webp "Axis helper in the 3D view" You can use scene cameras (2) to view the \uicontrol View3D component from a @@ -441,6 +451,11 @@ \li Background Color Actions \li \li \l{Changing Colors} + \row + \li \inlineimage icons/split-view.png + \li Toggle Split View On/Off + \li \key Ctrl + \key Alt + \key Q + \li \l{Using Split View} \row \li \inlineimage icons/particles-seek.png \li Seek Particle System Time From c14dc9d2baa2b7813be5fd5d02905b0ecd89309c Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Wed, 22 Nov 2023 15:28:54 +0200 Subject: [PATCH 035/101] EffectMaker: Focus view upon open, and correctly open new effects Also don't open old effect maker when creating a new effect Fixes: QDS-11359 Fixes: QDS-11364 Change-Id: Ie9659af991f10cafac29dc53cbe7163eb8995b2a Reviewed-by: Miikka Heikkinen Reviewed-by: Qt CI Patch Build Bot --- src/plugins/effectmakernew/effectmakermodel.cpp | 10 +++++++--- .../assetslibrary/assetslibrarywidget.cpp | 13 ++++++++----- .../components/assetslibrary/assetslibrarywidget.h | 2 +- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index d52e8858ca7..32fa88d7eb9 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -558,6 +558,9 @@ void EffectMakerModel::openComposition(const QString &path) { clear(); + const QString effectName = QFileInfo(path).baseName(); + setCurrentComposition(effectName); + QFile compFile(path); if (!compFile.open(QIODevice::ReadOnly)) { QString error = QString("Couldn't open composition file: '%1'").arg(path); @@ -567,6 +570,10 @@ void EffectMakerModel::openComposition(const QString &path) } QByteArray data = compFile.readAll(); + + if (data.isEmpty()) + return; + QJsonParseError parseError; QJsonDocument jsonDoc(QJsonDocument::fromJson(data, &parseError)); if (parseError.error != QJsonParseError::NoError) { @@ -597,7 +604,6 @@ void EffectMakerModel::openComposition(const QString &path) } // Get effects dir - const QString effectName = QFileInfo(path).baseName(); const Utils::FilePath effectsResDir = QmlDesigner::ModelNodeOperations::getEffectsImportDirectory(); const QString effectsResPath = effectsResDir.pathAppended(effectName).toString(); @@ -613,8 +619,6 @@ void EffectMakerModel::openComposition(const QString &path) setIsEmpty(m_nodes.isEmpty()); bakeShaders(); } - - setCurrentComposition(effectName); } void EffectMakerModel::exportResources(const QString &name) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index a141c696978..a785fea76f0 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -8,6 +8,7 @@ #include "assetslibrarymodel.h" #include "assetslibraryview.h" #include "designeractionmanager.h" +#include "designmodewidget.h" #include "modelnodeoperations.h" #include "qmldesignerconstants.h" #include "qmldesignerplugin.h" @@ -192,12 +193,12 @@ QString AssetsLibraryWidget::getUniqueEffectPath(const QString &parentFolder, co return path; } -bool AssetsLibraryWidget::createNewEffect(const QString &effectPath, bool openEffectMaker) +bool AssetsLibraryWidget::createNewEffect(const QString &effectPath, bool openInEffectMaker) { bool created = QFile(effectPath).open(QIODevice::WriteOnly); - if (created && openEffectMaker) { - ModelNodeOperations::openEffectMaker(effectPath); + if (created && openInEffectMaker) { + openEffectMaker(effectPath); emit directoryCreated(QFileInfo(effectPath).absolutePath()); } @@ -379,10 +380,12 @@ bool isEffectMakerActivated() void AssetsLibraryWidget::openEffectMaker(const QString &filePath) { - if (isEffectMakerActivated()) + if (isEffectMakerActivated()) { // new effect maker m_assetsView->emitCustomNotification("open_effectmaker_composition", {}, {filePath}); - else + QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("Effect Maker", true); + } else { // old effect maker ModelNodeOperations::openEffectMaker(filePath); + } } QString AssetsLibraryWidget::qmlSourcesPath() diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h index 33ad100c0b1..4b3976ebae2 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h @@ -92,7 +92,7 @@ public: Q_INVOKABLE void updateContextMenuActionsEnableState(); Q_INVOKABLE QString getUniqueEffectPath(const QString &parentFolder, const QString &effectName); - Q_INVOKABLE bool createNewEffect(const QString &effectPath, bool openEffectMaker = true); + Q_INVOKABLE bool createNewEffect(const QString &effectPath, bool openInEffectMaker = true); Q_INVOKABLE bool canCreateEffects() const; From 71394691b5ec186ca8eaf019b9b015045721c07d Mon Sep 17 00:00:00 2001 From: Aleksei German Date: Tue, 21 Nov 2023 14:54:32 +0100 Subject: [PATCH 036/101] QmlDesigner: Fix for MCUs styles combobox Task-number: QDS-11258 Change-Id: Ib1399e111daf14856e3e679619978180ba7da088 Reviewed-by: Aleksei German Reviewed-by: Reviewed-by: Qt CI Patch Build Bot --- .../componentcore/changestyleaction.cpp | 16 +++++++++++++--- .../components/toolbar/toolbarbackend.cpp | 3 ++- .../components/toolbar/toolbarbackend.h | 3 ++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp b/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp index aa386929400..2bf06c1a1a6 100644 --- a/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp +++ b/src/plugins/qmldesigner/components/componentcore/changestyleaction.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "changestyleaction.h" -#include "designermcumanager.h" #include #include @@ -47,6 +46,17 @@ static QString styleConfigFileName(const QString &qmlFileName) return QString(); } +static bool isQtForMCUs() +{ + if (ProjectExplorer::ProjectManager::startupTarget()) { + const QmlProjectManager::QmlBuildSystem *buildSystem = qobject_cast( + ProjectExplorer::ProjectManager::startupTarget()->buildSystem()); + if (buildSystem) + return buildSystem->qtForMCUs(); + } + return false; +} + ChangeStyleWidgetAction::ChangeStyleWidgetAction(QObject *parent) : QWidgetAction(parent) { items = getAllStyleItems(); @@ -78,7 +88,7 @@ QList ChangeStyleWidgetAction::getAllStyleItems() if (Utils::HostOsInfo::isWindowsHost()) items.append({"Windows", "Windows", {}}); - if (DesignerMcuManager::instance().isMCUProject()) + if (isQtForMCUs()) items.append({"MCUDefaultStyle", "MCUDefaultStyle", {}}); //what if we have a custom style set in .conf? @@ -178,7 +188,7 @@ QWidget *ChangeStyleWidgetAction::createWidget(QWidget *parent) comboBox->setDisabled(true); comboBox->setToolTip(tr(disbledTooltip)); comboBox->setCurrentIndex(0); - } else if (DesignerMcuManager::instance().isMCUProject()) { + } else if (isQtForMCUs()) { comboBox->setDisabled(true); comboBox->setEditText(style); } else { diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp index 37f512edb93..6ce8ef193a5 100644 --- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp @@ -353,8 +353,9 @@ ToolBarBackend::ToolBarBackend(QObject *parent) [this](ProjectExplorer::Project *project) { disconnect(m_kitConnection); emit isQt6Changed(); - emit isMCUsChanged(); emit projectOpenedChanged(); + emit stylesChanged(); + emit isMCUsChanged(); if (project) { m_kitConnection = connect(project, &ProjectExplorer::Project::activeTargetChanged, diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h index ce8dd62b524..307704d63a0 100644 --- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h @@ -84,7 +84,7 @@ class ToolBarBackend : public QObject Q_PROPERTY(int documentIndex READ documentIndex NOTIFY documentIndexChanged) Q_PROPERTY(QString currentWorkspace READ currentWorkspace NOTIFY currentWorkspaceChanged) Q_PROPERTY(bool lockWorkspace READ lockWorkspace WRITE setLockWorkspace NOTIFY lockWorkspaceChanged) - Q_PROPERTY(QStringList styles READ styles CONSTANT) + Q_PROPERTY(QStringList styles READ styles NOTIFY stylesChanged) Q_PROPERTY(bool isInDesignMode READ isInDesignMode NOTIFY isInDesignModeChanged) Q_PROPERTY(bool isInEditMode READ isInEditMode NOTIFY isInEditModeChanged) Q_PROPERTY(bool isInSessionMode READ isInSessionMode NOTIFY isInSessionModeChanged) @@ -151,6 +151,7 @@ signals: void documentIndexChanged(); void currentWorkspaceChanged(); void lockWorkspaceChanged(); + void stylesChanged(); void isInDesignModeChanged(); void isInEditModeChanged(); void isInSessionModeChanged(); From b2def1b949eac822a368488df175bfac6efdcc8b Mon Sep 17 00:00:00 2001 From: Eike Ziller Date: Mon, 20 Nov 2023 10:13:39 +0100 Subject: [PATCH 037/101] QmlDesigner: Hot fix for settings crash Change-Id: I05d27fb2dee65c50191e7dcd7c7bf8f195bb46e5 Reviewed-by: Tim Jenssen --- src/plugins/qmldesigner/designmodewidget.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp index 460b613b26b..bc566f4f756 100644 --- a/src/plugins/qmldesigner/designmodewidget.cpp +++ b/src/plugins/qmldesigner/designmodewidget.cpp @@ -582,6 +582,9 @@ void DesignModeWidget::setMinimumSizeHintFromContentMinimumSize(bool value) m_minimumSizeHintMode = newMode; + if (!m_dockManager) + return; + const auto &dockWidgets = m_dockManager->dockWidgetsMap(); for (auto dockWidget : dockWidgets) dockWidget->setMinimumSizeHintMode(m_minimumSizeHintMode); From ac3a4b71e607caacdc0b0486056198880cf8b933 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 24 Nov 2023 12:36:55 +0200 Subject: [PATCH 038/101] EffectMaker: Bake preview shaders using correct version of qsb tool If the target kit Qt version differs from Qt version that QDS was built with, there is a chance that shaders baked for the target kit don't work for rendering preview on QDS side, if QShader version has changed between the two Qt versions. This means we must bake separate shaders for the preview and the project to use, each using the correct version of qsb tool. Task-number: QDS-11361 Change-Id: I44df2aeb3f4d6aa4b80e3be052d46735d96c53ef Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Mahmoud Badri --- .../effectmakernew/effectmakermodel.cpp | 81 +++++++++++++------ src/plugins/effectmakernew/effectmakermodel.h | 4 +- 2 files changed, 61 insertions(+), 24 deletions(-) diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index 32fa88d7eb9..58f46b2b1fe 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -21,6 +21,7 @@ #include #include +#include #include namespace EffectMaker { @@ -1086,18 +1087,25 @@ QString EffectMakerModel::generateFragmentShader(bool includeUniforms) return s; } -void EffectMakerModel::handleQsbProcessExit(Utils::Process *qsbProcess, const QString &shader) +void EffectMakerModel::handleQsbProcessExit(Utils::Process *qsbProcess, const QString &shader, bool preview) { --m_remainingQsbTargets; const QString errStr = qsbProcess->errorString(); const QByteArray errStd = qsbProcess->readAllRawStandardError(); - if (!errStr.isEmpty()) - qWarning() << QString("Failed to generate QSB file for: %1 %2").arg(shader, errStr); + QString previewStr; + if (preview) + previewStr = QStringLiteral("preview"); - if (!errStd.isEmpty()) - qWarning() << QString("Failed to generate QSB file for: %1 %2") - .arg(shader, QString::fromUtf8(errStd)); + if (!errStr.isEmpty()) { + qWarning() << QString("Failed to generate %3 QSB file for: %1 %2") + .arg(shader, errStr, previewStr); + } + + if (!errStd.isEmpty()) { + qWarning() << QString("Failed to generate %3 QSB file for: %1 %2") + .arg(shader, QString::fromUtf8(errStd), previewStr); + } if (m_remainingQsbTargets <= 0) { Q_EMIT shadersBaked(); @@ -1183,21 +1191,30 @@ void EffectMakerModel::createFiles() QFile(m_vertexShaderFilename).remove(); if (QFileInfo(m_fragmentShaderFilename).exists()) QFile(m_fragmentShaderFilename).remove(); + if (QFileInfo(m_vertexShaderPreviewFilename).exists()) + QFile(m_vertexShaderPreviewFilename).remove(); + if (QFileInfo(m_fragmentShaderPreviewFilename).exists()) + QFile(m_fragmentShaderPreviewFilename).remove(); auto vertexShaderFile = QTemporaryFile(QDir::tempPath() + "/dsem_XXXXXX.vert.qsb"); auto fragmentShaderFile = QTemporaryFile(QDir::tempPath() + "/dsem_XXXXXX.frag.qsb"); + auto vertexShaderPreviewFile = QTemporaryFile(QDir::tempPath() + "/dsem_prev_XXXXXX.vert.qsb"); + auto fragmentShaderPreviewFile = QTemporaryFile(QDir::tempPath() + "/dsem_prev_XXXXXX.frag.qsb"); m_vertexSourceFile.setFileTemplate(QDir::tempPath() + "/dsem_XXXXXX.vert"); m_fragmentSourceFile.setFileTemplate(QDir::tempPath() + "/dsem_XXXXXX.frag"); if (!m_vertexSourceFile.open() || !m_fragmentSourceFile.open() - || !vertexShaderFile.open() || !fragmentShaderFile.open()) { + || !vertexShaderFile.open() || !fragmentShaderFile.open() + || !vertexShaderPreviewFile.open() || !fragmentShaderPreviewFile.open()) { qWarning() << "Unable to open temporary files"; } else { m_vertexSourceFilename = m_vertexSourceFile.fileName(); m_fragmentSourceFilename = m_fragmentSourceFile.fileName(); m_vertexShaderFilename = vertexShaderFile.fileName(); m_fragmentShaderFilename = fragmentShaderFile.fileName(); + m_vertexShaderPreviewFilename = vertexShaderPreviewFile.fileName(); + m_fragmentShaderPreviewFilename = fragmentShaderPreviewFile.fileName(); } } @@ -1244,27 +1261,43 @@ void EffectMakerModel::bakeShaders() Utils::FilePath qsbPath = qtVer->binPath().pathAppended("qsb").withExecutableSuffix(); if (!qsbPath.exists()) { - qWarning() << failMessage << "QSB tool not found"; + qWarning() << failMessage << "QSB tool for target kit not found"; + return; + } + + Utils::FilePath binPath = Utils::FilePath::fromString( + QLibraryInfo::path(QLibraryInfo::BinariesPath)); + Utils::FilePath qsbPrevPath = binPath.pathAppended("qsb").withExecutableSuffix(); + if (!qsbPrevPath.exists()) { + qWarning() << failMessage << "QSB tool for preview shaders not found"; return; } m_remainingQsbTargets = 2; // We only have 2 shaders const QStringList srcPaths = {m_vertexSourceFilename, m_fragmentSourceFilename}; const QStringList outPaths = {m_vertexShaderFilename, m_fragmentShaderFilename}; - for (int i = 0; i < 2; ++i) { - const auto workDir = Utils::FilePath::fromString(outPaths[i]); - // TODO: Optional legacy glsl support like standalone effect maker needs to add "100es,120" - QStringList args = {"-s", "--glsl", "300es,140,330,410", "--hlsl", "50", "--msl", "12"}; - args << "-o" << outPaths[i] << srcPaths[i]; + const QStringList outPrevPaths = {m_vertexShaderPreviewFilename, m_fragmentShaderPreviewFilename}; + + auto runQsb = [this, srcPaths](const Utils::FilePath &qsbPath, const QStringList &outPaths, bool preview) { + for (int i = 0; i < 2; ++i) { + const auto workDir = Utils::FilePath::fromString(outPaths[i]); + // TODO: Optional legacy glsl support like standalone effect maker needs to add "100es,120" + QStringList args = {"-s", "--glsl", "300es,140,330,410", "--hlsl", "50", "--msl", "12"}; + args << "-o" << outPaths[i] << srcPaths[i]; + + auto qsbProcess = new Utils::Process(this); + connect(qsbProcess, &Utils::Process::done, this, [=] { + handleQsbProcessExit(qsbProcess, srcPaths[i], preview); + }); + qsbProcess->setWorkingDirectory(workDir.absolutePath()); + qsbProcess->setCommand({qsbPath, args}); + qsbProcess->start(); + } + }; + + runQsb(qsbPath, outPaths, false); + runQsb(qsbPrevPath, outPrevPaths, true); - auto qsbProcess = new Utils::Process(this); - connect(qsbProcess, &Utils::Process::done, this, [=] { - handleQsbProcessExit(qsbProcess, srcPaths[i]); - }); - qsbProcess->setWorkingDirectory(workDir.absolutePath()); - qsbProcess->setCommand({qsbPath, args}); - qsbProcess->start(); - } } bool EffectMakerModel::shadersUpToDate() const @@ -1376,8 +1409,10 @@ QString EffectMakerModel::getQmlComponentString(bool localFiles) s += '\n' + customImagesString; s += '\n'; - s += l2 + "vertexShader: 'file:///" + m_vertexShaderFilename + "'\n"; - s += l2 + "fragmentShader: 'file:///" + m_fragmentShaderFilename + "'\n"; + const QString vertFile = localFiles ? m_vertexShaderFilename : m_vertexShaderPreviewFilename; + const QString fragFile = localFiles ? m_fragmentShaderFilename : m_fragmentShaderPreviewFilename; + s += l2 + "vertexShader: 'file:///" + vertFile + "'\n"; + s += l2 + "fragmentShader: 'file:///" + fragFile + "'\n"; s += l2 + "anchors.fill: parent\n"; if (m_shaderFeatures.enabled(ShaderFeatures::GridMesh)) { QString gridSize = QString("%1, %2").arg(m_shaderFeatures.gridMeshWidth()) diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h index 60d291f7520..9582450d845 100644 --- a/src/plugins/effectmakernew/effectmakermodel.h +++ b/src/plugins/effectmakernew/effectmakermodel.h @@ -141,7 +141,7 @@ private: QString getCustomShaderVaryings(bool outState); QString generateVertexShader(bool includeUniforms = true); QString generateFragmentShader(bool includeUniforms = true); - void handleQsbProcessExit(Utils::Process *qsbProcess, const QString &shader); + void handleQsbProcessExit(Utils::Process *qsbProcess, const QString &shader, bool preview); QString stripFileFromURL(const QString &urlString) const; QString getQmlEffectString(); @@ -174,6 +174,8 @@ private: QString m_vertexSourceFilename; QString m_fragmentShaderFilename; QString m_vertexShaderFilename; + QString m_fragmentShaderPreviewFilename; + QString m_vertexShaderPreviewFilename; // Used in exported QML, at root of the file QString m_exportedRootPropertiesString; // Used in exported QML, at ShaderEffect component of the file From e2c1cfb69fb3fa9b0db13c27af07d30364872930 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 23 Nov 2023 15:40:38 +0100 Subject: [PATCH 039/101] QmlDesigner: Add wizard data for models and backend json data Added the new files to all wizards, since the change of the qmldir file otherwise breaks the wizard. Adding json files to qmlproject for cmake generation. New files have to be added to cmakefiles.txt. Change-Id: If00eb4507b6f1364ce3cfa00db39632635febd09 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Mahmoud Badri --- .../projects/application-3d/wizard.json | 24 +++++++++++------ .../projects/application/wizard.json | 24 +++++++++++------ .../projects/common/app.qmlproject.tpl | 4 +++ .../projects/desktop-launcher/wizard.json | 24 +++++++++++------ .../projects/mobile-scroll/wizard.json | 16 ++++++++++++ .../projects/mobile-stack/wizard.json | 16 ++++++++++++ .../projects/mobile-swipe/wizard.json | 16 ++++++++++++ .../name/CMakeLists.importmodule.txt.tpl | 6 ++++- .../projects/shared-plugin/name/DataStore.qml | 15 +++++++++++ .../projects/shared-plugin/name/JsonData.qml | 9 +++++++ .../projects/shared-plugin/name/data.json | 4 +++ .../name/importmodule.qmldir.tpl | 1 + .../projects/shared-plugin/name/models.json | 24 +++++++++++++++++ .../projects/shared-plugin/name/qmldir | 1 + .../projects/qtquickapplication/wizard.json | 26 ++++++++++++------- 15 files changed, 175 insertions(+), 35 deletions(-) create mode 100644 share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml create mode 100644 share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/JsonData.qml create mode 100644 share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/data.json create mode 100644 share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/models.json 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 232dfd43199..cf30f9c91c7 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json @@ -367,14 +367,6 @@ "source": "../shared-plugin/name/Constants.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/Constants.qml" }, - { - "source": "../shared-plugin/name/DataStore.json.tpl", - "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.json" - }, - { - "source": "../shared-plugin/name/DataStore.qml.tpl", - "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" - }, { "source": "../shared-plugin/name/DirectoryFontLoader.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DirectoryFontLoader.qml" @@ -390,6 +382,22 @@ { "source": "../shared-plugin/name/designer/plugin.metainfo", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/designer/plugin.metainfo" + }, + { + "source": "../shared-plugin/name/JsonData.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" + }, + { + "source": "../shared-plugin/name/DataStore.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" + }, + { + "source": "../shared-plugin/name/models.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" + }, + { + "source": "../shared-plugin/name/data.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] } diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json index 2c5d6067505..6fd0637fb1a 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json @@ -380,14 +380,6 @@ "source": "../shared-plugin/name/Constants.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/Constants.qml" }, - { - "source": "../shared-plugin/name/DataStore.json.tpl", - "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.json" - }, - { - "source": "../shared-plugin/name/DataStore.qml.tpl", - "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" - }, { "source": "../shared-plugin/name/DirectoryFontLoader.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DirectoryFontLoader.qml" @@ -403,6 +395,22 @@ { "source": "../shared-plugin/name/designer/plugin.metainfo", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/designer/plugin.metainfo" + }, + { + "source": "../shared-plugin/name/JsonData.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" + }, + { + "source": "../shared-plugin/name/DataStore.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" + }, + { + "source": "../shared-plugin/name/models.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" + }, + { + "source": "../shared-plugin/name/data.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] } 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 6169688f16b..2a42e7222c8 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl @@ -63,6 +63,10 @@ Project { filter: "*.qsb" } + Files { + filter: "*.json" + } + Files { filter: "*.mesh" directory: "asset_imports" diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json index 81bbcb73f22..bb3e4851f9c 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json @@ -367,14 +367,6 @@ "source": "../shared-plugin/name/Constants.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/Constants.qml" }, - { - "source": "../shared-plugin/name/DataStore.json.tpl", - "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.json" - }, - { - "source": "../shared-plugin/name/DataStore.qml.tpl", - "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" - }, { "source": "../shared-plugin/name/DirectoryFontLoader.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DirectoryFontLoader.qml" @@ -390,6 +382,22 @@ { "source": "../shared-plugin/name/designer/plugin.metainfo", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/designer/plugin.metainfo" + }, + { + "source": "../shared-plugin/name/JsonData.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" + }, + { + "source": "../shared-plugin/name/DataStore.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" + }, + { + "source": "../shared-plugin/name/models.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" + }, + { + "source": "../shared-plugin/name/data.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] } diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json index 944b6b6289c..104d349bccf 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json @@ -341,6 +341,22 @@ { "source": "../shared-plugin/name/designer/plugin.metainfo", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/designer/plugin.metainfo" + }, + { + "source": "../shared-plugin/name/JsonData.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" + }, + { + "source": "../shared-plugin/name/DataStore.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" + }, + { + "source": "../shared-plugin/name/models.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" + }, + { + "source": "../shared-plugin/name/data.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] } diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json index c8733770e07..d8758ca2bf1 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json @@ -343,6 +343,22 @@ { "source": "../shared-plugin/name/designer/plugin.metainfo", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/designer/plugin.metainfo" + }, + { + "source": "../shared-plugin/name/JsonData.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" + }, + { + "source": "../shared-plugin/name/DataStore.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" + }, + { + "source": "../shared-plugin/name/models.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" + }, + { + "source": "../shared-plugin/name/data.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] } diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json index 295c85aa63a..0661a77b7b6 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json @@ -343,6 +343,22 @@ { "source": "../shared-plugin/name/designer/plugin.metainfo", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/designer/plugin.metainfo" + }, + { + "source": "../shared-plugin/name/JsonData.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" + }, + { + "source": "../shared-plugin/name/DataStore.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" + }, + { + "source": "../shared-plugin/name/models.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" + }, + { + "source": "../shared-plugin/name/data.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] } diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/CMakeLists.importmodule.txt.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/CMakeLists.importmodule.txt.tpl index 5606f3c7b14..3b74123f7b0 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/CMakeLists.importmodule.txt.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/CMakeLists.importmodule.txt.tpl @@ -11,10 +11,14 @@ qt6_add_qml_module(%{ImportModuleName} URI "%{ImportModuleName}" VERSION 1.0 RESOURCE_PREFIX "/qt/qml" - QML_FILES + QML_FILES Constants.qml DataStore.qml DirectoryFontLoader.qml EventListModel.qml EventListSimulator.qml + JsonData.qml + RESOURCES + data.json + models.json ) diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml new file mode 100644 index 00000000000..32acc1d8178 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml @@ -0,0 +1,15 @@ +pragma Singleton +import QtQuick 6.5 +import QtQuick.Studio.Utils 1.0 + +JsonListModel { + id: models + source: Qt.resolvedUrl("models.json") + + property ChildListModel exampleModel: ChildListModel { + modelName: "exampleModel" + } + + property JsonData backend: JsonData {} +} + diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/JsonData.qml b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/JsonData.qml new file mode 100644 index 00000000000..a49600e2704 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/JsonData.qml @@ -0,0 +1,9 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Studio.Utils 1.0 + +JsonBackend { + property string name: "someName" + property int number: 1 + source: Qt.resolvedUrl("data.json") +} diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/data.json b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/data.json new file mode 100644 index 00000000000..71208c18089 --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/data.json @@ -0,0 +1,4 @@ +{ + "name": "Christen Anderson", + "number": "+3455641" +} diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/importmodule.qmldir.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/importmodule.qmldir.tpl index a0ec2f17cfc..8f451c8494d 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/importmodule.qmldir.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/importmodule.qmldir.tpl @@ -4,3 +4,4 @@ singleton Constants 1.0 Constants.qml EventListSimulator 1.0 EventListSimulator.qml EventListModel 1.0 EventListModel.qml DirectoryFontLoader 1.0 DirectoryFontLoader.qml +singleton DataStore 1.0 DataStore.qml diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/models.json b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/models.json new file mode 100644 index 00000000000..17eb0e92b3f --- /dev/null +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/models.json @@ -0,0 +1,24 @@ +{ + "exampleModel": [ + { + "name": "Christen Anderson", + "number": "+3455641" + }, + { + "name": "Armanda Cox", + "number": "+21155641" + }, + { + "name": "Ken Garza", + "number": "+3288642" + }, + { + "name": "Rodney Hamilton", + "number": "+3558848" + }, + { + "name": "Andrew Battles", + "number": "+42488649" + } + ] +} diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/qmldir b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/qmldir index b5924a433cc..d99371ee1da 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/qmldir +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/qmldir @@ -3,3 +3,4 @@ singleton DataStore 1.0 DataStore.qml EventListModel 1.0 EventListModel.qml EventListSimulator 1.0 EventListSimulator.qml DirectoryFontLoader 1.0 DirectoryFontLoader.qml +singleton DataStore 1.0 DataStore.qml diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json index 64502bd1246..b1c8c5fb74f 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json @@ -242,16 +242,6 @@ "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/Constants.qml", "condition": "%{QdsProjectStyle}" }, - { - "source": "%{QdsWizardPath}/shared-plugin/name/DataStore.json.tpl", - "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.json", - "condition": "%{QdsProjectStyle}" - }, - { - "source": "%{QdsWizardPath}/shared-plugin/name/DataStore.qml.tpl", - "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml", - "condition": "%{QdsProjectStyle}" - }, { "source": "%{QdsWizardPath}/shared-plugin/name/DirectoryFontLoader.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DirectoryFontLoader.qml", @@ -271,6 +261,22 @@ "source": "%{QdsWizardPath}/shared-plugin/name/designer/plugin.metainfo", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/designer/plugin.metainfo", "condition": "%{QdsProjectStyle}" + }, + { + "source": "../shared-plugin/name/JsonData.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" + }, + { + "source": "../shared-plugin/name/DataStore.qml", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" + }, + { + "source": "../shared-plugin/name/models.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" + }, + { + "source": "../shared-plugin/name/data.json", + "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] } From 66bda77d432f3039c222e9621b08b5347bdcbcd4 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Mon, 20 Nov 2023 12:31:53 +0100 Subject: [PATCH 040/101] QmlDesigner: Make minimumSizeHint setting passive Remove the connection to the minimum size hint setting and the active call to the dock manager and force the user to restart design studio to apply changes. Change-Id: I2aca66b02a1f7658a2dac7322f6a530bf9f6b084 Reviewed-by: Tim Jenssen Reviewed-by: Qt CI Patch Build Bot Reviewed-by: --- src/plugins/qmldesigner/settingspage.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp index 19b329ad283..2f3582cdf70 100644 --- a/src/plugins/qmldesigner/settingspage.cpp +++ b/src/plugins/qmldesigner/settingspage.cpp @@ -4,7 +4,6 @@ #include "settingspage.h" #include "designersettings.h" -#include "designmodewidget.h" #include "qmldesignerexternaldependencies.h" #include "qmldesignerplugin.h" @@ -293,13 +292,6 @@ SettingsPageWidget::SettingsPageWidget(ExternalDependencies &externalDependencie m_styleLineEdit->setText(m_controls2StyleComboBox->currentText()); }); - connect(m_featureDockWidgetContentMinSize, &QCheckBox::toggled, this, [=](bool checked) { - if (checked && !m_featureDockWidgetContentMinSize->isChecked()) - m_featureDockWidgetContentMinSize->setChecked(true); - - QmlDesignerPlugin::instance()->mainWidget()->setMinimumSizeHintFromContentMinimumSize(checked); - }); - m_forwardPuppetOutputComboBox->addItems(puppetModes()); m_debugPuppetComboBox->addItems(puppetModes()); @@ -491,7 +483,8 @@ void SettingsPageWidget::apply() DesignerSettingsKey::FORWARD_PUPPET_OUTPUT, DesignerSettingsKey::DEBUG_PUPPET, DesignerSettingsKey::ENABLE_MODEL_EXCEPTION_OUTPUT, - DesignerSettingsKey::ENABLE_TIMELINEVIEW}; + DesignerSettingsKey::ENABLE_TIMELINEVIEW, + DesignerSettingsKey::ENABLE_DOCKWIDGET_CONTENT_MIN_SIZE}; for (const char * const key : restartNecessaryKeys) { if (QmlDesignerPlugin::settings().value(key) != settings.value(key)) { From b5da50338e39650a58669f0b933017f5e0bd50ea Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Thu, 23 Nov 2023 12:33:21 +0100 Subject: [PATCH 041/101] ADS: Prevent saving not displayed workspace Prevent saving a workspace that was never shown, e.g. only welcome page was shown and QtDS was closed again. This scenario causes the workspace to have wrong sizes hence the next time this workspace will be shown it will look distorted. This behavior is a result of the startup workspace always being loaded and always saved. If the workspace was never visually shown, it didn't get the correct geometry from the main window which results in wrong sizes of splitters in the workspace. Change-Id: I780b561e98e72f7d48becf32d178fb600b5d4336 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Tim Jenssen --- src/libs/advanceddockingsystem/dockmanager.cpp | 12 ++++++++++-- src/libs/advanceddockingsystem/dockmanager.h | 7 +++++++ src/libs/advanceddockingsystem/workspace.cpp | 10 ---------- src/libs/advanceddockingsystem/workspace.h | 4 ---- src/plugins/qmldesigner/designmodewidget.cpp | 1 + 5 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/libs/advanceddockingsystem/dockmanager.cpp b/src/libs/advanceddockingsystem/dockmanager.cpp index 15e7a9dbb15..af66f03b1a0 100644 --- a/src/libs/advanceddockingsystem/dockmanager.cpp +++ b/src/libs/advanceddockingsystem/dockmanager.cpp @@ -94,6 +94,7 @@ public: QtcSettings *m_settings = nullptr; bool m_modeChangeState = false; + bool m_wasShown = false; bool m_workspaceOrderDirty = false; /** @@ -364,8 +365,10 @@ DockManager::DockManager(QWidget *parent) DockManager::~DockManager() { - emit aboutToUnloadWorkspace(d->m_workspace.fileName()); - save(); + if (d->m_wasShown) { + emit aboutToUnloadWorkspace(d->m_workspace.fileName()); + save(); + } saveStartupWorkspace(); saveLockWorkspace(); @@ -1324,6 +1327,11 @@ bool DockManager::isModeChangeState() const return d->m_modeChangeState; } +void DockManager::aboutToShow() +{ + d->m_wasShown = true; +} + expected_str DockManager::importWorkspace(const QString &filePath) { qCInfo(adsLog) << "Import workspace" << filePath; diff --git a/src/libs/advanceddockingsystem/dockmanager.h b/src/libs/advanceddockingsystem/dockmanager.h index c11bd6ebb16..015e6724340 100644 --- a/src/libs/advanceddockingsystem/dockmanager.h +++ b/src/libs/advanceddockingsystem/dockmanager.h @@ -733,6 +733,13 @@ public: static QString readDisplayName(const Utils::FilePath &filePath); static bool writeDisplayName(const Utils::FilePath &filePath, const QString &displayName); + /** + * This is used to limit saving of workspaces to only when they were actually presented ones, + * otherwise it could lead to distorted workspace due to the correct windows sizes not being + * set when never presented/rendered. + */ + void aboutToShow(); + signals: void aboutToUnloadWorkspace(QString fileName); void aboutToLoadWorkspace(QString fileName); diff --git a/src/libs/advanceddockingsystem/workspace.cpp b/src/libs/advanceddockingsystem/workspace.cpp index 760e2c7dd1c..d3b0785d90b 100644 --- a/src/libs/advanceddockingsystem/workspace.cpp +++ b/src/libs/advanceddockingsystem/workspace.cpp @@ -41,16 +41,6 @@ const QString &Workspace::name() const return m_name; } -void Workspace::setLocked(bool value) -{ - m_locked = value; -} - -bool Workspace::isLocked() const -{ - return m_locked; -} - const Utils::FilePath &Workspace::filePath() const { return m_filePath; diff --git a/src/libs/advanceddockingsystem/workspace.h b/src/libs/advanceddockingsystem/workspace.h index 5e96e5a9815..c23db55d6b6 100644 --- a/src/libs/advanceddockingsystem/workspace.h +++ b/src/libs/advanceddockingsystem/workspace.h @@ -18,9 +18,6 @@ public: void setName(const QString &name); const QString &name() const; - void setLocked(bool value); - bool isLocked() const; - const Utils::FilePath &filePath() const; QString fileName() const; @@ -53,7 +50,6 @@ private: QString m_name; Utils::FilePath m_filePath; bool m_preset = false; - bool m_locked = false; }; } // namespace ADS diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp index bc566f4f756..fdbcb670b76 100644 --- a/src/plugins/qmldesigner/designmodewidget.cpp +++ b/src/plugins/qmldesigner/designmodewidget.cpp @@ -463,6 +463,7 @@ void DesignModeWidget::setup() this, [this](Utils::Id mode, Utils::Id previousMode) { if (mode == Core::Constants::MODE_DESIGN) { + m_dockManager->aboutToShow(); m_dockManager->reloadActiveWorkspace(); m_dockManager->setModeChangeState(false); } From 9affb29ddb79b86f15ea41b90866258f1eedecdc Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Fri, 24 Nov 2023 11:31:10 +0100 Subject: [PATCH 042/101] ADS: Fix FocusHighlighting when dragging tab Task-number: QDS-11172 Change-Id: Ibb159bb39a3e15797b468302c38531188e928ae9 Reviewed-by: Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Tim Jenssen --- src/libs/advanceddockingsystem/dockwidgettab.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libs/advanceddockingsystem/dockwidgettab.cpp b/src/libs/advanceddockingsystem/dockwidgettab.cpp index efea3d0b202..85c063beef8 100644 --- a/src/libs/advanceddockingsystem/dockwidgettab.cpp +++ b/src/libs/advanceddockingsystem/dockwidgettab.cpp @@ -372,12 +372,11 @@ void DockWidgetTab::mouseReleaseEvent(QMouseEvent *event) event->accept(); d->m_floatingWidget->finishDragging(); break; - - default: - if (DockManager::testConfigFlag(DockManager::FocusHighlighting)) - d->focusController()->setDockWidgetTabPressed(false); - break; } + + if (DockManager::testConfigFlag(DockManager::FocusHighlighting)) + d->focusController()->setDockWidgetTabPressed(false); + } else if (event->button() == Qt::MiddleButton) { if (DockManager::testConfigFlag(DockManager::MiddleMouseButtonClosesTab) && d->m_dockWidget->features().testFlag(DockWidget::DockWidgetClosable)) { From e1d450bcaf029ee5937e7ca3b493dcc529954dcc Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 24 Nov 2023 15:36:40 +0200 Subject: [PATCH 043/101] EffectMaker: Don't allow saving with pressing enter if save is disabled Fixes: QDS-11392 Change-Id: Ia600489b39d58a0224f17856f9ab6e2110faee82 Reviewed-by: Mahmoud Badri --- .../qmldesigner/effectMakerQmlSources/SaveDialog.qml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveDialog.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveDialog.qml index 8bd48e1d6c4..60ddae35452 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveDialog.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveDialog.qml @@ -83,8 +83,10 @@ StudioControls.Dialog { text: qsTr("Save") enabled: nameText.text !== "" onClicked: { - root.compositionName = nameText.text - root.accept() //TODO: Check if name is unique + if (btnSave.enabled) { + root.compositionName = nameText.text + root.accept() //TODO: Check if name is unique + } } } From d9671c62d967f27363f8d924c435aac982d5cdb6 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Fri, 24 Nov 2023 14:43:29 +0100 Subject: [PATCH 044/101] ADS: Fix switch enum not handled warning Change-Id: I7b9dd5f5cf3dde535aa099a9a64203060174123e Reviewed-by: Tim Jenssen --- src/libs/advanceddockingsystem/dockwidgettab.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libs/advanceddockingsystem/dockwidgettab.cpp b/src/libs/advanceddockingsystem/dockwidgettab.cpp index 85c063beef8..e5b0fb33a23 100644 --- a/src/libs/advanceddockingsystem/dockwidgettab.cpp +++ b/src/libs/advanceddockingsystem/dockwidgettab.cpp @@ -372,6 +372,9 @@ void DockWidgetTab::mouseReleaseEvent(QMouseEvent *event) event->accept(); d->m_floatingWidget->finishDragging(); break; + + default: + break; } if (DockManager::testConfigFlag(DockManager::FocusHighlighting)) From fceb1a2e6323abca50eb6f4fe98edb9e6f2ee093 Mon Sep 17 00:00:00 2001 From: Aleksei German Date: Fri, 24 Nov 2023 16:22:24 +0100 Subject: [PATCH 045/101] QmlDesigner: Fix Kit selector for MCU projects Task-number: QDS-10337 Change-Id: I896eb826d75fd9ee08e083d45b8f7180abf53c37 Reviewed-by: Aleksei German --- share/qtcreator/qmldesigner/statusbar/Main.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/share/qtcreator/qmldesigner/statusbar/Main.qml b/share/qtcreator/qmldesigner/statusbar/Main.qml index 1eb33b82360..da18cf67938 100644 --- a/share/qtcreator/qmldesigner/statusbar/Main.qml +++ b/share/qtcreator/qmldesigner/statusbar/Main.qml @@ -63,7 +63,8 @@ Item { model: backend.kits onActivated: backend.setCurrentKit(kits.currentIndex) openUpwards: true - enabled: (backend.isInDesignMode || (backend.isInEditMode && backend.projectOpened)) && backend.isQt6 + enabled: (backend.isInDesignMode || (backend.isInEditMode && backend.projectOpened)) + && backend.isQt6 && !backend.isMCUs property int kitIndex: backend.currentKit onKitIndexChanged: kits.currentIndex = backend.currentKit } From d0fccdc02590af3429cebaae4edb5fc9bc6221ff Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Fri, 24 Nov 2023 16:48:50 +0100 Subject: [PATCH 046/101] QmlDesigner: Fix signal name prefix removal Only remove the first to characters of a signal name, if it matches the regular expression. Task-number: QDS-11385 Change-Id: Icc61f2c5281c15842729f67d3b0498c80637ceb1 Reviewed-by: Tim Jenssen Reviewed-by: Qt CI Patch Build Bot --- .../components/connectioneditor/connectionmodel.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp index dd6350f4e56..88cdc8e52a9 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -859,6 +860,11 @@ QString removeOnFromSignalName(const QString &signal) { if (signal.isEmpty()) return {}; + + static const QRegularExpression rx("^on[A-Z]"); + if (!rx.match(signal).hasMatch()) + return signal; + QString ret = signal; ret.remove(0, 2); ret[0] = ret.at(0).toLower(); From e16a302a435b3e1983286b3b8ff682531230a4f9 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Fri, 24 Nov 2023 14:15:22 +0100 Subject: [PATCH 047/101] ADS: Integrate newest base repository commits * Update to newest version of ADS * Fix memory leak in DockContainerWidget Base repository was merged until commit 59b4dfb89c0c9c0e6035fe580088432312ed2d09 Change-Id: I357b21888fe6f0ec2160c8688d84cb7ecdcad079 Reviewed-by: Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Tim Jenssen --- src/libs/advanceddockingsystem/ads_globals.h | 16 ++-- .../dockareatitlebar.cpp | 85 ++++++++++++++++--- .../advanceddockingsystem/dockareatitlebar.h | 7 ++ .../advanceddockingsystem/dockareawidget.cpp | 20 +++-- .../dockcontainerwidget.cpp | 6 +- .../advanceddockingsystem/dockmanager.cpp | 37 ++++++++ src/libs/advanceddockingsystem/dockmanager.h | 34 +++++++- src/libs/advanceddockingsystem/dockwidget.cpp | 49 +++++++++++ src/libs/advanceddockingsystem/dockwidget.h | 19 +++++ .../components/resources/dockwidgets.css | 8 +- 10 files changed, 247 insertions(+), 34 deletions(-) diff --git a/src/libs/advanceddockingsystem/ads_globals.h b/src/libs/advanceddockingsystem/ads_globals.h index 6fc590f4718..364f49e01e2 100644 --- a/src/libs/advanceddockingsystem/ads_globals.h +++ b/src/libs/advanceddockingsystem/ads_globals.h @@ -66,7 +66,8 @@ enum eTitleBarButton { TitleBarButtonTabsMenu, TitleBarButtonUndock, TitleBarButtonClose, - TitleBarButtonAutoHide + TitleBarButtonAutoHide, + TitleBarButtonMinimize }; /** @@ -83,16 +84,17 @@ enum eDragState { * The different icons used in the UI */ enum eIcon { - TabCloseIcon, //!< TabCloseIcon - AutoHideIcon, //!< AutoHideIcon - DockAreaMenuIcon, //!< DockAreaMenuIcon - DockAreaUndockIcon, //!< DockAreaUndockIcon - DockAreaCloseIcon, //!< DockAreaCloseIcon + TabCloseIcon, //!< TabCloseIcon + AutoHideIcon, //!< AutoHideIcon + DockAreaMenuIcon, //!< DockAreaMenuIcon + DockAreaUndockIcon, //!< DockAreaUndockIcon + DockAreaCloseIcon, //!< DockAreaCloseIcon + DockAreaMinimizeIcon, FloatingWidgetCloseIcon, //!< FloatingWidgetCloseIcon FloatingWidgetNormalIcon, //!< FloatingWidgetNormalIcon FloatingWidgetMaximizeIcon, //!< FloatingWidgetMaximizeIcon - IconCount, //!< just a delimiter for range checks + IconCount, //!< just a delimiter for range checks }; /** diff --git a/src/libs/advanceddockingsystem/dockareatitlebar.cpp b/src/libs/advanceddockingsystem/dockareatitlebar.cpp index 7a2e6770621..54f97307da3 100644 --- a/src/libs/advanceddockingsystem/dockareatitlebar.cpp +++ b/src/libs/advanceddockingsystem/dockareatitlebar.cpp @@ -48,10 +48,11 @@ public: QPointer m_autoHideButton; QPointer m_undockButton; QPointer m_closeButton; + QPointer m_minimizeButton; QBoxLayout *m_layout = nullptr; DockAreaWidget *m_dockArea = nullptr; DockAreaTabBar *m_tabBar = nullptr; - ElidingLabel *m_autoHideTitleLabel; + ElidingLabel *m_autoHideTitleLabel = nullptr; bool m_menuOutdated = true; QMenu *m_tabsMenu; QList m_dockWidgetActionsButtons; @@ -202,6 +203,23 @@ void DockAreaTitleBarPrivate::createButtons() q, &DockAreaTitleBar::onAutoHideButtonClicked); + // Minimize button + m_minimizeButton = new TitleBarButton( + testAutoHideConfigFlag(DockManager::AutoHideHasMinimizeButton)); + m_minimizeButton->setObjectName("dockAreaMinimizeButton"); + //m_minimizeButton->setAutoRaise(true); + m_minimizeButton->setVisible(false); + internal::setButtonIcon(m_minimizeButton, + QStyle::SP_TitleBarMinButton, + ADS::DockAreaMinimizeIcon); + internal::setToolTip(m_minimizeButton, QObject::tr("Minimize")); + m_minimizeButton->setSizePolicy(sizePolicy); + m_layout->addWidget(m_minimizeButton, 0); + QObject::connect(m_minimizeButton, + &QToolButton::clicked, + q, + &DockAreaTitleBar::minimizeAutoHideContainer); + // Close button m_closeButton = new TitleBarButton(testConfigFlag(DockManager::DockAreaHasCloseButton)); m_closeButton->setObjectName("dockAreaCloseButton"); @@ -228,7 +246,10 @@ void DockAreaTitleBarPrivate::createAutoHideTitleLabel() { m_autoHideTitleLabel = new ElidingLabel(""); m_autoHideTitleLabel->setObjectName("autoHideTitleLabel"); - m_layout->addWidget(m_autoHideTitleLabel); + // At position 0 is the tab bar - insert behind tab bar + m_layout->insertWidget(1, m_autoHideTitleLabel); + m_autoHideTitleLabel->setVisible(false); // Default hidden + m_layout->insertWidget(2, new SpacerWidget(q)); } void DockAreaTitleBarPrivate::createTabBar() { @@ -370,10 +391,8 @@ DockAreaTitleBar::DockAreaTitleBar(DockAreaWidget *parent) setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); d->createTabBar(); - d->createAutoHideTitleLabel(); - d->m_autoHideTitleLabel->setVisible(false); // Default hidden - d->m_layout->addWidget(new SpacerWidget(this)); d->createButtons(); + d->createAutoHideTitleLabel(); setFocusPolicy(Qt::NoFocus); } @@ -452,6 +471,18 @@ void DockAreaTitleBar::onCloseButtonClicked() d->m_dockArea->closeArea(); } +void DockAreaTitleBar::onAutoHideCloseActionTriggered() +{ + d->m_dockArea->closeArea(); +} + +void DockAreaTitleBar::minimizeAutoHideContainer() +{ + auto autoHideContainer = d->m_dockArea->autoHideDockContainer(); + if (autoHideContainer) + autoHideContainer->collapseView(true); +} + void DockAreaTitleBar::onUndockButtonClicked() { if (d->m_dockArea->features().testFlag(DockWidget::DockWidgetFloatable)) @@ -543,6 +574,8 @@ TitleBarButton *DockAreaTitleBar::button(eTitleBarButton which) const return d->m_closeButton; case TitleBarButtonAutoHide: return d->m_autoHideButton; + case TitleBarButtonMinimize: + return d->m_minimizeButton; } return nullptr; } @@ -686,12 +719,28 @@ void DockAreaTitleBar::contextMenuEvent(QContextMenuEvent *event) } menu.addSeparator(); } - QAction *closeAction = menu.addAction(isAutoHide ? Tr::tr("Close") : Tr::tr("Close Group")); - closeAction->connect(closeAction, - &QAction::triggered, - this, - &DockAreaTitleBar::onCloseButtonClicked); - closeAction->setEnabled(d->m_dockArea->features().testFlag(DockWidget::DockWidgetClosable)); + + if (isAutoHide) { + QAction *minimizeAction = menu.addAction(Tr::tr("Minimize")); + minimizeAction->connect(minimizeAction, + &QAction::triggered, + this, + &DockAreaTitleBar::minimizeAutoHideContainer); + + QAction *closeAction = menu.addAction(Tr::tr("Close")); + closeAction->connect(closeAction, + &QAction::triggered, + this, + &DockAreaTitleBar::onAutoHideCloseActionTriggered); + closeAction->setEnabled(d->m_dockArea->features().testFlag(DockWidget::DockWidgetClosable)); + } else { + QAction *closeAction = menu.addAction(Tr::tr("Close Group")); + closeAction->connect(closeAction, + &QAction::triggered, + this, + &DockAreaTitleBar::onCloseButtonClicked); + closeAction->setEnabled(d->m_dockArea->features().testFlag(DockWidget::DockWidgetClosable)); + } if (!isAutoHide && !isTopLevelArea) { QAction *closeOthersAction = menu.addAction(Tr::tr("Close Other Groups")); @@ -728,8 +777,11 @@ QString DockAreaTitleBar::titleBarButtonToolTip(eTitleBarButton button) const break; case TitleBarButtonClose: - if (d->m_dockArea->isAutoHide()) - return Tr::tr("Close"); + if (d->m_dockArea->isAutoHide()) { + bool minimize = DockManager::testAutoHideConfigFlag( + DockManager::AutoHideCloseButtonCollapsesDock); + return minimize ? Tr::tr("Minimize") : Tr::tr("Close"); + } if (DockManager::testConfigFlag(DockManager::DockAreaCloseButtonClosesTab)) return Tr::tr("Close Active Tab"); @@ -758,4 +810,11 @@ void DockAreaTitleBar::setAreaFloating() d->makeAreaFloating(mapFromGlobal(QCursor::pos()), DraggingInactive); } +void DockAreaTitleBar::showAutoHideControls(bool show) +{ + d->m_tabBar->setVisible(!show); // Auto hide toolbar never has tabs + d->m_minimizeButton->setVisible(show); + d->m_autoHideTitleLabel->setVisible(show); +} + } // namespace ADS diff --git a/src/libs/advanceddockingsystem/dockareatitlebar.h b/src/libs/advanceddockingsystem/dockareatitlebar.h index 738dea476de..d710a12194b 100644 --- a/src/libs/advanceddockingsystem/dockareatitlebar.h +++ b/src/libs/advanceddockingsystem/dockareatitlebar.h @@ -84,6 +84,8 @@ private: void onTabsMenuAboutToShow(); void onCloseButtonClicked(); + void onAutoHideCloseActionTriggered(); + void minimizeAutoHideContainer(); void onUndockButtonClicked(); void onTabsMenuActionTriggered(QAction *action); void onCurrentTabChanged(int index); @@ -191,6 +193,11 @@ public: */ void setAreaFloating(); + /** + * Call this function, to create all the required auto hide controls + */ + void showAutoHideControls(bool show); + signals: /** * This signal is emitted if a tab in the tab bar is clicked by the user diff --git a/src/libs/advanceddockingsystem/dockareawidget.cpp b/src/libs/advanceddockingsystem/dockareawidget.cpp index cc263895af6..5cf12d70509 100644 --- a/src/libs/advanceddockingsystem/dockareawidget.cpp +++ b/src/libs/advanceddockingsystem/dockareawidget.cpp @@ -295,13 +295,20 @@ void DockAreaWidgetPrivate::updateTitleBarButtonVisibility(bool isTopLevel) if (!container) return; - if (isTopLevel) { + bool isAutoHide = q->isAutoHide(); + if (isAutoHide) { + bool showCloseButton = DockManager::autoHideConfigFlags().testFlag( + DockManager::AutoHideHasCloseButton); + m_titleBar->button(TitleBarButtonClose)->setVisible(showCloseButton); + m_titleBar->button(TitleBarButtonAutoHide)->setVisible(true); + m_titleBar->button(TitleBarButtonUndock)->setVisible(false); + m_titleBar->button(TitleBarButtonTabsMenu)->setVisible(false); + } else if (isTopLevel) { m_titleBar->button(TitleBarButtonClose)->setVisible(!container->isFloating()); m_titleBar->button(TitleBarButtonAutoHide)->setVisible(!container->isFloating()); // Undock and tabs should never show when auto hidden - m_titleBar->button(TitleBarButtonUndock) - ->setVisible(!container->isFloating() && !q->isAutoHide()); - m_titleBar->button(TitleBarButtonTabsMenu)->setVisible(!q->isAutoHide()); + m_titleBar->button(TitleBarButtonUndock)->setVisible(!container->isFloating()); + m_titleBar->button(TitleBarButtonTabsMenu)->setVisible(true); } else { m_titleBar->button(TitleBarButtonClose)->setVisible(true); m_titleBar->button(TitleBarButtonAutoHide)->setVisible(true); @@ -650,10 +657,7 @@ void DockAreaWidget::updateTitleBarVisibility() } if (isAutoHideFeatureEnabled()) { - auto tabBar = d->m_titleBar->tabBar(); - tabBar->setVisible(!autoHide); // Never show tab bar when auto hidden - // Always show when auto hidden, never otherwise - d->m_titleBar->autoHideTitleLabel()->setVisible(autoHide); + d->m_titleBar->showAutoHideControls(autoHide); updateTitleBarButtonVisibility(container->topLevelDockArea() == this); } } diff --git a/src/libs/advanceddockingsystem/dockcontainerwidget.cpp b/src/libs/advanceddockingsystem/dockcontainerwidget.cpp index c57e277eddb..11bbb1f23c5 100644 --- a/src/libs/advanceddockingsystem/dockcontainerwidget.cpp +++ b/src/libs/advanceddockingsystem/dockcontainerwidget.cpp @@ -484,9 +484,10 @@ void DockContainerWidgetPrivate::dropIntoSection(FloatingDockContainer *floating if (!targetAreaSplitter) { auto splitter = createSplitter(insertParam.orientation()); - m_layout->replaceWidget(targetArea, splitter); + QLayoutItem *layoutItem = m_layout->replaceWidget(targetArea, splitter); splitter->addWidget(targetArea); targetAreaSplitter = splitter; + delete layoutItem; } int areaIndex = targetAreaSplitter->indexOf(targetArea); auto floatingSplitter = floatingContainer->rootSplitter(); @@ -1532,10 +1533,11 @@ bool DockContainerWidget::restoreState(DockingStateReader &stateReader, bool tes if (!newRootSplitter) newRootSplitter = d->createSplitter(Qt::Horizontal); - d->m_layout->replaceWidget(d->m_rootSplitter, newRootSplitter); + QLayoutItem *layoutItem = d->m_layout->replaceWidget(d->m_rootSplitter, newRootSplitter); auto oldRoot = d->m_rootSplitter; d->m_rootSplitter = qobject_cast(newRootSplitter); oldRoot->deleteLater(); + delete layoutItem; return true; } diff --git a/src/libs/advanceddockingsystem/dockmanager.cpp b/src/libs/advanceddockingsystem/dockmanager.cpp index af66f03b1a0..a30ffb42e1d 100644 --- a/src/libs/advanceddockingsystem/dockmanager.cpp +++ b/src/libs/advanceddockingsystem/dockmanager.cpp @@ -87,6 +87,11 @@ public: DockWidget *m_centralWidget = nullptr; bool m_isLeavingMinimized = false; + Qt::ToolButtonStyle m_toolBarStyleDocked = Qt::ToolButtonIconOnly; + Qt::ToolButtonStyle m_toolBarStyleFloating = Qt::ToolButtonTextUnderIcon; + QSize m_toolBarIconSizeDocked = QSize(16, 16); + QSize m_toolBarIconSizeFloating = QSize(24, 24); + QString m_workspacePresetsPath; QList m_workspaces; Workspace m_workspace; @@ -769,6 +774,38 @@ QString DockManager::floatingContainersTitle() return g_floatingContainersTitle; } +void DockManager::setDockWidgetToolBarStyle(Qt::ToolButtonStyle style, DockWidget::eState state) +{ + if (DockWidget::StateFloating == state) + d->m_toolBarStyleFloating = style; + else + d->m_toolBarStyleDocked = style; +} + +Qt::ToolButtonStyle DockManager::dockWidgetToolBarStyle(DockWidget::eState state) const +{ + if (DockWidget::StateFloating == state) + return d->m_toolBarStyleFloating; + else + return d->m_toolBarStyleDocked; +} + +void DockManager::setDockWidgetToolBarIconSize(const QSize &iconSize, DockWidget::eState state) +{ + if (DockWidget::StateFloating == state) + d->m_toolBarIconSizeFloating = iconSize; + else + d->m_toolBarIconSizeDocked = iconSize; +} + +QSize DockManager::dockWidgetToolBarIconSize(DockWidget::eState state) const +{ + if (DockWidget::StateFloating == state) + return d->m_toolBarIconSizeFloating; + else + return d->m_toolBarIconSizeDocked; +} + DockWidget *DockManager::centralWidget() const { return d->m_centralWidget; diff --git a/src/libs/advanceddockingsystem/dockmanager.h b/src/libs/advanceddockingsystem/dockmanager.h index 015e6724340..53117b93e6b 100644 --- a/src/libs/advanceddockingsystem/dockmanager.h +++ b/src/libs/advanceddockingsystem/dockmanager.h @@ -186,10 +186,13 @@ public: = 0x20, ///< show the auto hide window on mouse over tab and hide it if mouse leaves auto hide container AutoHideCloseButtonCollapsesDock = 0x40, ///< Close button of an auto hide container collapses the dock instead of hiding it completely + AutoHideHasCloseButton + = 0x80, //< If the flag is set an auto hide title bar has a close button + AutoHideHasMinimizeButton + = 0x100, ///< if this flag is set, the auto hide title bar has a minimize button to collapse the dock widget - DefaultAutoHideConfig - = AutoHideFeatureEnabled | DockAreaHasAutoHideButton - | AutoHideCloseButtonCollapsesDock ///< the default configuration for left and right side bars + DefaultAutoHideConfig = AutoHideFeatureEnabled | DockAreaHasAutoHideButton + | AutoHideCloseButtonCollapsesDock | AutoHideHasCloseButton }; Q_DECLARE_FLAGS(AutoHideFlags, eAutoHideFlag) @@ -452,6 +455,31 @@ public: */ static QString floatingContainersTitle(); + /** + * This function sets the tool button style for the given dock widget state. It is possible to + * switch the tool button style depending on the state. If a dock widget is floating, then here + * are more space and it is possible to select a style that requires more space like + * Qt::ToolButtonTextUnderIcon. For the docked state Qt::ToolButtonIconOnly might be better. + */ + void setDockWidgetToolBarStyle(Qt::ToolButtonStyle style, DockWidget::eState state); + + /** + * Returns the tool button style for the given docking state. \see setToolBarStyle() + */ + Qt::ToolButtonStyle dockWidgetToolBarStyle(DockWidget::eState state) const; + + /** + * This function sets the tool button icon size for the given state. If a dock widget is + * floating, there is more space and increasing the icon size is possible. For docked widgets, + * small icon sizes, eg. 16 x 16 might be better. + */ + void setDockWidgetToolBarIconSize(const QSize &iconSize, DockWidget::eState state); + + /** + * Returns the icon size for a given docking state. \see setToolBarIconSize() + */ + QSize dockWidgetToolBarIconSize(DockWidget::eState state) const; + /** * This function returns managers central widget or nullptr if no central widget is set. */ diff --git a/src/libs/advanceddockingsystem/dockwidget.cpp b/src/libs/advanceddockingsystem/dockwidget.cpp index 6c89c92c66f..9c9e6086cd5 100644 --- a/src/libs/advanceddockingsystem/dockwidget.cpp +++ b/src/libs/advanceddockingsystem/dockwidget.cpp @@ -64,6 +64,7 @@ public: = DockWidget::MinimumSizeHintFromDockWidget; WidgetFactory *m_factory = nullptr; QPointer m_sideTabWidget; + DockWidget::eToolBarStyleSource m_toolBarStyleSource = DockWidget::ToolBarStyleFromDockManager; /** * Private data constructor @@ -106,6 +107,11 @@ public: * Creates the content widget with the registered widget factory and returns true on success. */ bool createWidgetFromFactory(); + + /** + * Use the dock manager toolbar style and icon size for the different states + */ + void setToolBarStyleFromDockManager(); }; // class DockWidgetPrivate DockWidgetPrivate::DockWidgetPrivate(DockWidget *parent) @@ -246,6 +252,19 @@ bool DockWidgetPrivate::createWidgetFromFactory() return true; } +void DockWidgetPrivate::setToolBarStyleFromDockManager() +{ + if (!m_dockManager) + return; + + auto state = DockWidget::StateDocked; + q->setToolBarIconSize(m_dockManager->dockWidgetToolBarIconSize(state), state); + q->setToolBarStyle(m_dockManager->dockWidgetToolBarStyle(state), state); + state = DockWidget::StateFloating; + q->setToolBarIconSize(m_dockManager->dockWidgetToolBarIconSize(state), state); + q->setToolBarStyle(m_dockManager->dockWidgetToolBarStyle(state), state); +} + DockWidget::DockWidget(const QString &uniqueId, QWidget *parent) : QFrame(parent) , d(new DockWidgetPrivate(this)) @@ -381,6 +400,12 @@ DockManager *DockWidget::dockManager() const void DockWidget::setDockManager(DockManager *dockManager) { d->m_dockManager = dockManager; + + if (!dockManager) + return; + + if (ToolBarStyleFromDockManager == d->m_toolBarStyleSource) + d->setToolBarStyleFromDockManager(); } DockContainerWidget *DockWidget::dockContainer() const @@ -491,6 +516,18 @@ QAction *DockWidget::toggleViewAction() const return d->m_toggleViewAction; } +void DockWidget::setToggleViewAction(QAction *action) +{ + if (!action) + return; + + d->m_toggleViewAction->setParent(nullptr); + delete d->m_toggleViewAction; + d->m_toggleViewAction = action; + d->m_toggleViewAction->setParent(this); + connect(d->m_toggleViewAction, &QAction::triggered, this, &DockWidget::toggleView); +} + void DockWidget::setToggleViewActionMode(eToggleViewActionMode mode) { if (ActionModeToggle == mode) { @@ -693,6 +730,18 @@ void DockWidget::setToolBar(QToolBar *toolBar) setToolbarFloatingStyle(isFloating()); } +void DockWidget::setToolBarStyleSource(eToolBarStyleSource source) +{ + d->m_toolBarStyleSource = source; + if (ToolBarStyleFromDockManager == d->m_toolBarStyleSource) + d->setToolBarStyleFromDockManager(); +} + +DockWidget::eToolBarStyleSource DockWidget::toolBarStyleSource() const +{ + return d->m_toolBarStyleSource; +} + void DockWidget::setToolBarStyle(Qt::ToolButtonStyle style, eState state) { if (StateFloating == state) diff --git a/src/libs/advanceddockingsystem/dockwidget.h b/src/libs/advanceddockingsystem/dockwidget.h index 65495cc04d6..03c92227664 100644 --- a/src/libs/advanceddockingsystem/dockwidget.h +++ b/src/libs/advanceddockingsystem/dockwidget.h @@ -154,6 +154,8 @@ public: enum eState { StateHidden, StateDocked, StateFloating }; + enum eToolBarStyleSource { ToolBarStyleFromDockManager, ToolBarStyleFromDockWidget }; + /** * Sets the widget for the dock widget to widget. * The InsertMode defines how the widget is inserted into the dock widget. @@ -385,6 +387,12 @@ public: */ QAction *toggleViewAction() const; + /** + * Use provided action to be the default toggle view action for this dock widget. + * This dock widget now owns the action. + */ + void setToggleViewAction(QAction *action); + /** * Configures the behavior of the toggle view action. * \see eToggleViewActionMode for a detailed description @@ -443,6 +451,17 @@ public: */ void setToolBar(QToolBar *toolBar); + /** + * Configures, if the dock widget uses the global tool bar styles from + * dock manager or if it uses its own tool bar style + */ + void setToolBarStyleSource(eToolBarStyleSource source); + + /** + * Returns the configured tool bar style source + */ + eToolBarStyleSource toolBarStyleSource() const; + /** * This function sets the tool button style for the given dock widget state. * It is possible to switch the tool button style depending on the state. diff --git a/src/plugins/qmldesigner/components/resources/dockwidgets.css b/src/plugins/qmldesigner/components/resources/dockwidgets.css index 2fc05b6014f..88ccadc4873 100644 --- a/src/plugins/qmldesigner/components/resources/dockwidgets.css +++ b/src/plugins/qmldesigner/components/resources/dockwidgets.css @@ -286,7 +286,8 @@ ADS--AutoHideDockContainer ADS--DockAreaWidget[focused="true"] ADS--DockAreaTitl /* AutoHideDockContainer titlebar buttons */ #dockAreaAutoHideButton { - /*qproperty-icon: url(:/ads/images/vs-pin-button.svg);*/ + /*qproperty-icon: url(:/ads/images/vs-pin-button.svg), + url(:/ads/images/vs-pin-button-disabled.svg) disabled;*/ qproperty-iconSize: 16px; } @@ -295,6 +296,11 @@ ADS--AutoHideDockContainer #dockAreaAutoHideButton { qproperty-iconSize: 16px; } +ADS--AutoHideDockContainer #dockAreaMinimizeButton { + /*qproperty-icon: url(:/ads/images/minimize-button-focused.svg);*/ + qproperty-iconSize: 16px; +} + ADS--AutoHideDockContainer #dockAreaCloseButton{ /*qproperty-icon: url(:/ads/images/close-button-focused.svg)*/ } From 49d3e6fddc230874ab7adef8744ceca96b856669 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Fri, 24 Nov 2023 15:43:30 +0100 Subject: [PATCH 048/101] qds: add Qt Shade Baker binary Task-number: QDS-11387 Change-Id: Ibea4c241fcaaecffc7f3a29b8fc68fda442c5104 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Tim Jenssen --- scripts/deploy.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/scripts/deploy.py b/scripts/deploy.py index 5dd6198eca6..15ddd3ced04 100755 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -147,20 +147,20 @@ def copy_qt_libs(target_qt_prefix_path, qt_bin_dir, qt_libs_dir): shutil.copy(library, lib_dest) -def deploy_qtdiag(qtc_binary_path, qt_install): - print("Copying qtdiag") - qtdiag_src = os.path.join(qt_install.bin, with_exe_ext('qtdiag')) +def deploy_binary(binary_name, qtc_binary_path, qt_install): + print(f"Copying {binary_name}") + binary_src = os.path.join(qt_install.bin, with_exe_ext(binary_name)) destdir = (qtc_binary_path if common.is_windows_platform() else os.path.join(qtc_binary_path, 'Contents', 'MacOS') if common.is_mac_platform() else os.path.join(qtc_binary_path, '..', 'lib', 'Qt', 'bin')) if not os.path.exists(destdir): os.makedirs(destdir) - shutil.copy(qtdiag_src, destdir) + shutil.copy(binary_src, destdir) if common.is_mac_platform(): # fix RPATHs - qtdiag_dest = os.path.join(destdir, 'qtdiag') - subprocess.check_call(['xcrun', 'install_name_tool', '-add_rpath', '@loader_path/../Frameworks', qtdiag_dest]) - subprocess.check_call(['xcrun', 'install_name_tool', '-delete_rpath', '@loader_path/../lib', qtdiag_dest]) + binary_dest = os.path.join(destdir, binary_name) + subprocess.check_call(['xcrun', 'install_name_tool', '-add_rpath', '@loader_path/../Frameworks', binary_dest]) + subprocess.check_call(['xcrun', 'install_name_tool', '-delete_rpath', '@loader_path/../lib', binary_dest]) def deploy_plugins(qtc_binary_path, qt_install): @@ -469,7 +469,8 @@ def main(): qtcreator_binary_path = (args.qtcreator_binary if common.is_mac_platform() else os.path.dirname(args.qtcreator_binary)) - deploy_qtdiag(qtcreator_binary_path, qt_install) + deploy_binary('qtdiag', qt_install) + deploy_binary('qsb', qt_install) deploy_plugins(qtcreator_binary_path, qt_install) deploy_imports(qtcreator_binary_path, qt_install) deploy_translations(qtcreator_binary_path, qt_install) From 37228f6da67e81a1c7739bc800bcfcb40b8157d5 Mon Sep 17 00:00:00 2001 From: Aleksei German Date: Fri, 24 Nov 2023 17:23:22 +0100 Subject: [PATCH 049/101] QmlDesigner: Fix Connections for items without ids MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task-number: QDS-7711 Change-Id: Ie686a7a456dd8cee57d63480913cd6f636af3e91 Reviewed-by: Henning Gründl Reviewed-by: Qt CI Patch Build Bot --- .../components/connectioneditor/connectionmodel.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp index 88cdc8e52a9..f693049e575 100644 --- a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp +++ b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp @@ -388,8 +388,7 @@ void ConnectionModel::addConnection(const PropertyName &signalName) || QmlVisualNode(selectedNode).isFlowTransition()) source = selectedNode.validId() + ".trigger()"; - if (!connectionView()->selectedModelNodes().constFirst().id().isEmpty()) - newNode.bindingProperty("target").setExpression(selectedNode.validId()); + newNode.bindingProperty("target").setExpression(selectedNode.validId()); } else { rootModelNode .nodeAbstractProperty(rootModelNode.metaInfo().defaultPropertyName()) From f6b5afa8e403655810b9ab80d2c2889bafcfd5a2 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Fri, 24 Nov 2023 18:33:19 +0100 Subject: [PATCH 050/101] Cmake: DS does not want automatic detection of cmake help file Task-number: QDS-9780 Change-Id: I006b27ee21a910f6d5095f09406b0f4e95a62c35 Reviewed-by: Tim Jenssen --- src/plugins/cmakeprojectmanager/cmakesettingspage.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp index 10f03133850..4d2a0dc5f3e 100644 --- a/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp +++ b/src/plugins/cmakeprojectmanager/cmakesettingspage.cpp @@ -9,6 +9,7 @@ #include "cmaketoolmanager.h" #include +#include #include #include @@ -453,6 +454,9 @@ void CMakeToolItemConfigWidget::onBinaryPathEditingFinished() void CMakeToolItemConfigWidget::updateQchFilePath() { + // QDS does not want automatic detection of cmake help file + if (Core::ICore::isQtDesignStudio()) + return; if (m_qchFileChooser->filePath().isEmpty()) m_qchFileChooser->setFilePath(CMakeTool::searchQchFile(m_binaryChooser->filePath())); } From 24968dbabd05fafd9a8eabcfcb81ec0ec6b235d3 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Thu, 23 Nov 2023 12:43:29 +0200 Subject: [PATCH 051/101] QmlDesigner: Update DataStore.qml when collections change Task-number: QDS-11113 Change-Id: I27d49d40a36a22e9af447087e7e8f7995812f1e3 Reviewed-by: Reviewed-by: Mahmoud Badri --- src/plugins/qmldesigner/CMakeLists.txt | 1 + .../collectioneditorconstants.h | 12 +- .../collectioneditorutils.cpp | 27 ++- .../collectioneditor/collectioneditorutils.h | 2 +- .../collectionsourcemodel.cpp | 10 +- .../collectioneditor/collectionsourcemodel.h | 1 + .../collectioneditor/collectionview.cpp | 45 +++- .../collectioneditor/collectionview.h | 7 +- .../collectioneditor/datastoremodelnode.cpp | 214 ++++++++++++++++++ .../collectioneditor/datastoremodelnode.h | 37 +++ 10 files changed, 331 insertions(+), 25 deletions(-) create mode 100644 src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp create mode 100644 src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 089d430302f..e167a83db35 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -844,6 +844,7 @@ extend_qtc_plugin(QmlDesigner collectionsourcemodel.cpp collectionsourcemodel.h collectionview.cpp collectionview.h collectionwidget.cpp collectionwidget.h + datastoremodelnode.cpp datastoremodelnode.h ) extend_qtc_plugin(QmlDesigner diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h index 11ceb034fa5..e914891de34 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorconstants.h @@ -7,10 +7,14 @@ namespace QmlDesigner::CollectionEditor { enum class SourceFormat { Unknown, Json, Csv }; -inline constexpr char SOURCEFILE_PROPERTY[] = "source"; +inline constexpr char SOURCEFILE_PROPERTY[] = "source"; +inline constexpr char ALLMODELS_PROPERTY[] = "allModels"; +inline constexpr char JSONCHILDMODELNAME_PROPERTY[] = "modelName"; -inline constexpr char COLLECTIONMODEL_IMPORT[] = "QtQuick.Studio.Utils"; -inline constexpr char JSONCOLLECTIONMODEL_TYPENAME[] = "QtQuick.Studio.Utils.JsonListModel"; -inline constexpr char CSVCOLLECTIONMODEL_TYPENAME[] = "QtQuick.Studio.Utils.CsvTableModel"; +inline constexpr char COLLECTIONMODEL_IMPORT[] = "QtQuick.Studio.Utils"; +inline constexpr char JSONCOLLECTIONMODEL_TYPENAME[] = "QtQuick.Studio.Utils.JsonListModel"; +inline constexpr char CSVCOLLECTIONMODEL_TYPENAME[] = "QtQuick.Studio.Utils.CsvTableModel"; +inline constexpr char JSONCOLLECTIONCHILDMODEL_TYPENAME[] = "QtQuick.Studio.Utils.ChildListModel"; +inline constexpr char JSONBACKEND_TYPENAME[] = "JsonData"; } // namespace QmlDesigner::CollectionEditor diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp index d4e4e7654f5..9abe498b912 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp @@ -14,6 +14,10 @@ #include +#include +#include +#include + #include #include #include @@ -127,16 +131,21 @@ bool canAcceptCollectionAsModel(const ModelNode &node) && modelProperty.propertyType().isVariant(); } -QString getSourceCollectionPath(const ModelNode &node) +QString getSourceCollectionPath(const ModelNode &dataStoreNode) { - QUrl nodeSource = node.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY).value().toUrl(); - QString sourcePath = nodeSource.isLocalFile() ? nodeSource.toLocalFile() : nodeSource.toString(); - return QmlDesignerPlugin::instance() - ->currentDesignDocument() - ->fileName() - .parentDir() - .resolvePath(sourcePath) - .toFSPathString(); + using Utils::FilePath; + ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject(); + + if (!currentProject || !dataStoreNode.isValid()) + return {}; + + const FilePath expectedFile = currentProject->projectDirectory().pathAppended( + "/imports/" + currentProject->displayName() + "/DataStore.json"); + + if (expectedFile.exists()) + return expectedFile.toFSPathString(); + + return {}; } QJsonArray defaultCollectionArray() diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h index 65806ab3b63..a9022ed0996 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h @@ -18,7 +18,7 @@ SourceFormat getSourceCollectionFormat(const QmlDesigner::ModelNode &node); QString getSourceCollectionType(const QmlDesigner::ModelNode &node); -QString getSourceCollectionPath(const QmlDesigner::ModelNode &node); +QString getSourceCollectionPath(const QmlDesigner::ModelNode &dataStoreNode); void assignCollectionSourceToNode(AbstractView *view, const ModelNode &modelNode, diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp index 098bbdaaa70..4d7773ade33 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp @@ -83,8 +83,8 @@ QVariant CollectionSourceModel::data(const QModelIndex &index, int role) const const ModelNode *collectionSource = &m_collectionSources.at(index.row()); switch (role) { - case NameRole: - return collectionSource->variantProperty("objectName").value(); + case NameRole: // Not used, to be removed + return collectionSource->variantProperty("objectName").value().toString(); case NodeRole: return QVariant::fromValue(*collectionSource); case CollectionTypeRole: @@ -634,7 +634,8 @@ void CollectionSourceModel::updateCollectionList(QModelIndex index) QSharedPointer newList = loadCollection(sourceNode, currentList); if (currentList != newList) { m_collectionList.replace(index.row(), newList); - emit this->dataChanged(index, index, {CollectionsRole}); + emit dataChanged(index, index, {CollectionsRole}); + emit collectionNamesChanged(sourceNode, newList->stringList()); } } @@ -657,6 +658,9 @@ void CollectionSourceModel::registerCollection(const QSharedPointersourceNode()) + emit collectionNamesChanged(collection->sourceNode(), collection->stringList()); } QModelIndex CollectionSourceModel::indexOfNode(const ModelNode &node) const diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h index f0dd517ee10..36226138c30 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h @@ -71,6 +71,7 @@ public: signals: void selectedIndexChanged(int idx); void collectionSelected(const ModelNode &sourceNode, const QString &collectionName); + void collectionNamesChanged(const ModelNode &sourceNode, QStringList collections); void isEmptyChanged(bool); void warning(const QString &title, const QString &body); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp index de82734b353..8a470c49155 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp @@ -8,12 +8,17 @@ #include "collectioneditorutils.h" #include "collectionsourcemodel.h" #include "collectionwidget.h" +#include "datastoremodelnode.h" #include "designmodecontext.h" #include "nodeabstractproperty.h" #include "nodemetainfo.h" #include "qmldesignerplugin.h" #include "variantproperty.h" +#include +#include +#include + #include #include #include @@ -37,7 +42,15 @@ namespace QmlDesigner { CollectionView::CollectionView(ExternalDependenciesInterface &externalDependencies) : AbstractView(externalDependencies) -{} + , m_dataStore(std::make_unique()) + +{ + connect(ProjectExplorer::ProjectManager::instance(), + &ProjectExplorer::ProjectManager::startupProjectChanged, + this, + &CollectionView::resetDataStoreNode); + resetDataStoreNode(); +} bool CollectionView::hasWidget() const { @@ -59,6 +72,19 @@ QmlDesigner::WidgetInfo CollectionView::widgetInfo() [this](const ModelNode &sourceNode, const QString &collection) { m_widget->collectionDetailsModel()->loadCollection(sourceNode, collection); }); + + connect(sourceModel, &CollectionSourceModel::isEmptyChanged, this, [this](bool isEmpty) { + if (isEmpty) + m_widget->collectionDetailsModel()->loadCollection({}, {}); + }); + + connect(sourceModel, + &CollectionSourceModel::collectionNamesChanged, + this, + [this](const ModelNode &sourceNode, const QStringList &collectionNames) { + if (sourceNode == m_dataStore->modelNode()) + m_dataStore->setCollectionNames(collectionNames); + }); } return createWidgetInfo(m_widget.data(), @@ -72,7 +98,7 @@ QmlDesigner::WidgetInfo CollectionView::widgetInfo() void CollectionView::modelAttached(Model *model) { AbstractView::modelAttached(model); - refreshModel(); + resetDataStoreNode(); } void CollectionView::nodeReparented(const ModelNode &node, @@ -179,16 +205,23 @@ void CollectionView::registerDeclarativeType() CollectionJsonSourceFilterModel::registerDeclarativeType(); } +void CollectionView::resetDataStoreNode() +{ + m_dataStore->reloadModel(); + refreshModel(); +} + void CollectionView::refreshModel() { if (!model()) return; // Load Model Groups - const ModelNodes collectionSourceNodes = rootModelNode().subModelNodesOfType( - jsonCollectionMetaInfo()) - + rootModelNode().subModelNodesOfType( - csvCollectionMetaInfo()); + ModelNodes collectionSourceNodes; + + if (ModelNode dataStore = m_dataStore->modelNode()) + collectionSourceNodes << dataStore; + m_widget->sourceModel()->setSources(collectionSourceNodes); } diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h index 994105f9745..bb52f82ac0b 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h @@ -4,13 +4,13 @@ #pragma once #include "abstractview.h" +#include "datastoremodelnode.h" #include "modelnode.h" -#include - namespace QmlDesigner { class CollectionWidget; +class DataStoreModelNode; class CollectionView : public AbstractView { @@ -45,6 +45,8 @@ public: static void registerDeclarativeType(); + void resetDataStoreNode(); + private: void refreshModel(); NodeMetaInfo jsonCollectionMetaInfo() const; @@ -52,5 +54,6 @@ private: void ensureStudioModelImport(); QPointer m_widget; + std::unique_ptr m_dataStore; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp new file mode 100644 index 00000000000..4b2ab6edbe8 --- /dev/null +++ b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp @@ -0,0 +1,214 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "datastoremodelnode.h" + +#include "collectioneditorconstants.h" +#include "model/qmltextgenerator.h" + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include +#include + +namespace { + +Utils::FilePath findFile(const Utils::FilePath &path, const QString &fileName) +{ + QDirIterator it(path.toString(), QDirIterator::Subdirectories); + + while (it.hasNext()) { + QFileInfo file(it.next()); + if (file.isDir()) + continue; + + if (file.fileName() == fileName) + return Utils::FilePath::fromFileInfo(file); + } + return {}; +} + +QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node) +{ + using QmlDesigner::AbstractProperty; + using QmlDesigner::PropertyName; + using QmlDesigner::PropertyNameList; + static PropertyNameList defaultsNodeProps = {"id", + QmlDesigner::CollectionEditor::SOURCEFILE_PROPERTY, + QmlDesigner::CollectionEditor::JSONCHILDMODELNAME_PROPERTY, + "backend"}; + PropertyNameList dynamicPropertyNames = Utils::transform( + node.dynamicProperties(), + [](const AbstractProperty &property) -> PropertyName { return property.name(); }); + + Utils::sort(dynamicPropertyNames); + + return defaultsNodeProps + dynamicPropertyNames; +} + +} // namespace + +namespace QmlDesigner { + +DataStoreModelNode::DataStoreModelNode() +{ + reloadModel(); +} + +void DataStoreModelNode::reloadModel() +{ + using Utils::FilePath; + if (!ProjectExplorer::ProjectManager::startupProject()) { + reset(); + return; + } + bool forceUpdate = false; + + const FilePath projectFilePath = ProjectExplorer::ProjectManager::startupProject()->projectDirectory(); + const FilePath importsPath = FilePath::fromString(projectFilePath.path() + "/imports"); + FilePath dataStoreQmlPath = findFile(importsPath, "DataStore.qml"); + FilePath dataStoreJsonPath = findFile(importsPath, "DataStore.json"); + QUrl dataStoreQmlUrl = dataStoreQmlPath.toUrl(); + + if (dataStoreQmlPath.exists() && dataStoreJsonPath.exists()) { + if (!m_model.get() || m_model->fileUrl() != dataStoreQmlUrl) { + m_model = Model::create(CollectionEditor::JSONCOLLECTIONMODEL_TYPENAME, 1, 1); + forceUpdate = true; + Import import = Import::createLibraryImport(CollectionEditor::COLLECTIONMODEL_IMPORT); + try { + if (!m_model->hasImport(import, true, true)) + m_model->changeImports({import}, {}); + } catch (const Exception &) { + QTC_ASSERT(false, return); + } + } + } else { + reset(); + } + + QTC_ASSERT(m_model.get(), return); + m_model->setFileUrl(dataStoreQmlUrl); + + m_dataRelativePath = dataStoreJsonPath.relativePathFrom(dataStoreQmlPath).toFSPathString(); + + if (forceUpdate) { + updateDataStoreProperties(); + updateSingletonFile(); + } +} + +QStringList DataStoreModelNode::collectionNames() const +{ + return m_collectionNames; +} + +Model *DataStoreModelNode::model() const +{ + return m_model.get(); +} + +ModelNode DataStoreModelNode::modelNode() const +{ + QTC_ASSERT(m_model.get(), return {}); + return m_model->rootModelNode(); +} + +QString DataStoreModelNode::getModelQmlText() +{ + ModelNode node = modelNode(); + QTC_ASSERT(node, return {}); + + Internal::QmlTextGenerator textGen(createNameList(node), + QmlJSTools::QmlJSToolsSettings::globalCodeStyle()->tabSettings()); + + QString genText = textGen(node); + return genText; +} + +void DataStoreModelNode::reset() +{ + if (m_model) + m_model.reset(); + + m_dataRelativePath.clear(); + setCollectionNames({}); +} + +void DataStoreModelNode::updateDataStoreProperties() +{ + QTC_ASSERT(model(), return); + + ModelNode rootNode = modelNode(); + QTC_ASSERT(rootNode.isValid(), return); + + static TypeName childNodeTypename = "ChildListModel"; + + const QList formerPropertyNames = rootNode.dynamicProperties(); + for (const AbstractProperty &property : formerPropertyNames) + rootNode.removeProperty(property.name()); + + rootNode.setIdWithoutRefactoring("models"); + + for (const QString &collectionName : std::as_const(m_collectionNames)) { + PropertyName newName = collectionName.toLatin1(); + + ModelNode collectionNode = model()->createModelNode(childNodeTypename); + + VariantProperty modelNameProperty = collectionNode.variantProperty( + CollectionEditor::JSONCHILDMODELNAME_PROPERTY); + modelNameProperty.setValue(newName); + + NodeProperty nodeProp = rootNode.nodeProperty(newName); + nodeProp.setDynamicTypeNameAndsetModelNode(childNodeTypename, collectionNode); + } + + // Backend Property + ModelNode backendNode = model()->createModelNode(CollectionEditor::JSONBACKEND_TYPENAME); + NodeProperty backendProperty = rootNode.nodeProperty("backend"); + backendProperty.setDynamicTypeNameAndsetModelNode(CollectionEditor::JSONBACKEND_TYPENAME, + backendNode); + // Source Property + VariantProperty sourceProp = rootNode.variantProperty(CollectionEditor::SOURCEFILE_PROPERTY); + sourceProp.setValue(m_dataRelativePath); +} + +void DataStoreModelNode::updateSingletonFile() +{ + using Utils::FilePath; + using Utils::FileSaver; + QTC_ASSERT(m_model.get(), return); + + const QString pragmaSingleTone = "pragma Singleton\n"; + QString imports; + + for (const Import &import : m_model->imports()) + imports += QStringLiteral("import %1\n").arg(import.toString(true)); + + QString content = pragmaSingleTone + imports + getModelQmlText(); + QUrl modelUrl = m_model->fileUrl(); + FileSaver file(FilePath::fromUserInput(modelUrl.isLocalFile() ? modelUrl.toLocalFile() + : modelUrl.toString())); + file.write(content.toLatin1()); + file.finalize(); +} + +void DataStoreModelNode::setCollectionNames(const QStringList &newCollectionNames) +{ + if (m_collectionNames != newCollectionNames) { + m_collectionNames = newCollectionNames; + updateDataStoreProperties(); + updateSingletonFile(); + } +} + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h new file mode 100644 index 00000000000..e76d7f50e4a --- /dev/null +++ b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h @@ -0,0 +1,37 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +namespace QmlDesigner { + +class Model; + +class DataStoreModelNode +{ +public: + DataStoreModelNode(); + + void reloadModel(); + QStringList collectionNames() const; + + Model *model() const; + ModelNode modelNode() const; + + void setCollectionNames(const QStringList &newCollectionNames); + +private: + QString getModelQmlText(); + + void reset(); + void updateDataStoreProperties(); + void updateSingletonFile(); + + ModelPointer m_model; + QStringList m_collectionNames; + QString m_dataRelativePath; +}; + +} // namespace QmlDesigner From ec59bab4914abb0a817dc85de9cd6129b87f7a3e Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Mon, 27 Nov 2023 09:03:08 +0100 Subject: [PATCH 052/101] QmlDesigner: correct JavaScript name Task-number: QDS-10810 Change-Id: I74c97600fd6284743eb06afcbf4d93d0f6c67633 Reviewed-by: Tim Jenssen --- .../qmldesigner/studio_templates/files/javascript/wizard.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qmldesigner/studio_templates/files/javascript/wizard.json b/share/qtcreator/qmldesigner/studio_templates/files/javascript/wizard.json index fb11c65b344..7ba90f75f6f 100644 --- a/share/qtcreator/qmldesigner/studio_templates/files/javascript/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/files/javascript/wizard.json @@ -4,8 +4,8 @@ "id": "Z.QtStudio.JavaScript.2", "category": "R.StudioJSFiles", "trDescription": "Creates a JavaScript file.", - "trDisplayName": "Java Script File", - "trDisplayCategory": "Java Script", + "trDisplayName": "JavaScript File", + "trDisplayCategory": "JavaScript", "icon": "file_javascript.png", "platformIndependent": true, From 60d23bff03edd7d8e5522523e2fff1843caec800 Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Mon, 27 Nov 2023 13:24:08 +0100 Subject: [PATCH 053/101] CMake: make sure that deploy.py errors get caught Change-Id: I05f818145ed29f4521bddc36051ae504c13278d7 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Eike Ziller --- cmake/Utils.cmake | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmake/Utils.cmake b/cmake/Utils.cmake index b1be1ccf105..3dbe0f1e810 100644 --- a/cmake/Utils.cmake +++ b/cmake/Utils.cmake @@ -22,6 +22,9 @@ function(setup_dependencies_component) set(_elfutils_arg "--elfutils \"${_elfutils_path}\"") endif() install(CODE " + if (CMAKE_VERSION GREATER_EQUAL 3.19) + set(QTC_COMMAND_ERROR_IS_FATAL COMMAND_ERROR_IS_FATAL ANY) + endif() # DESTDIR is set for e.g. the cpack DEB generator, but is empty in other situations if(DEFINED ENV{DESTDIR}) set(DESTDIR_WITH_SEP \"\$ENV{DESTDIR}/\") @@ -48,7 +51,7 @@ function(setup_dependencies_component) \"\${_ide_app_target}\" \"${_qmake_binary}\" COMMAND_ECHO STDOUT - \${QTC_COMMAND_ERROR_IS_FATAL} + ${QTC_COMMAND_ERROR_IS_FATAL} ) " COMPONENT Dependencies From 0c3c17c53a28e43fe34e84d1b63c50f610942b7a Mon Sep 17 00:00:00 2001 From: Tim Jenssen Date: Mon, 27 Nov 2023 13:24:17 +0100 Subject: [PATCH 054/101] Build/deploy: fix missing argument Change-Id: Ia73cfac75d336d7e321aef4059bb0eb6e4e3ed31 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Tim Jenssen --- scripts/deploy.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/deploy.py b/scripts/deploy.py index 15ddd3ced04..20ade283d2a 100755 --- a/scripts/deploy.py +++ b/scripts/deploy.py @@ -469,8 +469,8 @@ def main(): qtcreator_binary_path = (args.qtcreator_binary if common.is_mac_platform() else os.path.dirname(args.qtcreator_binary)) - deploy_binary('qtdiag', qt_install) - deploy_binary('qsb', qt_install) + deploy_binary('qtdiag', qtcreator_binary_path, qt_install) + deploy_binary('qsb', qtcreator_binary_path, qt_install) deploy_plugins(qtcreator_binary_path, qt_install) deploy_imports(qtcreator_binary_path, qt_install) deploy_translations(qtcreator_binary_path, qt_install) From 7ca7ec4664557c24f8ea513c54e684bf6e4fd064 Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Wed, 15 Nov 2023 10:30:56 +0200 Subject: [PATCH 055/101] Doc: Update 3D view icons Task-number: QDS-11241 Change-Id: I644b77813751081112cf9a6023c2bae265aa6fab Reviewed-by: Johanna Vanhatapio --- .../images/icons/3d-background-color.png | Bin 348 -> 1949 bytes .../images/icons/snapping-3d-conf.png | Bin 1912 -> 1600 bytes .../images/icons/snapping-3d.png | Bin 1854 -> 1585 bytes 3 files changed, 0 insertions(+), 0 deletions(-) diff --git a/doc/qtdesignstudio/images/icons/3d-background-color.png b/doc/qtdesignstudio/images/icons/3d-background-color.png index 37c68e632cafcb07761ccc4bf8d533d7409c209b..5d4aaf93cd23a214fb908a1c734e8bf5ef5976ce 100644 GIT binary patch literal 1949 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7I14-?iy0WWg+Z8+Vb&Z8 z1_suXnIRD+5xzcF$@#f@i7EL>sd^Q;1q>iyV_#8_n4FzjqL7rDo|$K>^nUk#C56ls zTcvPQUjyF)=hTc$kE){7;3~h6MhI|Z8xtBTx$+|-gpg^Jvqyke^gTP3i$ zR(Zu%AYpwa1+bEmY+EHqkcA2nz5xo(`9-M;mU@P|$p!|73g(u2h9+i47M7Me3PuJ- z#`*?k`bMU@Mg~>}hE}Gg3Q(YAr(jc*l4cd;;s&*>C?(BSDWjyMz)D}gyu4hm+*mKa zC|%#s($Z4jz)0W7NVg~@O}Dr*uOzWTH?LS3W`avc7m0xRdD)WnkfqLBRj99T>Rz?`gLWU6PVpb?&#my%yztcj!{)g`ec)m8}< zYr2Mpx<&>eh9*`cSYoS`nVXoNs$YlP!%5b(2yol5|ZCOiXkWlPoNB&CSeB%~DJgEfbUBuJJF* zOwY_q%t1D_BDX*Zsk}dcOGLbxLrTg=q$r5J(8EyBiT&)e zrhkpMrLu(B1J5~S?$ABRVYU|>k#XHD7IZ}h5Aj=_4x0$yg1 zkNo_M6BJyzwSMpjF5b}_btQrKZ-Y|YLpiP$Ni5-kM+1%+uTgMiVz6))=8|9#nRw7B zj%AB7zeb{jcf?@{KS4$YgZ^(F!Zqv%q-zfIGx#Knn$BR7d7#3us=;%~j}}FSCxPuc zaZE~+I?}d06zG1zE;8|f`L054Zib4!tRr%A50x1hf?|%V{Y&8coN=J`3!BYR7QF<4 z)fMfUe~$9(TOinfv7PTrl5!HO^^aEV70yjU57@3TZl1x~z_6n^O6IYW7sH81>I@7H z409eE^#vS^?pY+f_67?B0|$eJv-q(>-pVzPneQ<(F#KW9V2oXTHF@VgTe~ HDWM4fl5KPL delta 322 zcmbQse}`#;ay_H6r;B5V#p$h=_v*0)inKmV*HYo)a@77Ov{YKaN|slsYLR2V@Rg89 zY$_QqG6cjOJna;t>RDT#EM9bT(n$%YhbqBm-fX^aoV~Vo)09bfRvnhx73eB<|Ni2z zg8^3@!Wh;hO7*VLXNddIQhKJ2UE*lix{W*TC7<^b+|Y1ZBPX$5!nF07`I{sj+b&U+H3=FMIO*g)4VPrPdGn`z?q?l=FsB2^pVrXV%WNu|@q-|hi zWniGBP?1|;<(r?9nO5nNSdwb11TsYzq|`9Pz{1MF+{(lZMQLhDVoG93B0j~F|1C&cm?v5o>ZT=G80wm&m>B3Lnwli)rkGo%nj|Hrnx&biO)g*-(W%HS&`Zfou_8*t zK4ul-OlD&V^B~4VC57S=*Rm3;@{H6xB+sLS)8yl<+PtQEh6)A4M9{zDD9k74<*OnuMHd+!(+7#KWV{an^LB{Ts5Hzf5; delta 949 zcmX@W^Mh}Kq#_do1H*)g8Dg<{RI&FfyCynNKcdQp_~4)HSdOF|f2UG_*1_&^9o( zGB8k5sK_m_^36}lOsjNBEJ?Lh0-2% zCK@N|8km|`>Lw+oSm>HrCZ`x1CZ-rAStd^2z^tN@VwRR< zZf>5co0e!~pqpZ5Vyc^zn3SSxmS|#bmX?;3XqaL=`3G~D2Qdnj6pBk+%Sx=uGg9-= zg8~+6lc%w0*PG~>D`jo@}xYfC!tg0H{myrD@8i!eTeur8Jkj)O z6=-gsa5HBus{@DhnKuz4k3K$_Q@>NPKB(s{Kf3{gVvd3Fai!~}pKaE^l6q4ucW8Ou zktl|%}J+@ccc>RI)c_+UlzoA=_tvmV2(& zrN)?+cI>8a`)ALFpYQWu)N3!C+i}lbT0_(NwVvm#ZAYb&xX;+#VlbN#uM+w6^s;_$ SR|akd1_n=8KbLh*2~7aU=0I!! diff --git a/doc/qtdesignstudio/images/icons/snapping-3d.png b/doc/qtdesignstudio/images/icons/snapping-3d.png index a434305e257346110d09e2164ec55eced830993b..b10aae11347b806745ea3b5a4a89afc4e44e0f91 100644 GIT binary patch delta 676 zcmdnTw~=Rpq#_#w1B3kM|A`C?44efXk;M!Q+`=Ht$S`Y;1Oo%hyNOmaWDHHrj4UiI zbrg&YjEwaS%=C>+b&U+H3=FMIO*g)4VPrPdGn`z?q?l=FsB2^pVrXV%WMO4ws%>Co zWniGBP?1|;<(r?9nO5nNSdwb11TsYzq|`9Pz{1MF+{(llMQLhDVoG93B0j~F|1x(I-Y_`Iz`*d* z)5S5w;`H208@U++We$9__F-#H5^@!ryeY`*X3jsxe@siKyc84Md@;=^iZ|$#M@n!? z;>Hf6hreIN##)`byWZ|=+w0$P-{-B$ob@SrmVmrUp}}v5tsE={F8smjjE_Y&9=MvB z(8P47!isap23Hn4+a&b`=lK#P>nkleH9on8xVSDjxTt^j*%REcf&$%^o6MM#9`|wl zh)j7Bzs=ZiP49n&b}O%XHm4gB%zXqWwz*ctt3d6~}yM?v#=d5zFylMPGoq>UY!IRz9 K&t;ucLK6VKoZ!d+ delta 882 zcmdnUvyX3rq#_do1H*)g8DOw3J< zbrg&YjEwaSjP;F-bqy@6OwFu}%{RVlVPrPZGoM__q?l=7scT>nVqj@yXlP|RKk7Sm;_N8l>nNr=+BsB`2CDnHv~PE?|~Xu{5?cG&DCh(@iw7Fw#vk zGBMP(FitepH8W2%OEEMuGBhx=oVu<)5Y zjYV6_M9*A7BRn%NCBM8_Q%T=W!KNrB%_=7osy{KgBr`wHR;f6#Y_b81oCh)9#%DJy zz(ID)quLF%F*zeKFFiHIR!M*IIhMG3o}(uc7#J8eJzX3_G|ngg=;xhdQn5?-vkcl6p|3@J(PTA}WcOO4-WXam4 zt@ppz=j7xxH8o{lUz=R<@zK$flhr#nKDm2)`@6h6pGS`#rKP3Kx2v@(_@GededFfM z`u~5qd)xQd|NHX&>)MEoO#N-&iG2LxLBWp? zi3;N0kA8pq`g+UD%h%UNt1D=nICzfF Date: Thu, 23 Nov 2023 17:11:06 +0200 Subject: [PATCH 056/101] Doc: Describe Viewport Shading Fixes: QDS-11110 Change-Id: I098745446f421a37a8f263577aa4c098a5d13cea Reviewed-by: Mats Honkamaa --- .../qtdesignstudio-3d-editor.qdoc | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc index 7848fb0d07e..4c45f87ad8b 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc @@ -368,6 +368,54 @@ \inlineimage icons/particles-seek.png to manually seek forward or backward in the particle animation. + \section1 Using Viewport Shading + + Use \uicontrol {Viewport Shading} to change the rendering of the materials to only + reflect a particular aspect of the overall rendering process. Use shading also as a + debugging tool to understand why a material looks the way it does. In split view, + view the scene using different shading properties in each split. + + To use the \uicontrol {Viewport Shading}, right-click the \uicontrol 3D view to open the + context menu, select \uicontrol {Viewport Shading} and then select \uicontrol Wireframe, + one of the material properties, or \uicontrol{Reset All Viewports}. + + Select \uicontrol Wireframe to only show the edges of the objects in the scene. + + Select one of the material properties available for shading: + \table + \header + \li Property + \li Description + \row + \li Base Color + \li Shows only the base color of a material passed through without any lighting. + \row + \li Roughness + \li Shows only the roughness of a material passed through as an unlit greyscale + value. + \row + \li Metalness + \li Shows only the metalness of a material passed through as an unlit greyscale + value. + \row + \li Normals + \li Shows only the interpolated world space normal value of the material mapped + to an RGB color. + \row + \li Ambient Occlusion + \li Shows only the ambient occlusion of the material. + \row + \li Diffuse + \li Shows only the diffuse contribution of the material after all lighting. + \row + \li Specular + \li Shows only the specular contribution of the material after all + lighting. + \endtable + + Select \uicontrol{Reset All Viewports} to reset the shading of the scene in all of the + splits. + \section1 Summary of the 3D View Toolbar Buttons The \uicontrol{3D} view toolbar contains the following buttons: From c5f023751f0001a120622c614b23188764553f71 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 28 Nov 2023 13:30:50 +0100 Subject: [PATCH 057/101] QmlDesigner: Use QDS 4.3 in project template Change-Id: Ib9a6198512115780b6586242294c1c82fccd22dd 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 2a42e7222c8..95975c197d1 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl @@ -114,7 +114,7 @@ Project { /* Required for deployment */ targetDirectory: "/opt/%{ProjectName}" - qdsVersion: "4.4" + qdsVersion: "4.3" quickVersion: "%{QtQuickVersion}" From fa376883f0ce503e0346b1bb680a60df0dab52de Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 28 Nov 2023 16:18:48 +0100 Subject: [PATCH 058/101] QmlJSCheck: Ensure that ::createObjectsForImport always works correctly If ::createObjectsForImport is called twice, then m_objectsByQualifiedName already contains the type and an empty list is returned. The returned list is used for the prototype lookup and in this case the import is empty and the prototype cannot be found. This happened for QtQuick3D.Effect when used from QtQuick3D.Effects in some cases. There is a race condition. The second call to ::::createObjectsForImport is quite rare. Task-number: QDS-11069 Change-Id: I6dfe152224172d0d626625d24a53f36d4219372f Reviewed-by: Miikka Heikkinen --- src/libs/qmljs/qmljsinterpreter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/libs/qmljs/qmljsinterpreter.cpp b/src/libs/qmljs/qmljsinterpreter.cpp index 63e009607b9..9448ef39b01 100644 --- a/src/libs/qmljs/qmljsinterpreter.cpp +++ b/src/libs/qmljs/qmljsinterpreter.cpp @@ -1485,8 +1485,10 @@ QList CppQmlTypes::createObjectsForImport(const QStri // if it already exists, skip const QString key = qualifiedName(package, fmo->className(), version); - if (m_objectsByQualifiedName.contains(key)) + if (m_objectsByQualifiedName.contains(key)) { + exportedObjects.insert(key, m_objectsByQualifiedName.value(key)); continue; + } ComponentVersion cppVersion; for (const FakeMetaObject::Export &bestExport : std::as_const(bestExports)) { From 37cca63593fac4aff95e3f08a738451a81b87e20 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Wed, 29 Nov 2023 13:34:35 +0200 Subject: [PATCH 059/101] QmlDesigner: Cleanup the templates for DataStore - Fix the bug which disables the live preview - The singleton of the DataStore is defined once - Also modifies the template file formats of the DataStore files Fixes: QDS-11430 Change-Id: I67e0f64355dccdc32c031bb4dc0fb8edf3fdf64a Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Patch Build Bot --- .../projects/application-3d/wizard.json | 8 +++---- .../projects/application/wizard.json | 8 +++---- .../projects/desktop-launcher/wizard.json | 8 +++---- .../projects/mobile-scroll/wizard.json | 8 +++---- .../projects/mobile-stack/wizard.json | 8 +++---- .../projects/mobile-swipe/wizard.json | 8 +++---- .../projects/shared-plugin/name/DataStore.qml | 15 ------------ .../shared-plugin/name/DataStore.qml.tpl | 11 ++++++--- .../name/{JsonData.qml => JsonData.qml.tpl} | 0 .../name/{data.json => data.json.tpl} | 0 .../name/importmodule.qmldir.tpl | 1 - .../projects/shared-plugin/name/models.json | 24 ------------------- .../{DataStore.json.tpl => models.json.tpl} | 0 .../projects/shared-plugin/name/qmldir | 1 - .../projects/qtquickapplication/wizard.json | 8 +++---- 15 files changed, 36 insertions(+), 72 deletions(-) delete mode 100644 share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml rename share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/{JsonData.qml => JsonData.qml.tpl} (100%) rename share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/{data.json => data.json.tpl} (100%) delete mode 100644 share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/models.json rename share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/{DataStore.json.tpl => models.json.tpl} (100%) 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 cf30f9c91c7..2a2e1bd53d0 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json @@ -384,19 +384,19 @@ "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/designer/plugin.metainfo" }, { - "source": "../shared-plugin/name/JsonData.qml", + "source": "../shared-plugin/name/JsonData.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" }, { - "source": "../shared-plugin/name/DataStore.qml", + "source": "../shared-plugin/name/DataStore.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" }, { - "source": "../shared-plugin/name/models.json", + "source": "../shared-plugin/name/models.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" }, { - "source": "../shared-plugin/name/data.json", + "source": "../shared-plugin/name/data.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json index 6fd0637fb1a..24434e00762 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json @@ -397,19 +397,19 @@ "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/designer/plugin.metainfo" }, { - "source": "../shared-plugin/name/JsonData.qml", + "source": "../shared-plugin/name/JsonData.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" }, { - "source": "../shared-plugin/name/DataStore.qml", + "source": "../shared-plugin/name/DataStore.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" }, { - "source": "../shared-plugin/name/models.json", + "source": "../shared-plugin/name/models.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" }, { - "source": "../shared-plugin/name/data.json", + "source": "../shared-plugin/name/data.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json index bb3e4851f9c..2f590855690 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json @@ -384,19 +384,19 @@ "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/designer/plugin.metainfo" }, { - "source": "../shared-plugin/name/JsonData.qml", + "source": "../shared-plugin/name/JsonData.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" }, { - "source": "../shared-plugin/name/DataStore.qml", + "source": "../shared-plugin/name/DataStore.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" }, { - "source": "../shared-plugin/name/models.json", + "source": "../shared-plugin/name/models.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" }, { - "source": "../shared-plugin/name/data.json", + "source": "../shared-plugin/name/data.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json index 104d349bccf..008e3eb9952 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json @@ -343,19 +343,19 @@ "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/designer/plugin.metainfo" }, { - "source": "../shared-plugin/name/JsonData.qml", + "source": "../shared-plugin/name/JsonData.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" }, { - "source": "../shared-plugin/name/DataStore.qml", + "source": "../shared-plugin/name/DataStore.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" }, { - "source": "../shared-plugin/name/models.json", + "source": "../shared-plugin/name/models.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" }, { - "source": "../shared-plugin/name/data.json", + "source": "../shared-plugin/name/data.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json index d8758ca2bf1..e385b58ff8f 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json @@ -345,19 +345,19 @@ "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/designer/plugin.metainfo" }, { - "source": "../shared-plugin/name/JsonData.qml", + "source": "../shared-plugin/name/JsonData.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" }, { - "source": "../shared-plugin/name/DataStore.qml", + "source": "../shared-plugin/name/DataStore.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" }, { - "source": "../shared-plugin/name/models.json", + "source": "../shared-plugin/name/models.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" }, { - "source": "../shared-plugin/name/data.json", + "source": "../shared-plugin/name/data.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json index 0661a77b7b6..47fe3bd4e3d 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json @@ -345,19 +345,19 @@ "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/designer/plugin.metainfo" }, { - "source": "../shared-plugin/name/JsonData.qml", + "source": "../shared-plugin/name/JsonData.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" }, { - "source": "../shared-plugin/name/DataStore.qml", + "source": "../shared-plugin/name/DataStore.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" }, { - "source": "../shared-plugin/name/models.json", + "source": "../shared-plugin/name/models.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" }, { - "source": "../shared-plugin/name/data.json", + "source": "../shared-plugin/name/data.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml deleted file mode 100644 index 32acc1d8178..00000000000 --- a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml +++ /dev/null @@ -1,15 +0,0 @@ -pragma Singleton -import QtQuick 6.5 -import QtQuick.Studio.Utils 1.0 - -JsonListModel { - id: models - source: Qt.resolvedUrl("models.json") - - property ChildListModel exampleModel: ChildListModel { - modelName: "exampleModel" - } - - property JsonData backend: JsonData {} -} - diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml.tpl index 0f9c24373c7..ca8b45ede08 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.qml.tpl @@ -2,11 +2,16 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only pragma Singleton -import QtQuick.Studio.Utils +import QtQuick 6.5 +import QtQuick.Studio.Utils 1.0 JsonListModel { - property alias allModels: models id: models + source: Qt.resolvedUrl("models.json") - source: Qt.resolvedUrl("DataStore.json") + property ChildListModel book: ChildListModel { + modelName: "book" + } + + property JsonData backend: JsonData {} } diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/JsonData.qml b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/JsonData.qml.tpl similarity index 100% rename from share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/JsonData.qml rename to share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/JsonData.qml.tpl diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/data.json b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/data.json.tpl similarity index 100% rename from share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/data.json rename to share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/data.json.tpl diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/importmodule.qmldir.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/importmodule.qmldir.tpl index 8f451c8494d..a0ec2f17cfc 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/importmodule.qmldir.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/importmodule.qmldir.tpl @@ -4,4 +4,3 @@ singleton Constants 1.0 Constants.qml EventListSimulator 1.0 EventListSimulator.qml EventListModel 1.0 EventListModel.qml DirectoryFontLoader 1.0 DirectoryFontLoader.qml -singleton DataStore 1.0 DataStore.qml diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/models.json b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/models.json deleted file mode 100644 index 17eb0e92b3f..00000000000 --- a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/models.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "exampleModel": [ - { - "name": "Christen Anderson", - "number": "+3455641" - }, - { - "name": "Armanda Cox", - "number": "+21155641" - }, - { - "name": "Ken Garza", - "number": "+3288642" - }, - { - "name": "Rodney Hamilton", - "number": "+3558848" - }, - { - "name": "Andrew Battles", - "number": "+42488649" - } - ] -} diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.json.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/models.json.tpl similarity index 100% rename from share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/DataStore.json.tpl rename to share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/models.json.tpl diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/qmldir b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/qmldir index d99371ee1da..b5924a433cc 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/qmldir +++ b/share/qtcreator/qmldesigner/studio_templates/projects/shared-plugin/name/qmldir @@ -3,4 +3,3 @@ singleton DataStore 1.0 DataStore.qml EventListModel 1.0 EventListModel.qml EventListSimulator 1.0 EventListSimulator.qml DirectoryFontLoader 1.0 DirectoryFontLoader.qml -singleton DataStore 1.0 DataStore.qml diff --git a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json index b1c8c5fb74f..ec2164d4f26 100644 --- a/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json +++ b/share/qtcreator/templates/wizards/projects/qtquickapplication/wizard.json @@ -263,19 +263,19 @@ "condition": "%{QdsProjectStyle}" }, { - "source": "../shared-plugin/name/JsonData.qml", + "source": "../shared-plugin/name/JsonData.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/JsonData.qml" }, { - "source": "../shared-plugin/name/DataStore.qml", + "source": "../shared-plugin/name/DataStore.qml.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/DataStore.qml" }, { - "source": "../shared-plugin/name/models.json", + "source": "../shared-plugin/name/models.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/models.json" }, { - "source": "../shared-plugin/name/data.json", + "source": "../shared-plugin/name/data.json.tpl", "target": "%{ProjectDirectory}/imports/%{ImportModuleName}/data.json" } ] From 206ad75359ea319cde531aebcee9d317c26cead8 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Fri, 24 Nov 2023 16:17:47 +0200 Subject: [PATCH 060/101] QmlDesigner: Assign a single collection model to the selected node Task-number: QDS-11217 Change-Id: I35eb536540faa2299a51d152a29f07c2c36abe41 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Miikka Heikkinen Reviewed-by: Mahmoud Badri --- .../CollectionItem.qml | 7 ++++ .../CollectionView.qml | 1 - .../ModelSourceItem.qml | 8 +--- .../collectioneditorutils.cpp | 41 +++++++++++++++---- .../collectioneditor/collectioneditorutils.h | 9 ++-- .../collectioneditor/collectionwidget.cpp | 13 +++--- .../collectioneditor/collectionwidget.h | 2 +- 7 files changed, 54 insertions(+), 27 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionItem.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionItem.qml index 23d0c7af93b..2d26fe8de2d 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionItem.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionItem.qml @@ -16,6 +16,7 @@ Item { property color textColor property string sourceType + property bool hasSelectedTarget signal selectItem(int itemIndex) signal deleteItem() @@ -125,6 +126,12 @@ Item { shortcut: StandardKey.Replace onTriggered: renameDialog.open() } + + StudioControls.MenuItem { + text: qsTr("Assign to the selected node") + enabled: root.hasSelectedTarget + onTriggered: rootView.assignCollectionToSelectedNode(collectionName) + } } component Spacer: Item { diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml index 363d8bab309..33c371f807a 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml @@ -111,7 +111,6 @@ Item { implicitWidth: sourceListView.width onDeleteItem: root.model.removeRow(index) hasSelectedTarget: root.rootView.targetNodeSelected - onAssignToSelected: root.rootView.assignSourceNodeToSelectedItem(sourceNode) onAddCollection: (collectionName) => { root.rootView.addCollection(collectionName, sourceCollectionType, diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml index 00f4b804e41..c453d702bbf 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml @@ -24,7 +24,6 @@ Item { signal selectItem(int itemIndex) signal deleteItem() - signal assignToSelected() signal addCollection(string collectionName) function toggleExpanded() { @@ -161,6 +160,7 @@ Item { delegate: CollectionItem { width: collectionListView.width sourceType: collectionListView.model.sourceType + hasSelectedTarget: root.hasSelectedTarget onDeleteItem: collectionListView.model.removeRow(index) } } @@ -188,12 +188,6 @@ Item { shortcut: StandardKey.Replace onTriggered: renameDialog.open() } - - StudioControls.MenuItem { - text: qsTr("Assign to the selected node") - enabled: root.hasSelectedTarget - onTriggered: root.assignToSelected() - } } component Spacer: Item { diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp index 9abe498b912..6e0328e0087 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp @@ -7,7 +7,6 @@ #include "bindingproperty.h" #include "nodemetainfo.h" #include "propertymetainfo.h" -#include "qmldesignerplugin.h" #include "variantproperty.h" #include @@ -100,20 +99,30 @@ QString getSourceCollectionType(const ModelNode &node) return {}; } -void assignCollectionSourceToNode(AbstractView *view, - const ModelNode &modelNode, - const ModelNode &collectionSourceNode) +void assignCollectionToNode(AbstractView *view, + const ModelNode &modelNode, + const ModelNode &collectionSourceNode, + const QString &collectionName) { QTC_ASSERT(modelNode.isValid() && collectionSourceNode.isValid(), return); - if (collectionSourceNode.id().isEmpty() || !canAcceptCollectionAsModel(modelNode)) + QString sourceId = isDataStoreNode(collectionSourceNode) ? "DataStore" + : collectionSourceNode.id(); + + if (sourceId.isEmpty() || !canAcceptCollectionAsModel(modelNode)) + return; + + VariantProperty sourceProperty = collectionSourceNode.variantProperty(collectionName.toLatin1()); + if (!sourceProperty.exists()) return; BindingProperty modelProperty = modelNode.bindingProperty("model"); - view->executeInTransaction("CollectionEditor::assignCollectionSourceToNode", - [&modelProperty, &collectionSourceNode]() { - modelProperty.setExpression(collectionSourceNode.id()); + QString identifier = QString("%1.%2").arg(sourceId, QString::fromLatin1(sourceProperty.name())); + + view->executeInTransaction("CollectionEditor::assignCollectionToNode", + [&modelProperty, &identifier]() { + modelProperty.setExpression(identifier); }); } @@ -148,6 +157,22 @@ QString getSourceCollectionPath(const ModelNode &dataStoreNode) return {}; } +bool isDataStoreNode(const ModelNode &dataStoreNode) +{ + using Utils::FilePath; + ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject(); + + if (!currentProject || !dataStoreNode.isValid()) + return false; + + const FilePath expectedFile = currentProject->projectDirectory().pathAppended( + "/imports/" + currentProject->displayName() + "/DataStore.qml"); + + FilePath modelPath = FilePath::fromUserInput(dataStoreNode.model()->fileUrl().toLocalFile()); + + return modelPath.isSameFile(expectedFile); +} + QJsonArray defaultCollectionArray() { QJsonObject initialObject; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h index a9022ed0996..8d226e7a34c 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h @@ -20,9 +20,12 @@ QString getSourceCollectionType(const QmlDesigner::ModelNode &node); QString getSourceCollectionPath(const QmlDesigner::ModelNode &dataStoreNode); -void assignCollectionSourceToNode(AbstractView *view, - const ModelNode &modelNode, - const ModelNode &collectionSourceNode = {}); +void assignCollectionToNode(AbstractView *view, + const ModelNode &modelNode, + const ModelNode &collectionSourceNode, + const QString &collectionName); + +bool isDataStoreNode(const ModelNode &dataStoreNode); bool canAcceptCollectionAsModel(const ModelNode &node); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp index 7e5d4268302..94edd5da4c7 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp @@ -334,20 +334,19 @@ bool CollectionWidget::addCollectionToDataStore(const QString &collectionName) return added; } -void CollectionWidget::assignSourceNodeToSelectedItem(const QVariant &sourceNode) +void CollectionWidget::assignCollectionToSelectedNode(const QString collectionName) { - ModelNode sourceModel = sourceNode.value(); + ModelNode dsNode = dataStoreNode(); ModelNode targetNode = m_view->singleSelectedModelNode(); - QTC_ASSERT(sourceModel.isValid() && targetNode.isValid(), return); + QTC_ASSERT(dsNode.isValid() && targetNode.isValid(), return); - if (sourceModel.id().isEmpty()) { - warn(tr("Assigning the model group"), - tr("The model group must have a valid id to be assigned.")); + if (dsNode.id().isEmpty()) { + warn(tr("Assigning the model"), tr("The model must have a valid id to be assigned.")); return; } - CollectionEditor::assignCollectionSourceToNode(m_view, targetNode, sourceModel); + CollectionEditor::assignCollectionToNode(m_view, targetNode, dsNode, collectionName); } ModelNode CollectionWidget::dataStoreNode() const diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h index 03cf49aa7e3..6700bf91a4d 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h @@ -52,7 +52,7 @@ public: Q_INVOKABLE bool addCollectionToDataStore(const QString &collectionName); - Q_INVOKABLE void assignSourceNodeToSelectedItem(const QVariant &sourceNode); + Q_INVOKABLE void assignCollectionToSelectedNode(const QString collectionName); Q_INVOKABLE ModelNode dataStoreNode() const; From 1423740e09efdacb997f0236020062eea6372e1e Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Wed, 29 Nov 2023 14:26:15 +0200 Subject: [PATCH 061/101] QmlDesigner: Add save icon to the icon font Change-Id: Ic88f61f19142a42cc456cb85f836ea9ed5635c07 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Ali Kianian Reviewed-by: Miikka Heikkinen --- .../imports/StudioTheme/InternalConstants.qml | 185 +++++++++--------- .../imports/StudioTheme/icons.ttf | Bin 65816 -> 66032 bytes .../components/componentcore/theme.h | 1 + 3 files changed, 94 insertions(+), 92 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml index 92a9206f5bd..a727c0d4215 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml @@ -283,98 +283,99 @@ QtObject { readonly property string s_timeline: "\u012E" readonly property string s_visibility: "\u012F" readonly property string saveLogs_medium: "\u0130" - readonly property string scale_medium: "\u0131" - readonly property string search: "\u0132" - readonly property string search_small: "\u0133" - readonly property string sectionToggle: "\u0134" - readonly property string selectFill_medium: "\u0135" - readonly property string selectOutline_medium: "\u0136" - readonly property string selectParent_small: "\u0137" - readonly property string selection_small: "\u0138" - readonly property string settings_medium: "\u0139" - readonly property string signal_small: "\u013A" - readonly property string snapping_conf_medium: "\u013B" - readonly property string snapping_medium: "\u013C" - readonly property string snapping_small: "\u013D" - readonly property string sortascending_medium: "\u013E" - readonly property string sortdescending_medium: "\u013F" - readonly property string sphere_medium: "\u0140" - readonly property string sphere_small: "\u0141" - readonly property string splitColumns: "\u0142" - readonly property string splitRows: "\u0143" - readonly property string splitScreen_medium: "\u0144" - readonly property string spotLight_small: "\u0145" - readonly property string stackedContainer_small: "\u0146" - readonly property string startNode: "\u0147" - readonly property string step_medium: "\u0148" - readonly property string stop_medium: "\u0149" - readonly property string tableView_medium: "\u014A" - readonly property string testIcon: "\u014B" - readonly property string textAlignBottom: "\u014C" - readonly property string textAlignCenter: "\u014D" - readonly property string textAlignJustified: "\u014E" - readonly property string textAlignLeft: "\u014F" - readonly property string textAlignMiddle: "\u0150" - readonly property string textAlignRight: "\u0151" - readonly property string textAlignTop: "\u0152" - readonly property string textBulletList: "\u0153" - readonly property string textFullJustification: "\u0154" - readonly property string textNumberedList: "\u0155" - readonly property string textures_medium: "\u0156" - readonly property string tickIcon: "\u0157" - readonly property string tickMark_small: "\u0158" - readonly property string timeline_small: "\u0159" - readonly property string toEndFrame_medium: "\u015A" - readonly property string toNextFrame_medium: "\u015B" - readonly property string toPrevFrame_medium: "\u015C" - readonly property string toStartFrame_medium: "\u015D" - readonly property string topToolbar_annotations: "\u015E" - readonly property string topToolbar_closeFile: "\u015F" - readonly property string topToolbar_designMode: "\u0160" - readonly property string topToolbar_enterComponent: "\u0161" - readonly property string topToolbar_home: "\u0162" - readonly property string topToolbar_makeComponent: "\u0163" - readonly property string topToolbar_navFile: "\u0164" - readonly property string topToolbar_runProject: "\u0165" - readonly property string translationCreateFiles: "\u0166" - readonly property string translationCreateReport: "\u0167" - readonly property string translationExport: "\u0168" - readonly property string translationImport: "\u0169" - readonly property string translationSelectLanguages: "\u016A" - readonly property string translationTest: "\u016B" - readonly property string transparent: "\u016C" - readonly property string triState: "\u016D" - readonly property string triangleArcA: "\u016E" - readonly property string triangleArcB: "\u016F" - readonly property string triangleCornerA: "\u0170" - readonly property string triangleCornerB: "\u0171" - readonly property string unLinked: "\u0172" - readonly property string undo: "\u0173" - readonly property string unify_medium: "\u0174" - readonly property string unpin: "\u0175" - readonly property string upDownIcon: "\u0176" - readonly property string upDownSquare2: "\u0177" - readonly property string updateAvailable_medium: "\u0178" - readonly property string updateContent_medium: "\u0179" - readonly property string visibilityOff: "\u017A" - readonly property string visibilityOn: "\u017B" - readonly property string visible_medium: "\u017C" - readonly property string visible_small: "\u017D" - readonly property string warning_medium: "\u017E" - readonly property string wildcard: "\u017F" - readonly property string wizardsAutomotive: "\u0180" - readonly property string wizardsDesktop: "\u0181" - readonly property string wizardsGeneric: "\u0182" - readonly property string wizardsMcuEmpty: "\u0183" - readonly property string wizardsMcuGraph: "\u0184" - readonly property string wizardsMobile: "\u0185" - readonly property string wizardsUnknown: "\u0186" - readonly property string zoomAll: "\u0187" - readonly property string zoomIn: "\u0188" - readonly property string zoomIn_medium: "\u0189" - readonly property string zoomOut: "\u018A" - readonly property string zoomOut_medium: "\u018B" - readonly property string zoomSelection: "\u018C" + readonly property string save_medium: "\u0131" + readonly property string scale_medium: "\u0132" + readonly property string search: "\u0133" + readonly property string search_small: "\u0134" + readonly property string sectionToggle: "\u0135" + readonly property string selectFill_medium: "\u0136" + readonly property string selectOutline_medium: "\u0137" + readonly property string selectParent_small: "\u0138" + readonly property string selection_small: "\u0139" + readonly property string settings_medium: "\u013A" + readonly property string signal_small: "\u013B" + readonly property string snapping_conf_medium: "\u013C" + readonly property string snapping_medium: "\u013D" + readonly property string snapping_small: "\u013E" + readonly property string sortascending_medium: "\u013F" + readonly property string sortdescending_medium: "\u0140" + readonly property string sphere_medium: "\u0141" + readonly property string sphere_small: "\u0142" + readonly property string splitColumns: "\u0143" + readonly property string splitRows: "\u0144" + readonly property string splitScreen_medium: "\u0145" + readonly property string spotLight_small: "\u0146" + readonly property string stackedContainer_small: "\u0147" + readonly property string startNode: "\u0148" + readonly property string step_medium: "\u0149" + readonly property string stop_medium: "\u014A" + readonly property string tableView_medium: "\u014B" + readonly property string testIcon: "\u014C" + readonly property string textAlignBottom: "\u014D" + readonly property string textAlignCenter: "\u014E" + readonly property string textAlignJustified: "\u014F" + readonly property string textAlignLeft: "\u0150" + readonly property string textAlignMiddle: "\u0151" + readonly property string textAlignRight: "\u0152" + readonly property string textAlignTop: "\u0153" + readonly property string textBulletList: "\u0154" + readonly property string textFullJustification: "\u0155" + readonly property string textNumberedList: "\u0156" + readonly property string textures_medium: "\u0157" + readonly property string tickIcon: "\u0158" + readonly property string tickMark_small: "\u0159" + readonly property string timeline_small: "\u015A" + readonly property string toEndFrame_medium: "\u015B" + readonly property string toNextFrame_medium: "\u015C" + readonly property string toPrevFrame_medium: "\u015D" + readonly property string toStartFrame_medium: "\u015E" + readonly property string topToolbar_annotations: "\u015F" + readonly property string topToolbar_closeFile: "\u0160" + readonly property string topToolbar_designMode: "\u0161" + readonly property string topToolbar_enterComponent: "\u0162" + readonly property string topToolbar_home: "\u0163" + readonly property string topToolbar_makeComponent: "\u0164" + readonly property string topToolbar_navFile: "\u0165" + readonly property string topToolbar_runProject: "\u0166" + readonly property string translationCreateFiles: "\u0167" + readonly property string translationCreateReport: "\u0168" + readonly property string translationExport: "\u0169" + readonly property string translationImport: "\u016A" + readonly property string translationSelectLanguages: "\u016B" + readonly property string translationTest: "\u016C" + readonly property string transparent: "\u016D" + readonly property string triState: "\u016E" + readonly property string triangleArcA: "\u016F" + readonly property string triangleArcB: "\u0170" + readonly property string triangleCornerA: "\u0171" + readonly property string triangleCornerB: "\u0172" + readonly property string unLinked: "\u0173" + readonly property string undo: "\u0174" + readonly property string unify_medium: "\u0175" + readonly property string unpin: "\u0176" + readonly property string upDownIcon: "\u0177" + readonly property string upDownSquare2: "\u0178" + readonly property string updateAvailable_medium: "\u0179" + readonly property string updateContent_medium: "\u017A" + readonly property string visibilityOff: "\u017B" + readonly property string visibilityOn: "\u017C" + readonly property string visible_medium: "\u017D" + readonly property string visible_small: "\u017E" + readonly property string warning_medium: "\u017F" + readonly property string wildcard: "\u0180" + readonly property string wizardsAutomotive: "\u0181" + readonly property string wizardsDesktop: "\u0182" + readonly property string wizardsGeneric: "\u0183" + readonly property string wizardsMcuEmpty: "\u0184" + readonly property string wizardsMcuGraph: "\u0185" + readonly property string wizardsMobile: "\u0186" + readonly property string wizardsUnknown: "\u0187" + readonly property string zoomAll: "\u0188" + readonly property string zoomIn: "\u0189" + readonly property string zoomIn_medium: "\u018A" + readonly property string zoomOut: "\u018B" + readonly property string zoomOut_medium: "\u018C" + readonly property string zoomSelection: "\u018D" readonly property font iconFont: Qt.font({ "family": controlIcons.name, diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf index e5a2ca18235a69b6c7b3a4b55aa0a0b8bb1f82c9..42e3a73fedb69329f00cbfeb2558ea3cd7226ad1 100644 GIT binary patch delta 743 zcmbQy#PXq;#e{*8fq{XSp@D&!A;8To#CM_m?Y9h!j8_;K7-al|^^GDIq**dBFh(#i zFeD`BCKhOg>xfS@QL1M=!@$76k)BhT#=EI-4g&+{4F-nmH5sXiDVmGF>}OzLxWmA} zV3v`Qn#lF@e=7q6qX+{7gGxqjNrkM3hzA1$;|>M}rYAZ1$%$7k&og0QVEe(qz;rJ+ zv7&(S9K&}821W}81_p(^#N5<_>N`~#7#@Z&Ffd&%$S*F@*zf7Xpv~|^gMmSI3E26J z3=EtHvyyRK$iM_{zm?3{`36T_+JR%3kVC?6xbJJ67(e4BDgR3Pe@M4u~3dsv(S{#bzw$f zi^4X9GlZLj&kNrZArui8u_EG2q*vs$$Tv|QQB$G~qGv_#i+&NK6B8FRA?8TTw^)nV zytufyGx0j{b@40W?Qlwy+f z87a3?V^UA0aip20m8G3XUzVYe5tMN%(;{mkYxGPI!X!Fl_Exw#S;$aiCz<6BHjOgWolo;3@z@)swTrEb3RQ;}Vf@&A7YCI$v@GGMsJ Jrj>^t`2d)#?cD$X delta 506 zcmey+%rc{i#e{*8fq{XSp@D&!A;8To#CIWA#!?1GhCd7p3^M+~`bLop(kvJl7$X=M z7!s0m6AQG$b;Kr`DAhB3VPIh3NYANEYl=Akn1O-w3IoHn9T};KDVlwa^cSpwjT@(Om}h< zD+(CTGJI!XV61F~yAx+6<2q7#L(Hft}CD zz#w_WKRlk_<|_j?^9u$B28M@C^3pJR5~D3+?qoa0SjL{sa~M6DCO>E1F?lYF9%Iku zGc18D^%wkE{B8Wb{PXi%E)^5_2t Date: Mon, 27 Nov 2023 23:50:53 +0200 Subject: [PATCH 062/101] QmlDesigner: Add DataStore Dynamically to the project Task-number: QDS-11400 Change-Id: I0ad20a6aad604aa66d4d0f24ca32a19fb9e94a08 Reviewed-by: Mahmoud Badri --- .../collectioneditorutils.cpp | 144 ++++++++++++++++-- .../collectioneditor/collectioneditorutils.h | 10 ++ .../collectioneditor/collectionview.cpp | 5 + .../collectioneditor/collectionview.h | 1 + .../collectioneditor/collectionwidget.cpp | 16 +- .../collectioneditor/collectionwidget.h | 2 + .../collectioneditor/datastoremodelnode.cpp | 22 +-- 7 files changed, 166 insertions(+), 34 deletions(-) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp index 6e0328e0087..4eeca52964d 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp @@ -11,6 +11,7 @@ #include +#include #include #include @@ -66,6 +67,43 @@ struct LessThanVisitor } }; +Utils::FilePath findFile(const Utils::FilePath &path, const QString &fileName) +{ + QDirIterator it(path.toString(), QDirIterator::Subdirectories); + + while (it.hasNext()) { + QFileInfo file(it.next()); + if (file.isDir()) + continue; + + if (file.fileName() == fileName) + return Utils::FilePath::fromFileInfo(file); + } + return {}; +} + +Utils::FilePath dataStoreDir() +{ + using Utils::FilePath; + ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject(); + + if (!currentProject) + return {}; + + return currentProject->projectDirectory().pathAppended("/imports/" + + currentProject->displayName()); +} + +inline Utils::FilePath collectionPath(const QString &filePath) +{ + return dataStoreDir().pathAppended("/" + filePath); +} + +inline Utils::FilePath qmlDirFilePath() +{ + return collectionPath("qmldir"); +} + } // namespace namespace QmlDesigner::CollectionEditor { @@ -126,6 +164,16 @@ void assignCollectionToNode(AbstractView *view, }); } +Utils::FilePath dataStoreJsonFilePath() +{ + return collectionPath("models.json"); +} + +Utils::FilePath dataStoreQmlFilePath() +{ + return collectionPath("DataStore.qml"); +} + bool canAcceptCollectionAsModel(const ModelNode &node) { const NodeMetaInfo nodeMetaInfo = node.metaInfo(); @@ -143,13 +191,10 @@ bool canAcceptCollectionAsModel(const ModelNode &node) QString getSourceCollectionPath(const ModelNode &dataStoreNode) { using Utils::FilePath; - ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject(); - - if (!currentProject || !dataStoreNode.isValid()) + if (!dataStoreNode.isValid()) return {}; - const FilePath expectedFile = currentProject->projectDirectory().pathAppended( - "/imports/" + currentProject->displayName() + "/DataStore.json"); + const FilePath expectedFile = dataStoreJsonFilePath(); if (expectedFile.exists()) return expectedFile.toFSPathString(); @@ -160,13 +205,14 @@ QString getSourceCollectionPath(const ModelNode &dataStoreNode) bool isDataStoreNode(const ModelNode &dataStoreNode) { using Utils::FilePath; - ProjectExplorer::Project *currentProject = ProjectExplorer::ProjectManager::startupProject(); - if (!currentProject || !dataStoreNode.isValid()) + if (!dataStoreNode.isValid()) return false; - const FilePath expectedFile = currentProject->projectDirectory().pathAppended( - "/imports/" + currentProject->displayName() + "/DataStore.qml"); + const FilePath expectedFile = dataStoreQmlFilePath(); + + if (!expectedFile.exists()) + return false; FilePath modelPath = FilePath::fromUserInput(dataStoreNode.model()->fileUrl().toLocalFile()); @@ -183,4 +229,84 @@ QJsonArray defaultCollectionArray() return initialCollection; } +bool ensureDataStoreExists(bool &justCreated) +{ + using Utils::FilePath; + using Utils::FileReader; + using Utils::FileSaver; + + FilePath qmlDestinationPath = dataStoreQmlFilePath(); + justCreated = false; + + auto extractDependency = [&justCreated](const FilePath &filePath) -> bool { + if (filePath.exists()) + return true; + + const QString templateFileName = filePath.fileName() + u".tpl"; + const FilePath templatePath = findFile(Core::ICore::resourcePath(), templateFileName); + if (!templatePath.exists()) { + qWarning() << Q_FUNC_INFO << __LINE__ << templateFileName << "does not exist"; + return false; + } + + templatePath.copyFile(filePath); + if (filePath.exists()) { + justCreated = true; + return true; + } + + qWarning() << Q_FUNC_INFO << __LINE__ << "Cannot copy" << templateFileName << "to" << filePath; + return false; + }; + + if (!extractDependency(dataStoreJsonFilePath())) + return false; + + if (!extractDependency(collectionPath("data.json"))) + return false; + + if (!extractDependency(collectionPath("JsonData.qml"))) + return false; + + if (!qmlDestinationPath.exists()) { + if (qmlDestinationPath.ensureExistingFile()) { + justCreated = true; + } else { + qWarning() << Q_FUNC_INFO << __LINE__ << "Can't create DataStore Qml File"; + return false; + } + } + + FilePath qmlDirPath = qmlDirFilePath(); + qmlDirPath.ensureExistingFile(); + + FileReader qmlDirReader; + if (!qmlDirReader.fetch(qmlDirPath)) { + qWarning() << Q_FUNC_INFO << __LINE__ << "Can't read the content of the qmldir"; + return false; + } + + QByteArray qmlDirContent = qmlDirReader.data(); + const QList qmlDirLines = qmlDirContent.split('\n'); + for (const QByteArray &line : qmlDirLines) { + if (line.startsWith("singleton DataStore ")) + return true; + } + + if (!qmlDirContent.isEmpty() && qmlDirContent.back() != '\n') + qmlDirContent.append("\n"); + qmlDirContent.append("singleton DataStore 1.0 DataStore.qml\n"); + + FileSaver qmlDirSaver(qmlDirPath); + qmlDirSaver.write(qmlDirContent); + + if (qmlDirSaver.finalize()) { + justCreated = true; + return true; + } + + qWarning() << Q_FUNC_INFO << __LINE__ << "Can't write to the qmldir file"; + return false; +} + } // namespace QmlDesigner::CollectionEditor diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h index 8d226e7a34c..835960f671e 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h @@ -10,6 +10,10 @@ QT_BEGIN_NAMESPACE class QJsonArray; QT_END_NAMESPACE +namespace Utils { +class FilePath; +} + namespace QmlDesigner::CollectionEditor { bool variantIslessThan(const QVariant &a, const QVariant &b, CollectionDetails::DataType type); @@ -25,8 +29,14 @@ void assignCollectionToNode(AbstractView *view, const ModelNode &collectionSourceNode, const QString &collectionName); +Utils::FilePath dataStoreJsonFilePath(); + +Utils::FilePath dataStoreQmlFilePath(); + bool isDataStoreNode(const ModelNode &dataStoreNode); +bool ensureDataStoreExists(bool &justCreated); + bool canAcceptCollectionAsModel(const ModelNode &node); QJsonArray defaultCollectionArray(); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp index 8a470c49155..f6a24280d18 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp @@ -211,6 +211,11 @@ void CollectionView::resetDataStoreNode() refreshModel(); } +ModelNode CollectionView::dataStoreNode() const +{ + return m_dataStore->modelNode(); +} + void CollectionView::refreshModel() { if (!model()) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h index bb52f82ac0b..dd946776ed1 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h @@ -46,6 +46,7 @@ public: static void registerDeclarativeType(); void resetDataStoreNode(); + ModelNode dataStoreNode() const; private: void refreshModel(); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp index 94edd5da4c7..30ae4418ed6 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp @@ -316,6 +316,7 @@ bool CollectionWidget::importCollectionToDataStore(const QString &collectionName bool CollectionWidget::addCollectionToDataStore(const QString &collectionName) { + ensureDataStoreExists(); const ModelNode node = dataStoreNode(); if (!node.isValid()) { warn(tr("Can not import to the main model"), tr("The default model node is not available.")); @@ -349,14 +350,17 @@ void CollectionWidget::assignCollectionToSelectedNode(const QString collectionNa CollectionEditor::assignCollectionToNode(m_view, targetNode, dsNode, collectionName); } +void CollectionWidget::ensureDataStoreExists() +{ + bool filesJustCreated = false; + bool filesExist = CollectionEditor::ensureDataStoreExists(filesJustCreated); + if (filesExist && filesJustCreated) + m_view->resetDataStoreNode(); +} + ModelNode CollectionWidget::dataStoreNode() const { - for (int i = 0; i < m_sourceModel->rowCount(); ++i) { - const ModelNode node = m_sourceModel->sourceNodeAt(i); - if (CollectionEditor::getSourceCollectionFormat(node) == CollectionEditor::SourceFormat::Json) - return node; - } - return {}; + return m_view->dataStoreNode(); } void CollectionWidget::warn(const QString &title, const QString &body) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h index 6700bf91a4d..2be98df1901 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.h @@ -54,6 +54,8 @@ public: Q_INVOKABLE void assignCollectionToSelectedNode(const QString collectionName); + Q_INVOKABLE void ensureDataStoreExists(); + Q_INVOKABLE ModelNode dataStoreNode() const; void warn(const QString &title, const QString &body); diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp index 4b2ab6edbe8..446d7ef08fc 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp @@ -4,6 +4,7 @@ #include "datastoremodelnode.h" #include "collectioneditorconstants.h" +#include "collectioneditorutils.h" #include "model/qmltextgenerator.h" #include @@ -23,21 +24,6 @@ namespace { -Utils::FilePath findFile(const Utils::FilePath &path, const QString &fileName) -{ - QDirIterator it(path.toString(), QDirIterator::Subdirectories); - - while (it.hasNext()) { - QFileInfo file(it.next()); - if (file.isDir()) - continue; - - if (file.fileName() == fileName) - return Utils::FilePath::fromFileInfo(file); - } - return {}; -} - QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node) { using QmlDesigner::AbstractProperty; @@ -74,10 +60,8 @@ void DataStoreModelNode::reloadModel() } bool forceUpdate = false; - const FilePath projectFilePath = ProjectExplorer::ProjectManager::startupProject()->projectDirectory(); - const FilePath importsPath = FilePath::fromString(projectFilePath.path() + "/imports"); - FilePath dataStoreQmlPath = findFile(importsPath, "DataStore.qml"); - FilePath dataStoreJsonPath = findFile(importsPath, "DataStore.json"); + const FilePath dataStoreQmlPath = CollectionEditor::dataStoreQmlFilePath(); + const FilePath dataStoreJsonPath = CollectionEditor::dataStoreJsonFilePath(); QUrl dataStoreQmlUrl = dataStoreQmlPath.toUrl(); if (dataStoreQmlPath.exists() && dataStoreJsonPath.exists()) { From 85e8f7e998fbf9e2aade3035857fb2d2bb573676 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Tue, 28 Nov 2023 11:10:07 +0200 Subject: [PATCH 063/101] QmlDesigner: Remove the collection source item from the ui - Collection Source Model item is removed from the ui - Collection items are realigned Task-number: QDS-11416 Change-Id: Ia185907dec9221494c3551a3a679886910f9cfeb Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Miikka Heikkinen --- .../CollectionItem.qml | 44 +- .../CollectionView.qml | 7 - .../ModelSourceItem.qml | 423 +----------------- .../imports/StudioTheme/Values.qml | 5 + 4 files changed, 33 insertions(+), 446 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionItem.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionItem.qml index 2d26fe8de2d..e5ba5a96e5e 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionItem.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionItem.qml @@ -12,7 +12,7 @@ Item { id: root implicitWidth: 300 - implicitHeight: innerRect.height + 3 + implicitHeight: boundingRect.height + 3 property color textColor property string sourceType @@ -24,9 +24,8 @@ Item { Item { id: boundingRect - anchors.centerIn: root width: parent.width - height: nameHolder.height + height: itemLayout.height clip: true MouseArea { @@ -50,39 +49,24 @@ Item { } RowLayout { + id: itemLayout + width: parent.width - Text { - id: moveTool - - property StudioTheme.ControlStyle textStyle: StudioTheme.Values.viewBarButtonStyle - - Layout.preferredWidth: moveTool.textStyle.squareControlSize.width - Layout.preferredHeight: nameHolder.height - Layout.leftMargin: 12 - Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter - - text: StudioTheme.Constants.dragmarks - font.family: StudioTheme.Constants.iconFont.family - font.pixelSize: moveTool.textStyle.baseIconFontSize - color: root.textColor - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - } - Text { id: nameHolder Layout.fillWidth: true Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter + Layout.leftMargin: StudioTheme.Values.collectionItemTextSideMargin + Layout.topMargin: StudioTheme.Values.collectionItemTextMargin + Layout.bottomMargin: StudioTheme.Values.collectionItemTextMargin text: collectionName font.pixelSize: StudioTheme.Values.baseFontSize color: root.textColor - leftPadding: 5 - topPadding: 8 - rightPadding: 8 - bottomPadding: 8 + topPadding: StudioTheme.Values.collectionItemTextPadding + bottomPadding: StudioTheme.Values.collectionItemTextPadding elide: Text.ElideMiddle verticalAlignment: Text.AlignVCenter } @@ -91,13 +75,16 @@ Item { id: threeDots Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + Layout.topMargin: StudioTheme.Values.collectionItemTextMargin + Layout.bottomMargin: StudioTheme.Values.collectionItemTextMargin + Layout.rightMargin: StudioTheme.Values.collectionItemTextSideMargin + text: StudioTheme.Constants.more_medium font.family: StudioTheme.Constants.iconFont.family font.pixelSize: StudioTheme.Values.baseIconFontSize color: root.textColor - rightPadding: 12 - topPadding: nameHolder.topPadding - bottomPadding: nameHolder.bottomPadding + padding: StudioTheme.Values.collectionItemTextPadding + horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter @@ -144,6 +131,7 @@ Item { title: qsTr("Deleting the model") clip: true + implicitWidth: 300 contentItem: ColumnLayout { spacing: 2 diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml index 33c371f807a..95ef2b4b782 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml @@ -109,14 +109,7 @@ Item { delegate: ModelSourceItem { implicitWidth: sourceListView.width - onDeleteItem: root.model.removeRow(index) hasSelectedTarget: root.rootView.targetNodeSelected - onAddCollection: (collectionName) => { - root.rootView.addCollection(collectionName, - sourceCollectionType, - "", - sourceNode) - } } } } diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml index c453d702bbf..2678a36755b 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ModelSourceItem.qml @@ -12,424 +12,25 @@ Item { id: root implicitWidth: 300 - implicitHeight: wholeColumn.height + implicitHeight: collectionListView.height property bool hasSelectedTarget - property color textColor - property var collectionModel + ListView { + id: collectionListView - property bool expanded: false - readonly property bool isJsonModel: sourceCollectionType === "json" - - signal selectItem(int itemIndex) - signal deleteItem() - signal addCollection(string collectionName) - - function toggleExpanded() { - if (collectionListView.count > 0) - root.expanded = !root.expanded || sourceIsSelected; - } - - ColumnLayout { - id: wholeColumn width: parent.width - spacing: 0 + implicitHeight: contentHeight + leftMargin: 6 - Item { - id: boundingRect + model: internalModels + clip: true - Layout.fillWidth: true - Layout.preferredHeight: nameHolder.height - Layout.leftMargin: 6 - clip: true - - MouseArea { - id: itemMouse - - anchors.fill: parent - acceptedButtons: Qt.LeftButton - propagateComposedEvents: true - hoverEnabled: true - - onClicked: (event) => { - if (!sourceIsSelected) { - sourceIsSelected = true - event.accepted = true - } - } - - onDoubleClicked: (event) => { - root.toggleExpanded() - } - } - - Rectangle { - id: innerRect - anchors.fill: parent - } - - RowLayout { - width: parent.width - - Text { - id: expandButton - - property StudioTheme.ControlStyle textStyle: StudioTheme.Values.viewBarButtonStyle - - Layout.preferredWidth: expandButton.textStyle.squareControlSize.width - Layout.preferredHeight: nameHolder.height - Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter - - text: StudioTheme.Constants.startNode - font.family: StudioTheme.Constants.iconFont.family - font.pixelSize: 6 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - color: textColor - - rotation: root.expanded ? 90 : 0 - visible: collectionListView.count > 0 - - Behavior on rotation { - SpringAnimation { spring: 2; damping: 0.2 } - } - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton | Qt.LeftButton - onClicked: root.toggleExpanded() - } - } - - Text { - id: nameHolder - - Layout.fillWidth: true - Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter - - text: sourceName - font.pixelSize: StudioTheme.Values.baseFontSize - color: textColor - leftPadding: 5 - topPadding: 8 - rightPadding: 8 - bottomPadding: 8 - elide: Text.ElideMiddle - horizontalAlignment: Text.AlignLeft - verticalAlignment: Text.AlignVCenter - } - - Text { - id: threeDots - - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - - text: StudioTheme.Constants.more_medium - font.family: StudioTheme.Constants.iconFont.family - font.pixelSize: StudioTheme.Values.baseIconFontSize - color: textColor - rightPadding: 12 - topPadding: nameHolder.topPadding - bottomPadding: nameHolder.bottomPadding - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton | Qt.LeftButton - onClicked: collectionMenu.popup() - } - } - } - } - - ListView { - id: collectionListView - - Layout.fillWidth: true - Layout.preferredHeight: root.expanded ? contentHeight : 0 - Layout.leftMargin: 6 - model: internalModels - clip: true - - Behavior on Layout.preferredHeight { - NumberAnimation {duration: 500} - } - - delegate: CollectionItem { - width: collectionListView.width - sourceType: collectionListView.model.sourceType - hasSelectedTarget: root.hasSelectedTarget - onDeleteItem: collectionListView.model.removeRow(index) - } + delegate: CollectionItem { + width: collectionListView.width + sourceType: collectionListView.model.sourceType + hasSelectedTarget: root.hasSelectedTarget + onDeleteItem: collectionListView.model.removeRow(index) } } - - StudioControls.Menu { - id: collectionMenu - - closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside - - StudioControls.MenuItem { - text: qsTr("Add a model") - visible: root.isJsonModel && internalModels !== undefined - onTriggered: newCollectionDialog.open() - } - - StudioControls.MenuItem { - text: qsTr("Delete") - shortcut: StandardKey.Delete - onTriggered: deleteDialog.open() - } - - StudioControls.MenuItem { - text: qsTr("Rename") - shortcut: StandardKey.Replace - onTriggered: renameDialog.open() - } - } - - component Spacer: Item { - implicitWidth: 1 - implicitHeight: StudioTheme.Values.sectionColumnSpacing - } - - component NameField: Text { - Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter - horizontalAlignment: Qt.AlignRight - verticalAlignment: Qt.AlignCenter - color: StudioTheme.Values.themeTextColor - font.family: StudioTheme.Constants.font.family - font.pixelSize: StudioTheme.Values.baseIconFontSize - } - - component ErrorField: Text { - color: StudioTheme.Values.themeError - font.family: StudioTheme.Constants.font.family - font.pixelSize: StudioTheme.Values.baseIconFontSize - } - - StudioControls.Dialog { - id: deleteDialog - - title: qsTr("Deleting source") - - contentItem: ColumnLayout { - spacing: StudioTheme.Values.sectionColumnSpacing - - Text { - text: qsTr("Are you sure that you want to delete source \"" + sourceName + "\"?") - color: StudioTheme.Values.themeTextColor - } - - RowLayout { - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - spacing: StudioTheme.Values.sectionRowSpacing - - HelperWidgets.Button { - id: btnDelete - - text: qsTr("Delete") - onClicked: root.deleteItem(index) - } - - HelperWidgets.Button { - text: qsTr("Cancel") - onClicked: deleteDialog.reject() - } - } - } - } - - StudioControls.Dialog { - id: renameDialog - - title: qsTr("Rename source") - - onAccepted: { - if (newNameField.text !== "") - sourceName = newNameField.text - } - - onOpened: { - newNameField.text = sourceName - } - - contentItem: ColumnLayout { - spacing: 2 - - Text { - text: qsTr("Previous name: " + sourceName) - color: StudioTheme.Values.themeTextColor - } - - Spacer {} - - Text { - text: qsTr("New name:") - color: StudioTheme.Values.themeTextColor - } - - StudioControls.TextField { - id: newNameField - - Layout.fillWidth: true - actionIndicator.visible: false - translationIndicator.visible: false - validator: newNameValidator - - Keys.onEnterPressed: renameDialog.accept() - Keys.onReturnPressed: renameDialog.accept() - Keys.onEscapePressed: renameDialog.reject() - - onTextChanged: { - btnRename.enabled = newNameField.text !== "" - } - } - - Spacer {} - - RowLayout { - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - spacing: StudioTheme.Values.sectionRowSpacing - - HelperWidgets.Button { - id: btnRename - - text: qsTr("Rename") - onClicked: renameDialog.accept() - } - - HelperWidgets.Button { - text: qsTr("Cancel") - onClicked: renameDialog.reject() - } - } - } - } - - StudioControls.Dialog { - id: newCollectionDialog - - title: qsTr("Add a new model") - - onOpened: newCollectionName.text = qsTr("Model") - - onAccepted: root.addCollection(newCollectionName.text) - - contentItem: ColumnLayout { - spacing: 2 - - NameField { - text: qsTr("The model name") - } - - StudioControls.TextField { - id: newCollectionName - - readonly property bool isValid: newCollectionName.text !== "" && !newCollectionName.alreadyExists - property bool alreadyExists - - Layout.fillWidth: true - - actionIndicator.visible: false - translationIndicator.visible: false - validator: RegularExpressionValidator { - regularExpression: /^\w+$/ - } - - Keys.onEnterPressed: createCollectionButton.onClicked() - Keys.onReturnPressed: createCollectionButton.onClicked() - Keys.onEscapePressed: newCollectionDialog.reject() - - onTextChanged: newCollectionName.alreadyExists = internalModels.contains(newCollectionName.text) - } - - ErrorField { - text: qsTr("The model name already exists %1").arg(newCollectionName.text) - visible: newCollectionName.alreadyExists - } - - Spacer{} - - RowLayout { - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - spacing: StudioTheme.Values.sectionRowSpacing - - HelperWidgets.Button { - id: createCollectionButton - - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - text: qsTr("Add") - enabled: newCollectionName.isValid - onClicked: newCollectionDialog.accept() - } - - HelperWidgets.Button { - text: qsTr("Cancel") - onClicked: newCollectionDialog.reject() - } - } - } - } - - RegularExpressionValidator { - id: newNameValidator - regularExpression: /^\w+$/ - } - - states: [ - State { - name: "default" - when: !sourceIsSelected && !itemMouse.containsMouse - - PropertyChanges { - target: innerRect - opacity: 0.4 - color: StudioTheme.Values.themeControlBackground - } - - PropertyChanges { - target: root - textColor: StudioTheme.Values.themeTextColor - } - }, - State { - name: "hovered" - when: !sourceIsSelected && itemMouse.containsMouse - - PropertyChanges { - target: innerRect - opacity: 0.5 - color: StudioTheme.Values.themeControlBackgroundHover - } - - PropertyChanges { - target: root - textColor: StudioTheme.Values.themeTextColor - } - }, - State { - name: "selected" - when: sourceIsSelected - - PropertyChanges { - target: innerRect - opacity: 0.6 - color: StudioTheme.Values.themeControlBackgroundInteraction - } - - PropertyChanges { - target: root - textColor: StudioTheme.Values.themeIconColorSelected - expanded: true - } - - PropertyChanges { - target: expandButton - enabled: false - } - } - ] } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml index 82dbf132b19..6b179e42298 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml @@ -242,6 +242,11 @@ QtObject { property real dialogButtonSpacing: 10 property real dialogButtonPadding: 4 + // Collection Editor + property real collectionItemTextSideMargin: 10 + property real collectionItemTextMargin: 5 + property real collectionItemTextPadding: 5 + // NEW NEW NEW readonly property int flowMargin: 7 readonly property int flowSpacing: 7 // Odd so cursor has a center location From a6a8a094c5b52e3317d0b5356ae0de5e95ba1772 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Tue, 18 Apr 2023 10:44:44 +0200 Subject: [PATCH 064/101] HelperWidgets: Explicitly import Basic style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HorizontalScrollBar and VerticalScrollBar customizes ScrollBar. The default Controls style used in Qt 6 depends on the platform the application runs on, and in case of Windows, it will use the native Windows style. The Windows style is not customizable. To avoid issues (like warnings about transitionDuration not being defined), explicitly opt into the Basic style, which can be customized. Fixes: QTBUG-107771 Change-Id: I141b3466964e5c3c64b39ca73a85eac14b9b6202 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Fabian Kosmale Reviewed-by: Reviewed-by: Henning Gründl --- .../imports/HelperWidgets/HorizontalScrollBar.qml | 2 +- .../imports/HelperWidgets/VerticalScrollBar.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/HorizontalScrollBar.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/HorizontalScrollBar.qml index 7ce0324425f..3ae138d600b 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/HorizontalScrollBar.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/HorizontalScrollBar.qml @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick 2.15 -import QtQuick.Controls 2.15 +import QtQuick.Controls.Basic 2.15 import StudioTheme 1.0 as StudioTheme ScrollBar { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/VerticalScrollBar.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/VerticalScrollBar.qml index ed19826e656..8cf54df8e54 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/VerticalScrollBar.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/VerticalScrollBar.qml @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick 2.15 -import QtQuick.Controls 2.15 +import QtQuick.Controls.Basic 2.15 import StudioTheme 1.0 as StudioTheme ScrollBar { From 04ebd7b9c3710d51e9190871bdf8a552f8e95358 Mon Sep 17 00:00:00 2001 From: Fabian Kosmale Date: Tue, 18 Apr 2023 10:44:44 +0200 Subject: [PATCH 065/101] QmlDesigner: Cleanup HelperWidgets ScrollBars Change-Id: Ifc49b0a8c629cb6ed65851a782fe1280079b4a5e Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Thomas Hartmann --- .../imports/HelperWidgets/HorizontalScrollBar.qml | 11 +++++------ .../imports/HelperWidgets/VerticalScrollBar.qml | 6 +++--- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/HorizontalScrollBar.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/HorizontalScrollBar.qml index 3ae138d600b..9041dc17f0d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/HorizontalScrollBar.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/HorizontalScrollBar.qml @@ -1,9 +1,9 @@ // Copyright (C) 2020 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Controls.Basic 2.15 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Controls.Basic +import StudioTheme as StudioTheme ScrollBar { id: scrollBar @@ -13,9 +13,10 @@ ScrollBar { implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitContentHeight + topPadding + bottomPadding) - property bool scrollBarVisible: parent.childrenRect.width > parent.width + minimumSize: orientation == Qt.Horizontal ? height / width : width / height + orientation: Qt.Horizontal policy: scrollBar.scrollBarVisible ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff x: 0 @@ -24,8 +25,6 @@ ScrollBar { - (parent.bothVisible ? parent.verticalThickness : 0) padding: 0 - minimumSize: orientation == Qt.Horizontal ? height / width : width / height - background: Rectangle { color: StudioTheme.Values.themeScrollBarTrack } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/VerticalScrollBar.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/VerticalScrollBar.qml index 8cf54df8e54..520f401116f 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/VerticalScrollBar.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/VerticalScrollBar.qml @@ -1,9 +1,9 @@ // Copyright (C) 2020 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Controls.Basic 2.15 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Controls.Basic +import StudioTheme as StudioTheme ScrollBar { id: scrollBar From 64b50adbf6a06058e6c05e15b134e8d72a46b1bc Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Thu, 30 Nov 2023 10:46:49 +0100 Subject: [PATCH 066/101] QmlDesigner: Hide categories in Qt Insight view The configuration file of Qt Insight changed its form which means predefined categories were dropped and events took over. The insight view needs to be improved in that matter. For the upcoming release we hide categories all together in order to not create confusion. Task-number: QDS-11443 Change-Id: Ia5faa8574d4c856c8a8ee341f74dc97094fc6cee Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Reviewed-by: Thomas Hartmann --- share/qtcreator/qmldesigner/insight/Main.qml | 3 ++- .../imports/HelperWidgets/InsightSection.qml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qmldesigner/insight/Main.qml b/share/qtcreator/qmldesigner/insight/Main.qml index 1abad0050f5..14a69ce80f4 100644 --- a/share/qtcreator/qmldesigner/insight/Main.qml +++ b/share/qtcreator/qmldesigner/insight/Main.qml @@ -166,7 +166,7 @@ Rectangle { } } } - +/* HelperWidgets.Section { id: predefinedSection caption: qsTr("Predefined Categories") @@ -412,6 +412,7 @@ Rectangle { } } } +*/ } } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/InsightSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/InsightSection.qml index b23f8ff95d3..77482bd8488 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/InsightSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/InsightSection.qml @@ -23,6 +23,7 @@ Section { } SectionLayout { +/* PropertyLabel { text: qsTr("Category") } SecondColumnLayout { @@ -84,7 +85,7 @@ Section { ExpandingSpacer {} } - +*/ PropertyLabel { text: qsTr("Object name") tooltip: qsTr("Sets the object name of the component.") From 25ec12ac178c54c050f6312a022686c700dba739 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Fri, 1 Dec 2023 11:11:56 +0100 Subject: [PATCH 067/101] QmlDesigner: Fix property name for SectionLabel Task-number: QDS-11469 Change-Id: I7b7d772792fe79d6d3ccc34e8a58c92a018cca6e Reviewed-by: Ali Kianian Reviewed-by: Thomas Hartmann Reviewed-by: Qt CI Patch Build Bot --- .../imports/StudioControls/Section.qml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Section.qml index d937055dff2..18732305ce7 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Section.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/Section.qml @@ -34,7 +34,7 @@ Item { SectionLabel { id: arrow - style: control.style + controlStyle: control.style width: control.style.smallIconSize.width height: control.style.smallIconSize.height text: StudioTheme.Constants.sectionToggle @@ -56,7 +56,7 @@ Item { SectionLabel { id: label - style: control.style + controlStyle: control.style anchors.verticalCenter: parent.verticalCenter color: control.style.text.idle x: 22 From db0e1a62fc18741eb623e6b20e5194ce938ceb31 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Fri, 1 Dec 2023 12:43:44 +0100 Subject: [PATCH 068/101] QmlDesigner: Fix UrlChooser tooltip binding loop Task-number: QDS-11454 Change-Id: I519df644b4a034bcb103eeecc8bbf52504a9036d Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Thomas Hartmann Reviewed-by: Miikka Heikkinen --- .../imports/HelperWidgets/UrlChooser.qml | 259 +++++++++--------- 1 file changed, 130 insertions(+), 129 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml index 9b0252c02c0..3b00a30a1fc 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/UrlChooser.qml @@ -1,13 +1,13 @@ // Copyright (C) 2022 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -import QtQuick 2.15 -import QtQuick.Layouts 1.15 -import QtQuick.Controls 2.15 -import HelperWidgets 2.0 -import StudioControls 1.0 as StudioControls -import StudioTheme 1.0 as StudioTheme -import QtQuickDesignerTheme 1.0 +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls +import HelperWidgets +import StudioControls as StudioControls +import StudioTheme as StudioTheme +import QtQuickDesignerTheme Row { id: root @@ -44,6 +44,96 @@ Row { backendValue: root.backendValue } + component ThumbnailToolTip: ToolTip { + id: toolTip + + property alias checkerVisible: checker.visible + property alias thumbnailSource: thumbnail.source + + property alias titleText: title.text + property alias descriptionText: description.text + + property int maximumWidth: 420 + + delay: StudioTheme.Values.toolTipDelay + + background: Rectangle { + color: StudioTheme.Values.themeToolTipBackground + border.color: StudioTheme.Values.themeToolTipOutline + border.width: StudioTheme.Values.border + } + + contentItem: Row { + id: row + + readonly property real __epsilon: 2 + + height: Math.max(wrapper.visible ? wrapper.height : 0, column.height) + spacing: 10 + + Item { + id: wrapper + visible: thumbnail.status === Image.Ready + width: 96 + height: 96 + + Image { + id: checker + anchors.fill: parent + fillMode: Image.Tile + source: "images/checkers.png" + } + + Image { + id: thumbnail + anchors.fill: parent + sourceSize.width: wrapper.width + sourceSize.height: wrapper.height + asynchronous: true + fillMode: Image.PreserveAspectFit + } + } + + Column { + id: column + + property int thumbnailSize: wrapper.visible ? wrapper.width + row.spacing : 0 + + spacing: 10 + anchors.verticalCenter: parent.verticalCenter + width: Math.min(toolTip.maximumWidth - column.thumbnailSize, + Math.max(titleTextMetrics.width + row.__epsilon, + descriptionTextMetrics.width + row.__epsilon)) + + Text { + id: title + font: toolTip.font + color: StudioTheme.Values.themeToolTipText + + TextMetrics { + id: titleTextMetrics + text: title.text + font: title.font + } + } + + Text { + id: description + width: column.width + font: toolTip.font + color: StudioTheme.Values.themeToolTipText + wrapMode: Text.Wrap + + TextMetrics { + id: descriptionTextMetrics + text: description.text + font: description.font + } + } + } + } + } + StudioControls.FilterComboBox { id: comboBox @@ -90,71 +180,28 @@ Row { } } - ToolTip { - id: toolTip - visible: comboBox.hover && toolTip.text !== "" + ThumbnailToolTip { + id: rootToolTip + + visible: comboBox.hover && rootToolTip.text !== "" text: root.backendValue?.valueToString ?? "" - delay: StudioTheme.Values.toolTipDelay - background: Rectangle { - color: StudioTheme.Values.themeToolTipBackground - border.color: StudioTheme.Values.themeToolTipOutline - border.width: StudioTheme.Values.border - } - - contentItem: RowLayout { - spacing: 10 - - Item { - visible: thumbnail.status === Image.Ready - Layout.preferredWidth: 96 - Layout.preferredHeight: 96 - - Image { - id: checker - visible: !root.isMesh(root.absoluteFilePath) - anchors.fill: parent - fillMode: Image.Tile - source: "images/checkers.png" - } - - Image { - id: thumbnail - asynchronous: true - height: 96 - width: 96 - fillMode: Image.PreserveAspectFit - source: { - if (root.isBuiltInPrimitive(root.absoluteFilePath)) - return "image://qmldesigner_thumbnails/" - + root.absoluteFilePath.substring(1, root.absoluteFilePath.length) - + ".builtin" - - if (fileModel.isLocal(root.absoluteFilePath)) - return "image://qmldesigner_thumbnails/" + root.absoluteFilePath - - return root.absoluteFilePath - } - } - } - - ColumnLayout { - Text { - text: root.fileName(toolTip.text) - color: StudioTheme.Values.themeToolTipText - font: toolTip.font - } - - Text { - Layout.fillWidth: true - text: root.isBuiltInPrimitive(toolTip.text) ? qsTr("Built-in primitive") - : toolTip.text - font: toolTip.font - color: StudioTheme.Values.themeToolTipText - wrapMode: Text.WordWrap - } - } + checkerVisible: !root.isMesh(root.absoluteFilePath) + thumbnailSource: { + if (root.isBuiltInPrimitive(root.absoluteFilePath)) + return "image://qmldesigner_thumbnails/" + + root.absoluteFilePath.substring(1, root.absoluteFilePath.length) + + ".builtin" + + if (fileModel.isLocal(root.absoluteFilePath)) + return "image://qmldesigner_thumbnails/" + root.absoluteFilePath + + return root.absoluteFilePath } + titleText: root.fileName(rootToolTip.text) + descriptionText: root.isBuiltInPrimitive(rootToolTip.text) + ? qsTr("Built-in primitive") + : rootToolTip.text } delegate: ItemDelegate { @@ -217,71 +264,25 @@ Row { } } - ToolTip { + ThumbnailToolTip { id: delegateToolTip + visible: delegateRoot.hovered text: delegateRoot.relativeFilePath - delay: StudioTheme.Values.toolTipDelay - background: Rectangle { - color: StudioTheme.Values.themeToolTipBackground - border.color: StudioTheme.Values.themeToolTipOutline - border.width: StudioTheme.Values.border - } - - contentItem: RowLayout { - spacing: 10 - - Item { - visible: delegateThumbnail.status === Image.Ready - Layout.preferredWidth: 96 - Layout.preferredHeight: 96 - - Image { - id: delegateChecker - visible: !root.isMesh(delegateRoot.absoluteFilePath) - anchors.fill: parent - fillMode: Image.Tile - source: "images/checkers.png" - } - - Image { - id: delegateThumbnail - asynchronous: true - sourceSize.height: 96 - sourceSize.width: 96 - height: 96 - width: 96 - fillMode: Image.PreserveAspectFit - source: { - if (root.isBuiltInPrimitive(delegateRoot.name)) - return "image://qmldesigner_thumbnails/" - + delegateRoot.name.substring(1, delegateRoot.name.length) - + ".builtin" - - return "image://qmldesigner_thumbnails/" + delegateRoot.absoluteFilePath - } - } - } - - ColumnLayout { - Text { - text: delegateRoot.name - color: StudioTheme.Values.themeToolTipText - font: delegateToolTip.font - } - - Text { - Layout.fillWidth: true - text: root.isBuiltInPrimitive(delegateToolTip.text) - ? qsTr("Built-in primitive") - : delegateToolTip.text - font: delegateToolTip.font - color: StudioTheme.Values.themeToolTipText - wrapMode: Text.WordWrap - } - } + checkerVisible: !root.isMesh(delegateRoot.absoluteFilePath) + thumbnailSource: { + if (root.isBuiltInPrimitive(delegateRoot.name)) + return "image://qmldesigner_thumbnails/" + + delegateRoot.name.substring(1, delegateRoot.name.length) + + ".builtin" + + return "image://qmldesigner_thumbnails/" + delegateRoot.absoluteFilePath } + titleText: delegateRoot.name + descriptionText: root.isBuiltInPrimitive(delegateToolTip.text) + ? qsTr("Built-in primitive") + : delegateToolTip.text } } From 277463bb90c325bf35f11f8eeabf0f33af71f243 Mon Sep 17 00:00:00 2001 From: Henning Gruendl Date: Thu, 30 Nov 2023 18:36:23 +0100 Subject: [PATCH 069/101] QmlDesigner: Fix ColorPicker EyeDropper Task-number: QDS-11451 Change-Id: I8889e0475647bec480757652b84a5751642a6a07 Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Thomas Hartmann --- .../imports/HelperWidgets/ColorEditor.qml | 2 + .../HelperWidgets/ColorEditorPopup.qml | 2 + .../imports/StudioControls/PopupDialog.qml | 5 ++ .../propertyeditor/colorpalettebackend.cpp | 70 +++++++++++++------ .../propertyeditor/colorpalettebackend.h | 6 +- 5 files changed, 62 insertions(+), 23 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml index 48748345e63..3262b03065d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml @@ -183,6 +183,8 @@ SecondColumnLayout { property QtObject loaderItem: loader.item property string gradientPropertyName + keepOpen: loader.item?.eyeDropperActive ?? false + width: 260 function commitToGradient() { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditorPopup.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditorPopup.qml index 29c506e8c52..fcf2d341b89 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditorPopup.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditorPopup.qml @@ -13,6 +13,8 @@ import QtQuickDesignerColorPalette Column { id: root + property bool eyeDropperActive: ColorPaletteBackend.eyeDropperActive + property bool supportGradient: false property bool shapeGradients: false property alias gradientLine: gradientLine diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml index 4bfc0614b4b..594e115639b 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/PopupDialog.qml @@ -32,6 +32,8 @@ QtObject { property rect __itemGlobal: Qt.rect(0, 0, 100, 100) + property bool keepOpen: false + signal closing(close: var) function showGlobal() { @@ -287,6 +289,9 @@ QtObject { if (!focusWindow) return + if (root.keepOpen) + return + if (focusWindow !== window && focusWindow.transientParent !== window) root.close() } diff --git a/src/plugins/qmldesigner/components/propertyeditor/colorpalettebackend.cpp b/src/plugins/qmldesigner/components/propertyeditor/colorpalettebackend.cpp index 5f15f351110..fc5b9c6ebb3 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/colorpalettebackend.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/colorpalettebackend.cpp @@ -3,13 +3,14 @@ #include "colorpalettebackend.h" -#include -#include -#include +#include #include -#include +#include +#include #include +#include +#include namespace QmlDesigner { @@ -205,17 +206,22 @@ void ColorPaletteBackend::showDialog(QColor color) void ColorPaletteBackend::eyeDropper() { - QWindow *window = QGuiApplication::focusWindow(); - if (!window) + QWidget *widget = Core::ICore::mainWindow(); + if (!widget) return; + m_eyeDropperActive = true; + emit eyeDropperActiveChanged(); + if (!m_colorPickingEventFilter) m_colorPickingEventFilter = new QColorPickingEventFilter(this); - window->installEventFilter(m_colorPickingEventFilter); - window->setMouseGrabEnabled(true); - window->setKeyboardGrabEnabled(true); - + widget->installEventFilter(m_colorPickingEventFilter); +#ifndef QT_NO_CURSOR + widget->grabMouse(/*Qt::CrossCursor*/); +#else + widget->grabMouse(); +#endif #ifdef Q_OS_WIN32 // excludes WinRT // On Windows mouse tracking doesn't work over other processes's windows updateTimer->start(30); @@ -224,6 +230,14 @@ void ColorPaletteBackend::eyeDropper() // and loose focus. dummyTransparentWindow.show(); #endif + widget->grabKeyboard(); + /* With setMouseTracking(true) the desired color can be more precisely picked up, + * and continuously pushing the mouse button is not necessary. + */ + widget->setMouseTracking(true); + + QGuiApplication::setOverrideCursor(QCursor()); + updateEyeDropperPosition(QCursor::pos()); } @@ -245,7 +259,12 @@ QImage ColorPaletteBackend::grabScreenRect(const QPoint &p) if (!screen) screen = QGuiApplication::primaryScreen(); - const QPixmap pixmap = screen->grabWindow(0, p.x(), p.y(), g_screenGrabWidth, g_screenGrabHeight); + const QRect screenRect = screen->geometry(); + const QPixmap pixmap = screen->grabWindow(0, + p.x() - screenRect.x(), + p.y() - screenRect.y(), + g_screenGrabWidth, + g_screenGrabHeight); return pixmap.toImage(); } @@ -273,8 +292,8 @@ void ColorPaletteBackend::updateEyeDropperPosition(const QPoint &globalPos) void ColorPaletteBackend::updateCursor(const QImage &image) { - QWindow *window = QGuiApplication::focusWindow(); - if (!window) + QWidget *widget = Core::ICore::mainWindow(); + if (!widget) return; QPixmap pixmap(QSize(g_cursorWidth, g_cursorHeight)); @@ -307,24 +326,28 @@ void ColorPaletteBackend::updateCursor(const QImage &image) painter.drawRect(centerRect); painter.end(); - QCursor cursor(pixmap); - window->setCursor(cursor); + QGuiApplication::changeOverrideCursor(QCursor(pixmap)); } void ColorPaletteBackend::releaseEyeDropper() { - QWindow *window = QGuiApplication::focusWindow(); - if (!window) + QWidget *widget = Core::ICore::mainWindow(); + if (!widget) return; - window->removeEventFilter(m_colorPickingEventFilter); - window->setMouseGrabEnabled(false); + m_eyeDropperActive = false; + emit eyeDropperActiveChanged(); + + widget->removeEventFilter(m_colorPickingEventFilter); + widget->releaseMouse(); #ifdef Q_OS_WIN32 updateTimer->stop(); dummyTransparentWindow.setVisible(false); #endif - window->setKeyboardGrabEnabled(false); - window->unsetCursor(); + widget->releaseKeyboard(); + widget->setMouseTracking(false); + + QGuiApplication::restoreOverrideCursor(); } bool ColorPaletteBackend::handleEyeDropperMouseMove(QMouseEvent *e) @@ -360,4 +383,9 @@ bool ColorPaletteBackend::handleEyeDropperKeyPress(QKeyEvent *e) return true; } +bool ColorPaletteBackend::eyeDropperActive() const +{ + return m_eyeDropperActive; +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/propertyeditor/colorpalettebackend.h b/src/plugins/qmldesigner/components/propertyeditor/colorpalettebackend.h index 152a8a6d1e7..9ab60d7c9e6 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/colorpalettebackend.h +++ b/src/plugins/qmldesigner/components/propertyeditor/colorpalettebackend.h @@ -71,6 +71,7 @@ class ColorPaletteBackend : public QObject Q_PROPERTY(QStringList palettes READ palettes NOTIFY palettesChanged) + Q_PROPERTY(bool eyeDropperActive READ eyeDropperActive NOTIFY eyeDropperActiveChanged) public: ~ColorPaletteBackend(); @@ -82,7 +83,6 @@ public: void removeColor(int id, const QString &palette); Q_INVOKABLE void addRecentColor(const QString &color); - Q_INVOKABLE void addFavoriteColor(const QString &color); Q_INVOKABLE void removeFavoriteColor(int id); @@ -100,7 +100,6 @@ public: Q_INVOKABLE void showDialog(QColor color); - Q_INVOKABLE void eyeDropper(); QColor grabScreenColor(const QPoint &p); @@ -116,6 +115,7 @@ public: bool handleEyeDropperMouseButtonRelease(QMouseEvent *e); bool handleEyeDropperKeyPress(QKeyEvent *e); + bool eyeDropperActive() const; ColorPaletteBackend(const ColorPaletteBackend &) = delete; void operator=(const ColorPaletteBackend &) = delete; @@ -129,6 +129,7 @@ signals: void currentColorChanged(const QColor &color); void eyeDropperRejected(); + void eyeDropperActiveChanged(); private: ColorPaletteBackend(); @@ -140,6 +141,7 @@ private: QHash m_data; QColorPickingEventFilter *m_colorPickingEventFilter; + bool m_eyeDropperActive = false; #ifdef Q_OS_WIN32 QTimer *updateTimer; QWindow dummyTransparentWindow; From 6e566bac275bafb250ad28e188b088e8c004c252 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 1 Dec 2023 15:20:34 +0200 Subject: [PATCH 070/101] EffectMaker: Hide properties that use custom value These properties would require custom editor, so hide them for now. Typically there is no need to change these values from defaults. Fixes: QDS-11419 Change-Id: Ia91d48f5df86885420dccef47ed024af4cc8f430 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Mahmoud Badri --- .../effectMakerQmlSources/EffectCompositionNodeUniform.qml | 2 ++ src/plugins/effectmakernew/effectmakeruniformsmodel.cpp | 1 + src/plugins/effectmakernew/effectmakeruniformsmodel.h | 1 + src/plugins/effectmakernew/uniform.h | 1 + 4 files changed, 5 insertions(+) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNodeUniform.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNodeUniform.qml index 6aedc798f59..d696fccc1eb 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNodeUniform.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNodeUniform.qml @@ -15,6 +15,8 @@ Item { height: layout.implicitHeight + visible: !uniformUseCustomValue + Component.onCompleted: { if (uniformType === "int") valueLoader.source = "ValueInt.qml" diff --git a/src/plugins/effectmakernew/effectmakeruniformsmodel.cpp b/src/plugins/effectmakernew/effectmakeruniformsmodel.cpp index cfbbf3f5778..c4f9796f835 100644 --- a/src/plugins/effectmakernew/effectmakeruniformsmodel.cpp +++ b/src/plugins/effectmakernew/effectmakeruniformsmodel.cpp @@ -26,6 +26,7 @@ QHash EffectMakerUniformsModel::roleNames() const roles[MinValueRole] = "uniformMinValue"; roles[MaxValueRole] = "uniformMaxValue"; roles[TypeRole] = "uniformType"; + roles[UseCustomValueRole] = "uniformUseCustomValue"; return roles; } diff --git a/src/plugins/effectmakernew/effectmakeruniformsmodel.h b/src/plugins/effectmakernew/effectmakeruniformsmodel.h index 9b9651a8720..8b83a63dfe3 100644 --- a/src/plugins/effectmakernew/effectmakeruniformsmodel.h +++ b/src/plugins/effectmakernew/effectmakeruniformsmodel.h @@ -37,6 +37,7 @@ private: MaxValueRole, MinValueRole, TypeRole, + UseCustomValueRole }; QList m_uniforms; diff --git a/src/plugins/effectmakernew/uniform.h b/src/plugins/effectmakernew/uniform.h index 943942639c9..7216c6d9d6b 100644 --- a/src/plugins/effectmakernew/uniform.h +++ b/src/plugins/effectmakernew/uniform.h @@ -26,6 +26,7 @@ class Uniform : public QObject Q_PROPERTY(QVariant uniformMinValue MEMBER m_minValue CONSTANT) Q_PROPERTY(QVariant uniformMaxValue MEMBER m_maxValue CONSTANT) Q_PROPERTY(QVariant uniformDefaultValue MEMBER m_defaultValue CONSTANT) + Q_PROPERTY(QVariant uniformUseCustomValue MEMBER m_useCustomValue CONSTANT) public: enum class Type From 70f9e35c620b72e89d823bfb0c6586954239388b Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Wed, 29 Nov 2023 17:30:31 +0200 Subject: [PATCH 071/101] QmlDesigner: Polish the ui of the Model Editor - The main toolbar of the Model editor is aligned with the rest of the ui - Update/Save icon is updated - Tooltips for save and export actions are modified - Minimum size for the Model editor is applied Fixes: QDS-11449 Fixes: QDS-11244 Change-Id: Ice389ae439ac855eb3a5d3197a2365e6d2506a90 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Mahmoud Badri --- .../CollectionDetailsToolbar.qml | 6 ++--- .../CollectionView.qml | 25 +++++++++++-------- .../collectioneditor/collectionview.cpp | 1 + 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml index e627a6b6db4..78a8152a762 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml @@ -99,15 +99,15 @@ Item { Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter IconButton { - icon: StudioTheme.Constants.updateContent_medium - tooltip: qsTr("Update existing file with changes") + icon: StudioTheme.Constants.save_medium + tooltip: qsTr("Save changes") enabled: root.model.collectionName !== "" onClicked: root.model.saveCurrentCollection() } IconButton { icon: StudioTheme.Constants.export_medium - tooltip: qsTr("Export the model to a new file") + tooltip: qsTr("Export model") enabled: root.model.collectionName !== "" onClicked: fileDialog.open() } diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml index 95ef2b4b782..32f71cc231b 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionView.qml @@ -55,32 +55,35 @@ Item { ColumnLayout { id: collectionsSideBar + spacing: 0 Layout.alignment: Qt.AlignTop | Qt.AlignLeft Layout.minimumWidth: 300 Layout.fillWidth: !grid.isHorizontal - RowLayout { - spacing: StudioTheme.Values.sectionRowSpacing + Rectangle { + color: StudioTheme.Values.themeToolbarBackground + Layout.preferredHeight: StudioTheme.Values.toolbarHeight Layout.fillWidth: true - Layout.preferredHeight: 50 Text { - Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter - Layout.fillWidth: true + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: StudioTheme.Values.toolbarHorizontalMargin text: qsTr("Data Models") font.pixelSize: StudioTheme.Values.baseFontSize color: StudioTheme.Values.themeTextColor - leftPadding: 15 } - HelperWidgets.IconButton { - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter + HelperWidgets.AbstractButton { + anchors.verticalCenter: parent.verticalCenter + anchors.right: parent.right + anchors.rightMargin: StudioTheme.Values.toolbarHorizontalMargin - icon: StudioTheme.Constants.import_medium + style: StudioTheme.Values.viewBarButtonStyle + buttonIcon: StudioTheme.Constants.import_medium tooltip: qsTr("Import a model") - radius: StudioTheme.Values.smallRadius onClicked: importDialog.open() } @@ -117,7 +120,7 @@ Item { HelperWidgets.IconButton { id: addCollectionButton - iconSize:16 + iconSize: 16 Layout.fillWidth: true Layout.minimumWidth: 24 Layout.alignment: Qt.AlignTop | Qt.AlignHCenter diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp index f6a24280d18..9140f02ec53 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp @@ -61,6 +61,7 @@ QmlDesigner::WidgetInfo CollectionView::widgetInfo() { if (m_widget.isNull()) { m_widget = new CollectionWidget(this); + m_widget->setMinimumSize(m_widget->minimumSizeHint()); auto collectionEditorContext = new Internal::CollectionEditorContext(m_widget.data()); Core::ICore::addContextObject(collectionEditorContext); From 11a84a8754910f886ef7be6313d3fe119784f47e Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Mon, 4 Dec 2023 11:27:37 +0200 Subject: [PATCH 072/101] QmlDesigner: Fix content library license check Fixes: QDS-9680 Change-Id: I96a85bba779f373144fb04b4ede4b39f898957e6 Reviewed-by: Mahmoud Badri Reviewed-by: Tim Jenssen --- .../components/componentcore/viewmanager.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp index ade7a521a89..d26618dbdad 100644 --- a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -224,12 +225,8 @@ QList ViewManager::standardViews() const .toBool()) list.append(&d->debugView); -#ifdef CHECK_LICENSE - if (checkLicense() == FoundLicense::enterprise) + if (checkEnterpriseLicense()) list.append(&d->contentLibraryView); -#else - list.append(&d->contentLibraryView); -#endif return list; } @@ -401,12 +398,8 @@ QList ViewManager::widgetInfos() const if (enableModelEditor()) widgetInfoList.append(d->collectionView.widgetInfo()); -#ifdef CHECK_LICENSE - if (checkLicense() == FoundLicense::enterprise) + if (checkEnterpriseLicense()) widgetInfoList.append(d->contentLibraryView.widgetInfo()); -#else - widgetInfoList.append(d->contentLibraryView.widgetInfo()); -#endif if (d->debugView.hasWidget()) widgetInfoList.append(d->debugView.widgetInfo()); From 8f6e90783c52d0ba26b902876375efd547c2314b Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Fri, 1 Dec 2023 14:13:01 +0200 Subject: [PATCH 073/101] QmlDesigner: Fix the bug for importing json file - Json objects are considered valid in the json arrays. - Json arrays are removed from the row objects. Fixes: QDS-11472 Change-Id: I89d7fb6d12952a994cf5e3aab0869154a3ab5d27 Reviewed-by: Mahmoud Badri Reviewed-by: Miikka Heikkinen Reviewed-by: Shrief Gabr Reviewed-by: Qt CI Patch Build Bot --- .../collectioneditor/collectionimporttools.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.cpp index b3691ce78b4..183730873d6 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionimporttools.cpp @@ -33,8 +33,16 @@ QJsonArray loadAsSingleJsonCollection(const QUrl &url) auto refineJsonArray = [](const QJsonArray &array) -> QJsonArray { QJsonArray resultArray; for (const QJsonValue &collectionData : array) { - if (!collectionData.isObject()) - resultArray.push_back(collectionData); + if (collectionData.isObject()) { + QJsonObject rowObject = collectionData.toObject(); + const QStringList rowKeys = rowObject.keys(); + for (const QString &key : rowKeys) { + QJsonValue cellValue = rowObject.value(key); + if (cellValue.isArray()) + rowObject.remove(key); + } + resultArray.push_back(rowObject); + } } return resultArray; }; From 500febad2537b170640ec0e4ecc2f27748a3d9b4 Mon Sep 17 00:00:00 2001 From: Aleksei German Date: Mon, 4 Dec 2023 17:21:04 +0100 Subject: [PATCH 074/101] QmlDesigner: Fix for Basic Controls style Task-number: QDS-10980 Change-Id: Ia50bbe602dc54b5684c1ee432052e8c33559ef7f Reviewed-by: Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Tim Jenssen --- src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp index 6ce8ef193a5..e42d71d24bb 100644 --- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp @@ -504,7 +504,7 @@ void ToolBarBackend::setCurrentStyle(int index) const QList items = ChangeStyleWidgetAction::getAllStyleItems(); QTC_ASSERT(items.size() > index, return); - QTC_ASSERT(index > 0, return ); + QTC_ASSERT(index >= 0, return ); QTC_ASSERT(currentDesignDocument(), return ); From 9184db8dfb3ef71b6c54815f937387e5d959cadb Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 5 Dec 2023 11:46:14 +0100 Subject: [PATCH 075/101] StudioWelcome: Fix help url for getting started Task-number: QDS-9780 Change-Id: I32a3f5782cda1611ce12588873ac6f45620adf52 Reviewed-by: Tim Jenssen --- src/plugins/studiowelcome/studiowelcomeplugin.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index d9b29ffb951..2c6cd60379e 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -296,7 +296,8 @@ public: Q_INVOKABLE void showHelp() { - QDesktopServices::openUrl(QUrl("qthelp://org.qt-project.qtdesignstudio/doc/index.html")); + QDesktopServices::openUrl( + QUrl("qthelp://org.qt-project.qtdesignstudio/doc/studio-getting-started.html")); } Q_INVOKABLE void openExample(const QString &examplePath, From b5370c435eabc647e30e5dd366d668b65a076a04 Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 5 Dec 2023 16:05:06 +0200 Subject: [PATCH 076/101] EffectMaker: Block adding same effect node twice The actual blocking is done at uniform level, as the problem of having same effect node twice is duplicate uniforms. Fixes: QDS-11470 Change-Id: I77b15b4a207efaebff39b4f6b1700d70262abcdb Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Patch Build Bot --- .../effectMakerQmlSources/EffectNode.qml | 18 +++++++++------ .../effectmakernew/effectmakermodel.cpp | 22 ++++++++++++++----- src/plugins/effectmakernew/effectmakermodel.h | 5 ++++- .../effectmakernew/effectmakernodesmodel.cpp | 21 ++++++++++++++++++ .../effectmakernew/effectmakernodesmodel.h | 3 +++ .../effectmakernew/effectmakerwidget.cpp | 4 ++++ src/plugins/effectmakernew/effectnode.cpp | 21 ++++++++++++++++++ src/plugins/effectmakernew/effectnode.h | 11 ++++++++++ 8 files changed, 92 insertions(+), 13 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml index 8ae703adb7e..f3fca1ccec7 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectNode.qml @@ -15,20 +15,22 @@ Rectangle { width: 140 height: 32 - color: mouseArea.containsMouse ? StudioTheme.Values.themeControlBackgroundInteraction - : "transparent" + color: mouseArea.containsMouse && modelData.canBeAdded + ? StudioTheme.Values.themeControlBackgroundInteraction : "transparent" signal addEffectNode(var nodeQenPath) - MouseArea { + ToolTipArea { id: mouseArea anchors.fill: parent - hoverEnabled: true acceptedButtons: Qt.LeftButton + tooltip: modelData.canBeAdded ? "" : qsTr("Existing effect has conflicting properties, this effect cannot be added.") + onClicked: { - root.addEffectNode(modelData.nodeQenPath) + if (modelData.canBeAdded) + root.addEffectNode(modelData.nodeQenPath) } } @@ -41,13 +43,15 @@ Rectangle { width: 32 height: 32 - color: StudioTheme.Values.themeTextColor + color: modelData.canBeAdded ? StudioTheme.Values.themeTextColor + : StudioTheme.Values.themeTextColorDisabled source: modelData.nodeIcon } Text { text: modelData.nodeName - color: StudioTheme.Values.themeTextColor + color: modelData.canBeAdded ? StudioTheme.Values.themeTextColor + : StudioTheme.Values.themeTextColorDisabled font.pointSize: StudioTheme.Values.smallFontSize anchors.verticalCenter: nodeIcon.verticalCenter } diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index 58f46b2b1fe..f71fa1d75f5 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -112,6 +112,8 @@ void EffectMakerModel::addNode(const QString &nodeQenPath) setIsEmpty(false); bakeShaders(); + + emit nodesChanged(); } void EffectMakerModel::moveNode(int fromIdx, int toIdx) @@ -138,6 +140,8 @@ void EffectMakerModel::removeNode(int idx) setIsEmpty(true); else bakeShaders(); + + emit nodesChanged(); } void EffectMakerModel::clear() @@ -148,6 +152,7 @@ void EffectMakerModel::clear() endResetModel(); setIsEmpty(true); + emit nodesChanged(); } QString EffectMakerModel::fragmentShader() const @@ -181,7 +186,7 @@ const QString &EffectMakerModel::qmlComponentString() const return m_qmlComponentString; } -const QList EffectMakerModel::allUniforms() +const QList EffectMakerModel::allUniforms() const { QList uniforms = {}; for (const auto &node : std::as_const(m_nodes)) @@ -604,10 +609,6 @@ void EffectMakerModel::openComposition(const QString &path) return; } - // Get effects dir - const Utils::FilePath effectsResDir = QmlDesigner::ModelNodeOperations::getEffectsImportDirectory(); - const QString effectsResPath = effectsResDir.pathAppended(effectName).toString(); - if (json.contains("nodes") && json["nodes"].isArray()) { const QJsonArray nodesArray = json["nodes"].toArray(); for (const auto &nodeElement : nodesArray) { @@ -620,6 +621,8 @@ void EffectMakerModel::openComposition(const QString &path) setIsEmpty(m_nodes.isEmpty()); bakeShaders(); } + + emit nodesChanged(); } void EffectMakerModel::exportResources(const QString &name) @@ -1438,6 +1441,15 @@ void EffectMakerModel::setCurrentComposition(const QString &newCurrentCompositio emit currentCompositionChanged(); } +QStringList EffectMakerModel::uniformNames() const +{ + QStringList usedList; + const QList uniforms = allUniforms(); + for (const auto uniform : uniforms) + usedList.append(uniform->name()); + return usedList; +} + void EffectMakerModel::updateQmlComponent() { // Clear possible QML runtime errors diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h index 9582450d845..1f4284b0813 100644 --- a/src/plugins/effectmakernew/effectmakermodel.h +++ b/src/plugins/effectmakernew/effectmakermodel.h @@ -89,6 +89,8 @@ public: QString currentComposition() const; void setCurrentComposition(const QString &newCurrentComposition); + QStringList uniformNames() const; + signals: void isEmptyChanged(); void selectedIndexChanged(int idx); @@ -97,6 +99,7 @@ signals: void shadersBaked(); void currentCompositionChanged(); + void nodesChanged(); private: enum Roles { @@ -116,7 +119,7 @@ private: bool isValidIndex(int idx) const; - const QList allUniforms(); + const QList allUniforms() const; const QString getBufUniform(); const QString getVSUniforms(); diff --git a/src/plugins/effectmakernew/effectmakernodesmodel.cpp b/src/plugins/effectmakernew/effectmakernodesmodel.cpp index dce99bba26e..c6773faa090 100644 --- a/src/plugins/effectmakernew/effectmakernodesmodel.cpp +++ b/src/plugins/effectmakernew/effectmakernodesmodel.cpp @@ -52,6 +52,9 @@ QString EffectMakerNodesModel::nodesSourcesPath() const void EffectMakerNodesModel::loadModel() { + if (m_modelLoaded) + return; + auto nodesPath = Utils::FilePath::fromString(nodesSourcesPath()); if (!nodesPath.exists()) { @@ -88,6 +91,8 @@ void EffectMakerNodesModel::loadModel() return a->name() < b->name(); }); + m_modelLoaded = true; + resetModel(); } @@ -97,4 +102,20 @@ void EffectMakerNodesModel::resetModel() endResetModel(); } +void EffectMakerNodesModel::updateCanBeAdded(const QStringList &uniforms) +{ + for (const EffectNodesCategory *cat : std::as_const(m_categories)) { + const QList nodes = cat->nodes(); + for (EffectNode *node : nodes) { + bool match = false; + for (const QString &uniform : uniforms) { + match = node->hasUniform(uniform); + if (match) + break; + } + node->setCanBeAdded(!match); + } + } +} + } // namespace EffectMaker diff --git a/src/plugins/effectmakernew/effectmakernodesmodel.h b/src/plugins/effectmakernew/effectmakernodesmodel.h index 56400982da3..7320ca729fc 100644 --- a/src/plugins/effectmakernew/effectmakernodesmodel.h +++ b/src/plugins/effectmakernew/effectmakernodesmodel.h @@ -30,11 +30,14 @@ public: QList categories() const { return m_categories; } + void updateCanBeAdded(const QStringList &uniforms); + private: QString nodesSourcesPath() const; QList m_categories; bool m_probeNodesDir = false; + bool m_modelLoaded = false; }; } // namespace EffectMaker diff --git a/src/plugins/effectmakernew/effectmakerwidget.cpp b/src/plugins/effectmakernew/effectmakerwidget.cpp index 724ab04f892..e11b4015a10 100644 --- a/src/plugins/effectmakernew/effectmakerwidget.cpp +++ b/src/plugins/effectmakernew/effectmakerwidget.cpp @@ -76,6 +76,10 @@ EffectMakerWidget::EffectMakerWidget(EffectMakerView *view) {"rootView", QVariant::fromValue(this)}}); QmlDesigner::QmlDesignerPlugin::trackWidgetFocusTime( this, QmlDesigner::Constants::EVENT_NEWEFFECTMAKER_TIME); + + connect(m_effectMakerModel.data(), &EffectMakerModel::nodesChanged, [this]() { + m_effectMakerNodesModel->updateCanBeAdded(m_effectMakerModel->uniformNames()); + }); } diff --git a/src/plugins/effectmakernew/effectnode.cpp b/src/plugins/effectmakernew/effectnode.cpp index 292c04d13e5..fc9d8ae7bfd 100644 --- a/src/plugins/effectmakernew/effectnode.cpp +++ b/src/plugins/effectmakernew/effectnode.cpp @@ -2,6 +2,8 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "effectnode.h" +#include "compositionnode.h" +#include "uniform.h" #include #include @@ -22,6 +24,12 @@ EffectNode::EffectNode(const QString &qenPath) iconPath = QStringLiteral("%1/%2").arg(parentDir.path(), "placeholder.svg"); } m_iconPath = QUrl::fromLocalFile(iconPath); + + CompositionNode node({}, qenPath); + const QList uniforms = node.uniforms(); + + for (const Uniform *uniform : uniforms) + m_uniformNames.insert(uniform->name()); } QString EffectNode::name() const @@ -39,5 +47,18 @@ QString EffectNode::qenPath() const return m_qenPath; } +void EffectNode::setCanBeAdded(bool enabled) +{ + if (enabled != m_canBeAdded) { + m_canBeAdded = enabled; + emit canBeAddedChanged(); + } +} + +bool EffectNode::hasUniform(const QString &name) +{ + return m_uniformNames.contains(name); +} + } // namespace EffectMaker diff --git a/src/plugins/effectmakernew/effectnode.h b/src/plugins/effectmakernew/effectnode.h index 5c457e2a6de..864904e088c 100644 --- a/src/plugins/effectmakernew/effectnode.h +++ b/src/plugins/effectmakernew/effectnode.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include namespace EffectMaker { @@ -16,6 +17,7 @@ class EffectNode : public QObject Q_PROPERTY(QString nodeDescription MEMBER m_description CONSTANT) Q_PROPERTY(QUrl nodeIcon MEMBER m_iconPath CONSTANT) Q_PROPERTY(QString nodeQenPath MEMBER m_qenPath CONSTANT) + Q_PROPERTY(bool canBeAdded MEMBER m_canBeAdded NOTIFY canBeAddedChanged) public: EffectNode(const QString &qenPath); @@ -24,11 +26,20 @@ public: QString description() const; QString qenPath() const; + void setCanBeAdded(bool enabled); + + bool hasUniform(const QString &name); + +signals: + void canBeAddedChanged(); + private: QString m_name; QString m_description; QString m_qenPath; QUrl m_iconPath; + bool m_canBeAdded = true; + QSet m_uniformNames; }; } // namespace EffectMaker From c3d22dfcd986af9ce4ff94c94518e278c8029bb4 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Tue, 5 Dec 2023 13:58:57 +0100 Subject: [PATCH 077/101] QmlDesigner: Avoid deletion and recreation of keyframes if possible Without this all keyframes are first deleted and then recreated. This becomes notable slow with a larger number of keyframes, since the timeline does react to each deletion/creation and rebuilds the scene for the group. Instead we can keep all keyframes and simply adjust their frame. Change-Id: Ic34ffbdea74f57cf8f5bcddfbce8a8c18ffef7b0 Reviewed-by: Knud Dollereder Reviewed-by: Qt CI Patch Build Bot --- .../components/curveeditor/curveeditorview.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp index e7395c66625..afe704a59d9 100644 --- a/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/curveeditorview.cpp @@ -307,10 +307,20 @@ void CurveEditorView::commitKeyframes(TreeItem *item) auto replaceKeyframes = [&group, pitem, this]() mutable { m_block = true; - for (auto& frame : group.keyframes()) - frame.destroy(); - AnimationCurve curve = pitem->curve(); + + unsigned int i = 0; + const size_t numberOfKeyFrames = curve.keyframes().size(); + for (auto &frame : group.keyframes()) { + if (i < numberOfKeyFrames) { + QPointF pos = curve.keyframes().at(i).position(); + frame.variantProperty("frame").setValue(pos.x()); + } else { + frame.destroy(); + } + i++; + } + if (curve.valueType() == AnimationCurve::ValueType::Bool) { for (const auto& frame : curve.keyframes()) { QPointF pos = frame.position(); From bb690b4ccc425dc1fa160356a4b53bb8e4d620d9 Mon Sep 17 00:00:00 2001 From: Ali Kianian Date: Thu, 7 Dec 2023 09:36:43 +0200 Subject: [PATCH 078/101] QmlDesigner: Fix the bug for showing focused widget-based scrollbars MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: QDS-11474 Change-Id: Ibfc156893812ab7a541fe01e995fe528a1d80d2f Reviewed-by: Henning Gründl Reviewed-by: Qt CI Patch Build Bot --- src/libs/advanceddockingsystem/dockwidget.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libs/advanceddockingsystem/dockwidget.cpp b/src/libs/advanceddockingsystem/dockwidget.cpp index 9c9e6086cd5..f216ac7495e 100644 --- a/src/libs/advanceddockingsystem/dockwidget.cpp +++ b/src/libs/advanceddockingsystem/dockwidget.cpp @@ -309,8 +309,11 @@ void DockWidget::setWidget(QWidget *widget, eInsertMode insertMode) auto scrollAreaWidget = qobject_cast(widget); if (scrollAreaWidget || ForceNoScrollArea == insertMode) { d->m_layout->addWidget(widget); - if (scrollAreaWidget && scrollAreaWidget->viewport()) - scrollAreaWidget->viewport()->setProperty("dockWidgetContent", true); + if (scrollAreaWidget) { + if (scrollAreaWidget->viewport()) + scrollAreaWidget->viewport()->setProperty("dockWidgetContent", true); + scrollAreaWidget->setProperty("focused", isFocused()); + } } else { d->setupScrollArea(); d->m_scrollArea->setWidget(widget); @@ -482,6 +485,11 @@ void DockWidget::setFocused(bool focused) if (d->m_scrollArea) d->m_scrollArea->setProperty("focused", focused); + QList scrollAreas = d->m_widget->findChildren( + Qt::FindDirectChildrenOnly); + for (QAbstractScrollArea *scrollArea : scrollAreas) + scrollArea->setProperty("focused", focused); + const QString customObjectName = QString("__mainSrollView"); QList quickWidgets = d->m_widget->findChildren(); From dfcb3d046235a6cad42098e64fcdc3e4679425ff Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Mon, 4 Dec 2023 17:04:19 +0200 Subject: [PATCH 079/101] QmlDesigner: Improve collection editor edit column dialog - move name and type fields to same line as their labels to reduce dialog's height - remove "force" option, force by default after showing a warning - focus and select name field upon dialog open - when opening the dialog for last column, align right to avoid overflow - bunch of cleanups and naming improvements Fixes: QDS-11245 Fixes: QDS-11250 Change-Id: I613a9cf693320b0bc0768ea709eb47e00d218222 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Reviewed-by: Miikka Heikkinen Reviewed-by: Shrief Gabr --- .../CollectionDetailsView.qml | 37 ++-- .../EditPropertyDialog.qml | 170 +++++++----------- .../collectioneditor/collectiondetails.cpp | 14 +- .../collectioneditor/collectiondetails.h | 2 +- .../collectiondetailsmodel.cpp | 17 +- .../collectioneditor/collectiondetailsmodel.h | 2 +- 6 files changed, 97 insertions(+), 145 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml index 42e145bd905..4585fa49d1d 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml @@ -109,15 +109,9 @@ Rectangle { clip: true delegate: HeaderDelegate { - id: horizontalHeaderItem - selectedItem: tableView.model.selectedColumn color: StudioTheme.Values.themeControlBackgroundInteraction - function getGlobalBottomLeft() { - return mapToGlobal(0, horizontalHeaderItem.height) - } - MouseArea { anchors.fill: parent anchors.margins: 5 @@ -125,8 +119,13 @@ Rectangle { onClicked: (mouse) => { tableView.model.selectColumn(index) - if (mouse.button === Qt.RightButton) - headerMenu.popIndex(index, horizontalHeaderItem.getGlobalBottomLeft()) + if (mouse.button === Qt.RightButton) { + let posX = index === root.model.columnCount() - 1 ? parent.width - editProperyDialog.width : 0 + + headerMenu.clickedHeaderIndex = index + headerMenu.dialogPos = parent.mapToGlobal(posX, parent.height) + headerMenu.popup() + } } } } @@ -134,38 +133,32 @@ Rectangle { StudioControls.Menu { id: headerMenu - property int clickedHeader: -1 - property point initialPosition - - function popIndex(clickedIndex, clickedRect) - { - headerMenu.clickedHeader = clickedIndex - headerMenu.initialPosition = clickedRect - headerMenu.popup() - } + property int clickedHeaderIndex: -1 + property point dialogPos onClosed: { - headerMenu.clickedHeader = -1 + headerMenu.clickedHeaderIndex = -1 } StudioControls.MenuItem { text: qsTr("Edit") - onTriggered: editProperyDialog.editProperty(headerMenu.clickedHeader, headerMenu.initialPosition) + onTriggered: editProperyDialog.openDialog(headerMenu.clickedHeaderIndex, + headerMenu.dialogPos) } StudioControls.MenuItem { text: qsTr("Delete") - onTriggered: deleteColumnDialog.popUp(headerMenu.clickedHeader) + onTriggered: deleteColumnDialog.popUp(headerMenu.clickedHeaderIndex) } StudioControls.MenuItem { text: qsTr("Sort Ascending") - onTriggered: sortedModel.sort(headerMenu.clickedHeader, Qt.AscendingOrder) + onTriggered: sortedModel.sort(headerMenu.clickedHeaderIndex, Qt.AscendingOrder) } StudioControls.MenuItem { text: qsTr("Sort Descending") - onTriggered: sortedModel.sort(headerMenu.clickedHeader, Qt.DescendingOrder) + onTriggered: sortedModel.sort(headerMenu.clickedHeaderIndex, Qt.DescendingOrder) } } } diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/EditPropertyDialog.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/EditPropertyDialog.qml index 545896cc278..37fd92cdd61 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/EditPropertyDialog.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/EditPropertyDialog.qml @@ -12,26 +12,22 @@ StudioControls.Dialog { required property var model property int __propertyIndex: -1 - property string __oldName + property string __currentName - title: qsTr("Edit Property") - clip: true + title: qsTr("Edit Column") - function editProperty(index, initialPosition) { + function openDialog(index, initialPosition) { root.__propertyIndex = index if (root.__propertyIndex < 0) return - let previousName = root.model.propertyName(root.__propertyIndex) - let previousType = root.model.propertyType(root.__propertyIndex) + root.__currentName = root.model.propertyName(root.__propertyIndex) + nameTextField.text = root.__currentName + nameTextField.selectAll() + nameTextField.forceActiveFocus() - root.__oldName = previousName - newNameField.text = previousName - - propertyType.initialType = previousType - - forceChangeType.checked = false + typeComboBox.initialType = root.model.propertyType(root.__propertyIndex) let newPoint = mapFromGlobal(initialPosition.x, initialPosition.y) x = newPoint.x @@ -41,144 +37,116 @@ StudioControls.Dialog { } onAccepted: { - if (newNameField.text !== "" && newNameField.text !== root.__oldName) - root.model.renameColumn(root.__propertyIndex, newNameField.text) + if (nameTextField.text !== "" && nameTextField.text !== root.__currentName) + root.model.renameColumn(root.__propertyIndex, nameTextField.text) - if (propertyType.changed || forceChangeType.checked) - root.model.setPropertyType(root.__propertyIndex, propertyType.currentText, forceChangeType.checked) + if (typeComboBox.initialType !== typeComboBox.currentText) + root.model.setPropertyType(root.__propertyIndex, typeComboBox.currentText) } - onRejected: { - let currentDatatype = propertyType.initialType - propertyType.currentIndex = propertyType.find(currentDatatype) - } + contentItem: Column { + spacing: 5 - component Spacer: Item { - implicitWidth: 1 - implicitHeight: StudioTheme.Values.columnGap - } + Grid { + columns: 2 + rows: 2 + spacing: 2 + verticalItemAlignment: Grid.AlignVCenter - contentItem: ColumnLayout { - spacing: 2 - - Text { - text: qsTr("Name") - color: StudioTheme.Values.themeTextColor - } - - StudioControls.TextField { - id: newNameField - - Layout.fillWidth: true - - actionIndicator.visible: false - translationIndicator.visible: false - - Keys.onEnterPressed: root.accept() - Keys.onReturnPressed: root.accept() - Keys.onEscapePressed: root.reject() - - validator: RegularExpressionValidator { - regularExpression: /^\w+$/ + Text { + text: qsTr("Name") + color: StudioTheme.Values.themeTextColor + width: 50 + verticalAlignment: Text.AlignVCenter } - onTextChanged: { - editButton.enabled = newNameField.text !== "" - } - } + StudioControls.TextField { + id: nameTextField - Spacer {} + actionIndicator.visible: false + translationIndicator.visible: false - Text { - text: qsTr("Type") - color: StudioTheme.Values.themeTextColor - } + Keys.onEnterPressed: root.accept() + Keys.onReturnPressed: root.accept() + Keys.onEscapePressed: root.reject() - StudioControls.ComboBox { - id: propertyType - - Layout.fillWidth: true - - property string initialType - readonly property bool changed: propertyType.initialType !== propertyType.currentText - - model: root.model.typesList() - actionIndicatorVisible: false - - onInitialTypeChanged: propertyType.currentIndex = propertyType.find(initialType) - } - - Spacer {} - - RowLayout { - spacing: StudioTheme.Values.sectionRowSpacing - - StudioControls.CheckBox { - id: forceChangeType - actionIndicatorVisible: false + validator: RegularExpressionValidator { + regularExpression: /^\w+$/ + } } Text { - text: qsTr("Force update values") + text: qsTr("Type") color: StudioTheme.Values.themeTextColor - Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter } - } - Spacer { - visible: warningBox.visible - implicitHeight: StudioTheme.Values.controlLabelGap + StudioControls.ComboBox { + id: typeComboBox + + property string initialType + + model: root.model.typesList() + actionIndicatorVisible: false + + onInitialTypeChanged: typeComboBox.currentIndex = typeComboBox.find(initialType) + } } Rectangle { id: warningBox - Layout.fillWidth: true - Layout.preferredHeight: warning.height - - visible: propertyType.initialType !== propertyType.currentText + visible: typeComboBox.initialType !== typeComboBox.currentText color: "transparent" clip: true border.color: StudioTheme.Values.themeWarning + width: parent.width + height: warning.height - RowLayout { + Row { id: warning - width: parent.width + padding: 5 + spacing: 5 HelperWidgets.IconLabel { icon: StudioTheme.Constants.warning_medium - Layout.leftMargin: 10 + anchors.verticalCenter: parent.verticalCenter } Text { - text: qsTr("Conversion from %1 to %2 may lead to irreversible data loss") - .arg(propertyType.initialType) - .arg(propertyType.currentText) + text: qsTr("Conversion from %1 to %2 may lead to data loss") + .arg(typeComboBox.initialType) + .arg(typeComboBox.currentText) + + width: warningBox.width - 20 color: StudioTheme.Values.themeTextColor wrapMode: Text.WordWrap - Layout.fillWidth: true - Layout.margins: 8 } } } - Spacer {} - - RowLayout { - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - spacing: StudioTheme.Values.sectionRowSpacing + Row { + height: 40 + spacing: 5 + anchors.right: parent.right HelperWidgets.Button { id: editButton - text: qsTr("Edit") + text: qsTr("Apply") + enabled: nameTextField.text !== "" + width: 70 + anchors.bottom: parent.bottom + onClicked: root.accept() } HelperWidgets.Button { text: qsTr("Cancel") + anchors.bottom: parent.bottom + width: 70 + onClicked: root.reject() } } diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp index cd8296ca2de..e422adfbf02 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp @@ -258,7 +258,7 @@ bool CollectionDetails::setPropertyName(int column, const QString &value) return true; } -bool CollectionDetails::forcePropertyType(int column, DataType type, bool force) +bool CollectionDetails::setPropertyType(int column, DataType type) { if (!isValid() || !d->isValidColumnId(column)) return false; @@ -270,13 +270,11 @@ bool CollectionDetails::forcePropertyType(int column, DataType type, bool force) property.type = type; - if (force) { - for (QJsonObject &element : d->elements) { - if (element.contains(property.name)) { - QJsonValue value = element.value(property.name); - element.insert(property.name, valueToVariant(value, type).toJsonValue()); - changed = true; - } + for (QJsonObject &element : d->elements) { + if (element.contains(property.name)) { + QJsonValue value = element.value(property.name); + element.insert(property.name, valueToVariant(value, type).toJsonValue()); + changed = true; } } diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h index 33e5552884f..28e3b1bafe3 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h @@ -63,7 +63,7 @@ public: bool setPropertyValue(int row, int column, const QVariant &value); bool setPropertyName(int column, const QString &value); - bool forcePropertyType(int column, DataType type, bool force = false); + bool setPropertyType(int column, DataType type); CollectionReference reference() const; CollectionEditor::SourceFormat sourceFormat() const; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp index a39da321e92..87202979574 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp @@ -6,7 +6,6 @@ #include "collectioneditorconstants.h" #include "collectioneditorutils.h" #include "modelnode.h" -#include "variantproperty.h" #include @@ -325,20 +324,14 @@ bool CollectionDetailsModel::renameColumn(int section, const QString &newValue) return setHeaderData(section, Qt::Horizontal, newValue); } -bool CollectionDetailsModel::setPropertyType(int column, const QString &newValue, bool force) +bool CollectionDetailsModel::setPropertyType(int column, const QString &newValue) { - bool changed = m_currentCollection.forcePropertyType(column, - CollectionDataTypeHelper::typeFromString( - newValue), - force); + bool changed = m_currentCollection.setPropertyType(column, + CollectionDataTypeHelper::typeFromString( + newValue)); if (changed) { emit headerDataChanged(Qt::Horizontal, column, column); - - if (force) { - emit dataChanged(index(0, column), - index(rowCount() - 1, column), - {Qt::DisplayRole, DataTypeRole}); - } + emit dataChanged(index(0, column), index(rowCount() - 1, column), {Qt::DisplayRole, DataTypeRole}); } return changed; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h index eca3c697200..99611e0c9b0 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h @@ -55,7 +55,7 @@ public: Q_INVOKABLE bool addColumn(int column, const QString &name, const QString &propertyType = {}); Q_INVOKABLE bool selectColumn(int section); Q_INVOKABLE bool renameColumn(int section, const QString &newValue); - Q_INVOKABLE bool setPropertyType(int column, const QString &newValue, bool force = false); + Q_INVOKABLE bool setPropertyType(int column, const QString &newValue); Q_INVOKABLE bool selectRow(int row); Q_INVOKABLE void deselectAll(); From 268fa9fe65015a51cc2ed08f957349de3ce06f13 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Thu, 7 Dec 2023 18:16:19 +0200 Subject: [PATCH 080/101] EffectMaker: Show current composition name Fixes: QDS-11442 Change-Id: I047040e42fd60c00abe2be7e2210fc8bb53678cb Reviewed-by: Reviewed-by: Miikka Heikkinen Reviewed-by: Amr Elsayed Reviewed-by: Qt CI Patch Build Bot --- .../effectMakerQmlSources/EffectMakerTopBar.qml | 8 ++++++++ src/plugins/effectmakernew/effectmakermodel.cpp | 1 + 2 files changed, 9 insertions(+) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml index c8758ff2ebb..1ae879994bd 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml @@ -26,6 +26,14 @@ Rectangle { onClicked: root.saveClicked() } + Text { + readonly property string compName: EffectMakerBackend.effectMakerModel.currentComposition + + text: compName !== "" ? compName : qsTr("Untitled") + anchors.centerIn: parent + color: StudioTheme.Values.themeTextColor + } + HelperWidgets.AbstractButton { anchors.verticalCenter: parent.verticalCenter anchors.rightMargin: 5 diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index f71fa1d75f5..d459a02845f 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -150,6 +150,7 @@ void EffectMakerModel::clear() qDeleteAll(m_nodes); m_nodes.clear(); endResetModel(); + setCurrentComposition(""); setIsEmpty(true); emit nodesChanged(); From 034f48070cf8b23919384b7e74f3dda00258b9ca Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Thu, 7 Dec 2023 18:32:55 +0200 Subject: [PATCH 081/101] QmlDesigner: Allow `qDebug() <<` an Import Handy for debugging Change-Id: I524dab8895dc7c9ae2ae9fa820c4a57a6072e1ab Reviewed-by: Miikka Heikkinen --- src/plugins/qmldesigner/designercore/include/import.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/qmldesigner/designercore/include/import.h b/src/plugins/qmldesigner/designercore/include/import.h index 741c5ae54da..cde683a105d 100644 --- a/src/plugins/qmldesigner/designercore/include/import.h +++ b/src/plugins/qmldesigner/designercore/include/import.h @@ -5,9 +5,10 @@ #include +#include +#include #include #include -#include #include "qmldesignercorelib_global.h" @@ -91,6 +92,12 @@ public: return std::tie(first.m_url, first.m_type) < std::tie(second.m_url, second.m_type); } + friend QDebug operator<<(QDebug debug, const Import &import) + { + debug << import.toString(); + return debug; + } + private: Import(const QString &url, const QString &version, From 5f26d1e4eb5096867137e76bf31fb7b5152a73be Mon Sep 17 00:00:00 2001 From: Shrief Gabr Date: Tue, 5 Dec 2023 18:56:24 +0200 Subject: [PATCH 082/101] QmlDesigner: Remove datatype names from column Task-number: QDS-11460 Change-Id: I9501db735a5b0b4eb54740b8a4d3e20287aa4207 Reviewed-by: Mahmoud Badri --- .../collectionEditorQmlSource/CollectionDetailsView.qml | 5 +++++ .../collectioneditor/collectiondetailsmodel.cpp | 9 ++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml index 4585fa49d1d..d2c7f17ca33 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml @@ -128,6 +128,11 @@ Rectangle { } } } + + HelperWidgets.ToolTipArea { + anchors.fill: parent + text: root.model.propertyType(index) + } } StudioControls.Menu { diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp index 87202979574..2946a26ea2a 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp @@ -223,15 +223,10 @@ Qt::ItemFlags CollectionDetailsModel::flags(const QModelIndex &index) const QVariant CollectionDetailsModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal) { - if (role == DataTypeRole) { + if (role == DataTypeRole) return CollectionDataTypeHelper::typeToString(m_currentCollection.typeAt(section)); - } else if (role == Qt::DisplayRole) { - return QString("%1 <%2>").arg(m_currentCollection.propertyAt(section), - CollectionDataTypeHelper::typeToString( - m_currentCollection.typeAt(section))); - } else { + else return m_currentCollection.propertyAt(section); - } } if (orientation == Qt::Vertical) From f03b1cd53b5d5e9ab2d4d86ed2b8104c1ea707e5 Mon Sep 17 00:00:00 2001 From: Mats Honkamaa Date: Wed, 18 Oct 2023 15:31:42 +0300 Subject: [PATCH 083/101] Doc: Clarify previewing on device instructions Task-number: QDS-10228 Change-Id: Ic5fd9abd26e996e3201ca5fac062e6d593e8609f Reviewed-by: Tanja Remes Reviewed-by: Leena Miettinen Reviewed-by: Qt CI Patch Build Bot --- .../qtquick/qtquick-live-preview-devices.qdoc | 15 +++++++++++---- .../images/design-studio-kit-selection.webp | Bin 0 -> 8530 bytes .../images/design-studio-select-kit.webp | Bin 0 -> 4522 bytes 3 files changed, 11 insertions(+), 4 deletions(-) create mode 100644 doc/qtdesignstudio/images/design-studio-kit-selection.webp create mode 100644 doc/qtdesignstudio/images/design-studio-select-kit.webp diff --git a/doc/qtcreator/src/qtquick/qtquick-live-preview-devices.qdoc b/doc/qtcreator/src/qtquick/qtquick-live-preview-devices.qdoc index 8e527264d5d..f84285718f0 100644 --- a/doc/qtcreator/src/qtquick/qtquick-live-preview-devices.qdoc +++ b/doc/qtcreator/src/qtquick/qtquick-live-preview-devices.qdoc @@ -23,17 +23,24 @@ necessary files to a location in a device where you want to run the executable at. + \note To preview on a wirelessly connected device, select \preferences > \uicontrol Devices + and connect the device. + To preview a UI on a device: \list 1 + \if defined(qtcreator) \li In \uicontrol Projects > \uicontrol {Build & Run}, enable the kit predefined for the device type (1). \li Select the kit for the device in the kit selector (2). - \if defined(qtcreator) \image qtcreator-live-preview-kit.png - \else - \image studio-kit-selector.png "Kit selector" - \endif + \else + \li In the bottom toolbar, select \inlineimage icons/settings.png + and enable the kit predefined for the device type. + \image design-studio-kit-selection.webp. + \li Select the kit for the device in the bottom toolbar. + \image design-studio-select-kit.webp + \endif \li Select \uicontrol Build > \uicontrol {QML Preview} or press \key {Alt+P}. \endlist diff --git a/doc/qtdesignstudio/images/design-studio-kit-selection.webp b/doc/qtdesignstudio/images/design-studio-kit-selection.webp new file mode 100644 index 0000000000000000000000000000000000000000..b38c85fb7924d250c218f15d38e5ece977ca6aaf GIT binary patch literal 8530 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 PQffG(00SFC0EiC&qy}xE literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/images/design-studio-select-kit.webp b/doc/qtdesignstudio/images/design-studio-select-kit.webp new file mode 100644 index 0000000000000000000000000000000000000000..16c4146cc1f6cc8a2aa3bcb0d5711771a87c0b8b GIT binary patch literal 4522 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 I7y>|i0KhE7iU0rr literal 0 HcmV?d00001 From 19a81c13dff8adc038bb926dca0d9e4aad16ac6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Jen=C3=9Fen?= Date: Fri, 8 Dec 2023 11:24:25 +0100 Subject: [PATCH 084/101] ADS: compile fix against Qt 6.2.x MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Iad2b44dd056dbd37ba47133dd972e8bfbf11f7cc Reviewed-by: Henning Gründl Reviewed-by: Qt CI Patch Build Bot --- src/libs/advanceddockingsystem/dockwidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libs/advanceddockingsystem/dockwidget.cpp b/src/libs/advanceddockingsystem/dockwidget.cpp index f216ac7495e..a46fae58bef 100644 --- a/src/libs/advanceddockingsystem/dockwidget.cpp +++ b/src/libs/advanceddockingsystem/dockwidget.cpp @@ -485,7 +485,7 @@ void DockWidget::setFocused(bool focused) if (d->m_scrollArea) d->m_scrollArea->setProperty("focused", focused); - QList scrollAreas = d->m_widget->findChildren( + QList scrollAreas = d->m_widget->findChildren(QString(), Qt::FindDirectChildrenOnly); for (QAbstractScrollArea *scrollArea : scrollAreas) scrollArea->setProperty("focused", focused); From 4ab995da59cbd64d340934f6efd868f56ffe83dd Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Fri, 8 Dec 2023 12:04:12 +0200 Subject: [PATCH 085/101] EffectMaker: Update changed effect to 2D/property views The effect directory will be rescanned to update the types, and the puppet is reset if updated types are in use in the current document. If updated effect was also selected, selection is refreshed to update property view. Fixes: QDS-11367 Change-Id: I79cf476d8a70295f79525b6e1a5eeda27bb0b637 Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Patch Build Bot --- .../effectmakernew/effectmakermodel.cpp | 2 + src/plugins/effectmakernew/effectmakermodel.h | 1 + .../effectmakernew/effectmakerwidget.cpp | 85 ++++++++++++++++++- .../effectmakernew/effectmakerwidget.h | 16 ++++ 4 files changed, 103 insertions(+), 1 deletion(-) diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index d459a02845f..45efcb8c3ff 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -720,6 +720,8 @@ void EffectMakerModel::exportResources(const QString &name) if (!source.copyFile(target)) qWarning() << __FUNCTION__ << " Failed to copy file: " << source; } + + emit resourcesExported(QString("Effects.%1.%1").arg(name).toUtf8(), effectPath); } void EffectMakerModel::resetEffectError(int type) diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h index 1f4284b0813..02e46ce2cd7 100644 --- a/src/plugins/effectmakernew/effectmakermodel.h +++ b/src/plugins/effectmakernew/effectmakermodel.h @@ -100,6 +100,7 @@ signals: void currentCompositionChanged(); void nodesChanged(); + void resourcesExported(const QByteArray &type, const Utils::FilePath &path); private: enum Roles { diff --git a/src/plugins/effectmakernew/effectmakerwidget.cpp b/src/plugins/effectmakernew/effectmakerwidget.cpp index e11b4015a10..ceb8017ce43 100644 --- a/src/plugins/effectmakernew/effectmakerwidget.cpp +++ b/src/plugins/effectmakernew/effectmakerwidget.cpp @@ -17,16 +17,21 @@ #include +#include #include #include #include +#include + #include +#include #include #include #include #include +#include namespace EffectMaker { @@ -77,9 +82,27 @@ EffectMakerWidget::EffectMakerWidget(EffectMakerView *view) QmlDesigner::QmlDesignerPlugin::trackWidgetFocusTime( this, QmlDesigner::Constants::EVENT_NEWEFFECTMAKER_TIME); - connect(m_effectMakerModel.data(), &EffectMakerModel::nodesChanged, [this]() { + connect(m_effectMakerModel.data(), &EffectMakerModel::nodesChanged, this, [this]() { m_effectMakerNodesModel->updateCanBeAdded(m_effectMakerModel->uniformNames()); }); + + connect(m_effectMakerModel.data(), &EffectMakerModel::resourcesExported, + this, [this](const QmlDesigner::TypeName &type, const Utils::FilePath &path) { + if (!m_importScan.timer) { + m_importScan.timer = new QTimer(this); + connect(m_importScan.timer, &QTimer::timeout, + this, &EffectMakerWidget::handleImportScanTimer); + } + + if (m_importScan.timer->isActive() && !m_importScan.future.isFinished()) + m_importScan.future.cancel(); + + m_importScan.counter = 0; + m_importScan.type = type; + m_importScan.path = path; + + m_importScan.timer->start(100); + }); } @@ -177,5 +200,65 @@ void EffectMakerWidget::reloadQmlSource() m_quickWidget->setSource(QUrl::fromLocalFile(effectMakerQmlPath)); } +void EffectMakerWidget::handleImportScanTimer() +{ + ++m_importScan.counter; + + if (m_importScan.counter == 1) { + // Rescan the effect import to update code model + auto modelManager = QmlJS::ModelManagerInterface::instance(); + if (modelManager) { + QmlJS::PathsAndLanguages pathToScan; + pathToScan.maybeInsert(m_importScan.path); + m_importScan.future = ::Utils::asyncRun(&QmlJS::ModelManagerInterface::importScan, + modelManager->workingCopy(), + pathToScan, modelManager, true, true, true); + } + } else if (m_importScan.counter < 100) { + // We have to wait a while to ensure qmljs detects new files and updates its + // internal model. Then we force amend on rewriter to trigger qmljs snapshot update. + if (m_importScan.future.isCanceled() || m_importScan.future.isFinished()) + m_importScan.counter = 100; // skip the timeout step + } else if (m_importScan.counter == 100) { + // Scanning is taking too long, abort + m_importScan.future.cancel(); + m_importScan.timer->stop(); + m_importScan.counter = 0; + } else if (m_importScan.counter == 101) { + if (m_effectMakerView->model() && m_effectMakerView->model()->rewriterView()) { + QmlDesigner::QmlDesignerPlugin::instance()->documentManager().resetPossibleImports(); + m_effectMakerView->model()->rewriterView()->forceAmend(); + } + } else if (m_importScan.counter == 102) { + if (m_effectMakerView->model()) { + // If type is in use, we have to reset puppet to update 2D view + if (!m_effectMakerView->allModelNodesOfType( + m_effectMakerView->model()->metaInfo(m_importScan.type)).isEmpty()) { + m_effectMakerView->resetPuppet(); + } + } + } else if (m_importScan.counter >= 103) { + // Refresh property view by resetting selection if any selected node is of updated type + if (m_effectMakerView->model() && m_effectMakerView->hasSelectedModelNodes()) { + const auto nodes = m_effectMakerView->selectedModelNodes(); + QmlDesigner::MetaInfoType metaType + = m_effectMakerView->model()->metaInfo(m_importScan.type).type(); + bool match = false; + for (const QmlDesigner::ModelNode &node : nodes) { + if (node.metaInfo().type() == metaType) { + match = true; + break; + } + } + if (match) { + m_effectMakerView->clearSelectedModelNodes(); + m_effectMakerView->setSelectedModelNodes(nodes); + } + } + m_importScan.timer->stop(); + m_importScan.counter = 0; + } +} + } // namespace EffectMaker diff --git a/src/plugins/effectmakernew/effectmakerwidget.h b/src/plugins/effectmakernew/effectmakerwidget.h index 3c43d732e40..9204026a9c9 100644 --- a/src/plugins/effectmakernew/effectmakerwidget.h +++ b/src/plugins/effectmakernew/effectmakerwidget.h @@ -9,9 +9,14 @@ #include #include +#include class StudioQuickWidget; +QT_BEGIN_NAMESPACE +class QTimer; +QT_END_NAMESPACE + namespace EffectMaker { class EffectMakerView; @@ -51,6 +56,7 @@ protected: private: void reloadQmlSource(); + void handleImportScanTimer(); QPointer m_effectMakerModel; QPointer m_effectMakerNodesModel; @@ -58,6 +64,16 @@ private: QPointer m_quickWidget; QmlDesigner::QmlModelNodeProxy m_backendModelNode; QmlDesigner::QmlAnchorBindingProxy m_backendAnchorBinding; + + struct ImportScanData { + QFuture future; + int counter = 0; + QTimer *timer = nullptr; + QmlDesigner::TypeName type; + Utils::FilePath path; + }; + + ImportScanData m_importScan; }; } // namespace EffectMaker From cc07031cd6d06758bba401f99986d2a03832b119 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Fri, 8 Dec 2023 14:58:04 +0200 Subject: [PATCH 086/101] EffectMaker: Improve adding and saving compositions Add and implement 2 icons for adding and saving compositions. Fixes: QDS-11511 Change-Id: I113eeb81ea05fc6db9019d95d476bc0fe20b409f Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Miikka Heikkinen --- .../effectMakerQmlSources/EffectMaker.qml | 29 +++++++-- .../EffectMakerTopBar.qml | 20 +++++- .../{SaveDialog.qml => SaveAsDialog.qml} | 4 +- .../SaveChangesDialog.qml | 62 +++++++++++++++++++ .../effectmakernew/effectmakermodel.cpp | 40 ++++++++++-- src/plugins/effectmakernew/effectmakermodel.h | 13 ++-- .../effectmakernew/effectmakerwidget.cpp | 2 +- 7 files changed, 153 insertions(+), 17 deletions(-) rename share/qtcreator/qmldesigner/effectMakerQmlSources/{SaveDialog.qml => SaveAsDialog.qml} (96%) create mode 100644 share/qtcreator/qmldesigner/effectMakerQmlSources/SaveChangesDialog.qml diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index 3f962478e0b..07cfba3cf6d 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -16,24 +16,45 @@ Item { property int moveToIdx: 0 property bool previewAnimationRunning: false - SaveDialog { + SaveAsDialog { id: saveDialog compositionName: EffectMakerBackend.effectMakerModel.currentComposition anchors.centerIn: parent + onAccepted: { let name = saveDialog.compositionName - EffectMakerBackend.effectMakerModel.exportComposition(name) - EffectMakerBackend.effectMakerModel.exportResources(name) + EffectMakerBackend.effectMakerModel.saveComposition(name) } } + SaveChangesDialog { + id: saveChangesDialog + anchors.centerIn: parent + + onAccepted: EffectMakerBackend.effectMakerModel.clear() + } + Column { id: col anchors.fill: parent spacing: 1 EffectMakerTopBar { - onSaveClicked: saveDialog.open() + onAddClicked: { + if (EffectMakerBackend.effectMakerModel.hasUnsavedChanges) + saveChangesDialog.open() + else + EffectMakerBackend.effectMakerModel.clear() + } + + onSaveClicked: { + let name = EffectMakerBackend.effectMakerModel.currentComposition + + if (name === "") + saveDialog.open() + else + EffectMakerBackend.effectMakerModel.saveComposition(name) + } } EffectMakerPreview { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml index 1ae879994bd..2c7ff15cd5e 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml @@ -15,13 +15,29 @@ Rectangle { height: StudioTheme.Values.toolbarHeight color: StudioTheme.Values.themeToolbarBackground + signal addClicked signal saveClicked - HelperWidgets.Button { + HelperWidgets.AbstractButton { + id: addButton + anchors.verticalCenter: parent.verticalCenter x: 5 + style: StudioTheme.Values.viewBarButtonStyle + buttonIcon: StudioTheme.Constants.add_medium + tooltip: qsTr("Add new composition") - text: qsTr("Save in Library") + onClicked: root.addClicked() + } + + HelperWidgets.AbstractButton { + anchors.verticalCenter: parent.verticalCenter + x: addButton.x + addButton.width + 5 + style: StudioTheme.Values.viewBarButtonStyle + buttonIcon: StudioTheme.Constants.save_medium + tooltip: qsTr("Save current composition") + enabled: EffectMakerBackend.effectMakerModel.hasUnsavedChanges + || EffectMakerBackend.effectMakerModel.currentComposition === "" onClicked: root.saveClicked() } diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveDialog.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml similarity index 96% rename from share/qtcreator/qmldesigner/effectMakerQmlSources/SaveDialog.qml rename to share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml index 60ddae35452..bf136210aa6 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveDialog.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml @@ -6,7 +6,7 @@ import QtQuick.Controls import HelperWidgets as HelperWidgets import StudioControls as StudioControls import StudioTheme as StudioTheme -import AssetsLibraryBackend +import EffectMakerBackend StudioControls.Dialog { id: root @@ -21,7 +21,7 @@ StudioControls.Dialog { property string compositionName: "" onOpened: { - nameText.text = compositionName //TODO: Generate unique name + nameText.text = EffectMakerBackend.effectMakerModel.currentComposition emptyText.text = "" nameText.forceActiveFocus() } diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveChangesDialog.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveChangesDialog.qml new file mode 100644 index 00000000000..2552cb79102 --- /dev/null +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveChangesDialog.qml @@ -0,0 +1,62 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick.Controls +import HelperWidgets as HelperWidgets +import StudioControls as StudioControls +import StudioTheme as StudioTheme +import EffectMakerBackend + +StudioControls.Dialog { + id: root + + title: qsTr("Save Changes") + + closePolicy: Popup.CloseOnEscape + modal: true + implicitWidth: 250 + implicitHeight: 140 + + contentItem: Column { + spacing: 35 + + Text { + text: qsTr("Current composition has unsaved changes.") + color: StudioTheme.Values.themeTextColor + } + + Row { + anchors.right: parent.right + spacing: 2 + + HelperWidgets.Button { + id: btnSave + + width: 70 + text: qsTr("Save") + onClicked: { + if (btnSave.enabled) { + let name = EffectMakerBackend.effectMakerModel.currentComposition + EffectMakerBackend.effectMakerModel.saveComposition(name) + root.accept() + } + } + } + + HelperWidgets.Button { + id: btnDontSave + + width: 70 + text: qsTr("Don't Save") + onClicked: root.accept() + } + + HelperWidgets.Button { + width: 70 + text: qsTr("Cancel") + onClicked: root.reject() + } + } + } +} diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index 45efcb8c3ff..fa9d2d31c2f 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -106,12 +106,17 @@ void EffectMakerModel::addNode(const QString &nodeQenPath) { beginInsertRows({}, m_nodes.size(), m_nodes.size()); auto *node = new CompositionNode("", nodeQenPath); + connect(qobject_cast(node->uniformsModel()), + &EffectMakerUniformsModel::dataChanged, this, [this] { + setHasUnsavedChanges(true); + }); m_nodes.append(node); endInsertRows(); setIsEmpty(false); bakeShaders(); + setHasUnsavedChanges(true); emit nodesChanged(); } @@ -126,6 +131,7 @@ void EffectMakerModel::moveNode(int fromIdx, int toIdx) m_nodes.move(fromIdx, toIdx); endMoveRows(); + setHasUnsavedChanges(true); bakeShaders(); } @@ -141,6 +147,7 @@ void EffectMakerModel::removeNode(int idx) else bakeShaders(); + setHasUnsavedChanges(true); emit nodesChanged(); } @@ -150,6 +157,7 @@ void EffectMakerModel::clear() qDeleteAll(m_nodes); m_nodes.clear(); endResetModel(); + setHasUnsavedChanges(!m_currentComposition.isEmpty()); setCurrentComposition(""); setIsEmpty(true); @@ -528,7 +536,7 @@ QString EffectMakerModel::getQmlEffectString() return s; } -void EffectMakerModel::exportComposition(const QString &name) +void EffectMakerModel::saveComposition(const QString &name) { const QString effectsAssetsDir = QmlDesigner::ModelNodeOperations::getEffectsDefaultDirectory(); const QString path = effectsAssetsDir + QDir::separator() + name + ".qep"; @@ -559,6 +567,10 @@ void EffectMakerModel::exportComposition(const QString &name) saveFile.write(jsonDoc.toJson()); saveFile.close(); + setCurrentComposition(name); + setHasUnsavedChanges(false); + + saveResources(name); } void EffectMakerModel::openComposition(const QString &path) @@ -615,6 +627,10 @@ void EffectMakerModel::openComposition(const QString &path) for (const auto &nodeElement : nodesArray) { beginInsertRows({}, m_nodes.size(), m_nodes.size()); auto *node = new CompositionNode(effectName, "", nodeElement.toObject()); + connect(qobject_cast(node->uniformsModel()), + &EffectMakerUniformsModel::dataChanged, this, [this] { + setHasUnsavedChanges(true); + }); m_nodes.append(node); endInsertRows(); } @@ -623,10 +639,11 @@ void EffectMakerModel::openComposition(const QString &path) bakeShaders(); } + setHasUnsavedChanges(false); emit nodesChanged(); } -void EffectMakerModel::exportResources(const QString &name) +void EffectMakerModel::saveResources(const QString &name) { // Make sure that uniforms are up-to-date updateCustomUniforms(); @@ -692,7 +709,7 @@ void EffectMakerModel::exportResources(const QString &name) QString qmlFilePath = effectsResPath + qmlFilename; writeToFile(qmlString.toUtf8(), qmlFilePath, FileType::Text); - // Export shaders and images + // Save shaders and images QStringList sources = {m_vertexShaderFilename, m_fragmentShaderFilename}; QStringList dests = {vsFilename, fsFilename}; @@ -721,7 +738,7 @@ void EffectMakerModel::exportResources(const QString &name) qWarning() << __FUNCTION__ << " Failed to copy file: " << source; } - emit resourcesExported(QString("Effects.%1.%1").arg(name).toUtf8(), effectPath); + emit resourcesSaved(QString("Effects.%1.%1").arg(name).toUtf8(), effectPath); } void EffectMakerModel::resetEffectError(int type) @@ -1440,10 +1457,25 @@ void EffectMakerModel::setCurrentComposition(const QString &newCurrentCompositio { if (m_currentComposition == newCurrentComposition) return; + m_currentComposition = newCurrentComposition; emit currentCompositionChanged(); } +bool EffectMakerModel::hasUnsavedChanges() const +{ + return m_hasUnsavedChanges; +} + +void EffectMakerModel::setHasUnsavedChanges(bool val) +{ + if (m_hasUnsavedChanges == val) + return; + + m_hasUnsavedChanges = val; + emit hasUnsavedChangesChanged(); +} + QStringList EffectMakerModel::uniformNames() const { QStringList usedList; diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h index 02e46ce2cd7..c06a1d5749b 100644 --- a/src/plugins/effectmakernew/effectmakermodel.h +++ b/src/plugins/effectmakernew/effectmakermodel.h @@ -44,6 +44,7 @@ class EffectMakerModel : public QAbstractListModel Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged) Q_PROPERTY(int selectedIndex MEMBER m_selectedIndex NOTIFY selectedIndexChanged) + Q_PROPERTY(bool hasUnsavedChanges MEMBER m_hasUnsavedChanges WRITE setHasUnsavedChanges NOTIFY hasUnsavedChangesChanged) Q_PROPERTY(bool shadersUpToDate READ shadersUpToDate WRITE setShadersUpToDate NOTIFY shadersUpToDateChanged) Q_PROPERTY(QString qmlComponentString READ qmlComponentString) Q_PROPERTY(QString currentComposition READ currentComposition WRITE setCurrentComposition NOTIFY currentCompositionChanged) @@ -81,14 +82,16 @@ public: Q_INVOKABLE void resetEffectError(int type); Q_INVOKABLE void setEffectError(const QString &errorMessage, int type = -1, int lineNumber = -1); - Q_INVOKABLE void exportComposition(const QString &name); - Q_INVOKABLE void exportResources(const QString &name); + Q_INVOKABLE void saveComposition(const QString &name); void openComposition(const QString &path); QString currentComposition() const; void setCurrentComposition(const QString &newCurrentComposition); + bool hasUnsavedChanges() const; + void setHasUnsavedChanges(bool val); + QStringList uniformNames() const; signals: @@ -97,10 +100,10 @@ signals: void effectErrorChanged(); void shadersUpToDateChanged(); void shadersBaked(); - void currentCompositionChanged(); void nodesChanged(); - void resourcesExported(const QByteArray &type, const Utils::FilePath &path); + void resourcesSaved(const QByteArray &type, const Utils::FilePath &path); + void hasUnsavedChangesChanged(); private: enum Roles { @@ -152,6 +155,7 @@ private: void updateCustomUniforms(); void createFiles(); void bakeShaders(); + void saveResources(const QString &name); QString mipmapPropertyName(const QString &name) const; QString getQmlImagesString(bool localFiles); @@ -161,6 +165,7 @@ private: int m_selectedIndex = -1; bool m_isEmpty = true; + bool m_hasUnsavedChanges = false; // True when shaders haven't changed since last baking bool m_shadersUpToDate = true; int m_remainingQsbTargets = 0; diff --git a/src/plugins/effectmakernew/effectmakerwidget.cpp b/src/plugins/effectmakernew/effectmakerwidget.cpp index ceb8017ce43..877d0e2d523 100644 --- a/src/plugins/effectmakernew/effectmakerwidget.cpp +++ b/src/plugins/effectmakernew/effectmakerwidget.cpp @@ -86,7 +86,7 @@ EffectMakerWidget::EffectMakerWidget(EffectMakerView *view) m_effectMakerNodesModel->updateCanBeAdded(m_effectMakerModel->uniformNames()); }); - connect(m_effectMakerModel.data(), &EffectMakerModel::resourcesExported, + connect(m_effectMakerModel.data(), &EffectMakerModel::resourcesSaved, this, [this](const QmlDesigner::TypeName &type, const Utils::FilePath &path) { if (!m_importScan.timer) { m_importScan.timer = new QTimer(this); From fba2fda7881966a4359589037229a4e5578d1778 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Mon, 11 Dec 2023 15:54:35 +0200 Subject: [PATCH 087/101] EffectMaker: improve save changes dialog - move cancel button to the left - rename don't save to discard changes - update buttons sizes to match their content - remove few useless parts and reorganize the layout Change-Id: I08308a90082b0c73ff9a6bf34b255764e07f20df Reviewed-by: Miikka Heikkinen --- .../SaveChangesDialog.qml | 40 ++++++++----------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveChangesDialog.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveChangesDialog.qml index 2552cb79102..e119d15f348 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveChangesDialog.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveChangesDialog.qml @@ -15,48 +15,42 @@ StudioControls.Dialog { closePolicy: Popup.CloseOnEscape modal: true - implicitWidth: 250 - implicitHeight: 140 - - contentItem: Column { - spacing: 35 + implicitWidth: 300 + implicitHeight: 130 + contentItem: Item { Text { text: qsTr("Current composition has unsaved changes.") color: StudioTheme.Values.themeTextColor } + HelperWidgets.Button { + width: 60 + anchors.bottom: parent.bottom + text: qsTr("Cancel") + onClicked: root.reject() + } + Row { anchors.right: parent.right + anchors.bottom: parent.bottom spacing: 2 HelperWidgets.Button { - id: btnSave - - width: 70 + width: 50 text: qsTr("Save") onClicked: { - if (btnSave.enabled) { - let name = EffectMakerBackend.effectMakerModel.currentComposition - EffectMakerBackend.effectMakerModel.saveComposition(name) - root.accept() - } + let name = EffectMakerBackend.effectMakerModel.currentComposition + EffectMakerBackend.effectMakerModel.saveComposition(name) + root.accept() } } HelperWidgets.Button { - id: btnDontSave - - width: 70 - text: qsTr("Don't Save") + width: 110 + text: qsTr("Discard Changes") onClicked: root.accept() } - - HelperWidgets.Button { - width: 70 - text: qsTr("Cancel") - onClicked: root.reject() - } } } } From 8f51c7a75d1c153a3c9214c112a552fc3f41e715 Mon Sep 17 00:00:00 2001 From: Shrief Gabr Date: Wed, 29 Nov 2023 12:58:13 +0200 Subject: [PATCH 088/101] QmlDesigner: Modify model export functions Task-number: QDS-11298 Change-Id: I919c8cd4ecac4bad7dab4d4fdf2d1cf3548cd95b Reviewed-by: Ali Kianian Reviewed-by: Mahmoud Badri --- .../CollectionDetailsToolbar.qml | 3 +- .../collectioneditor/collectiondetails.cpp | 10 +- .../collectioneditor/collectiondetails.h | 4 +- .../collectiondetailsmodel.cpp | 102 ++++++------------ .../collectioneditor/collectiondetailsmodel.h | 10 +- 5 files changed, 45 insertions(+), 84 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml index 78a8152a762..3e268d10f48 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsToolbar.qml @@ -128,8 +128,7 @@ Item { onAccepted: { let filePath = fileDialog.file.toString() - let exportType = fileDialog.selectedNameFilter.index === 0 ? "JSON" : "CSV" - root.model.exportCollection(filePath, root.model.collectionName, exportType) + root.model.exportCollection(filePath) } } diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp index e422adfbf02..e0bc86f99f6 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -436,16 +437,19 @@ void CollectionDetails::resetPropertyTypes() resetPropertyType(property); } -QJsonArray CollectionDetails::getJsonCollection() const +QString CollectionDetails::getCollectionAsJsonString() const { QJsonArray collectionArray; + for (const QJsonObject &element : std::as_const(d->elements)) collectionArray.push_back(element); - return collectionArray; + QString collectionString = QString::fromUtf8(QJsonDocument(collectionArray).toJson()); + + return collectionString; } -QString CollectionDetails::getCsvCollection() const +QString CollectionDetails::getCollectionAsCsvString() const { QString content; if (d->properties.count() <= 0) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h index 28e3b1bafe3..694947b126a 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h @@ -82,8 +82,8 @@ public: bool markSaved(); void swap(CollectionDetails &other); - QJsonArray getJsonCollection() const; - QString getCsvCollection() const; + QString getCollectionAsJsonString() const; + QString getCollectionAsCsvString() const; static void registerDeclarativeType(); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp index 2946a26ea2a..49398b2aea2 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp @@ -396,34 +396,14 @@ void CollectionDetailsModel::loadCollection(const ModelNode &sourceNode, const Q } } -bool CollectionDetailsModel::exportCollection(const QUrl &url, - const QString &collectionName, - const QString &exportType) -{ - QString filePath; - if (url.isLocalFile()) { - QFileInfo fileInfo(url.toLocalFile()); - if (fileInfo.suffix().toLower() != exportType.toLower()) - fileInfo.setFile(QString("%1.%2").arg(url.toLocalFile(), exportType.toLower())); - filePath = fileInfo.absoluteFilePath(); - } else { - filePath = url.toString(); - } - - if (exportType == "JSON") { - QJsonArray content = m_currentCollection.getJsonCollection(); - return saveCollectionAsJson(filePath, content, collectionName); - } else if (exportType == "CSV") { - QString content = m_currentCollection.getCsvCollection(); - return saveCollectionAsCsv(filePath, content); - } - - return false; -} - bool CollectionDetailsModel::saveCurrentCollection() { - return saveCollection(m_currentCollection); + return saveCollection({}, &m_currentCollection); +} + +bool CollectionDetailsModel::exportCollection(const QString &filePath) +{ + return saveCollection(filePath, &m_currentCollection); } void CollectionDetailsModel::updateEmpty() @@ -600,58 +580,40 @@ void CollectionDetailsModel::setCollectionName(const QString &newCollectionName) } } -bool CollectionDetailsModel::saveCollection(CollectionDetails &collection) +bool CollectionDetailsModel::saveCollection(const QString &filePath, CollectionDetails *collection) { - if (!collection.isValid() || !m_openedCollections.contains(collection.reference())) - return false; - - const ModelNode node = collection.reference().node; bool saved = false; - if (CollectionEditor::getSourceCollectionType(node) == "json") { - saved = saveCollectionAsJson(CollectionEditor::getSourceCollectionPath(node), - collection.getJsonCollection(), - collection.reference().name); - } else if (CollectionEditor::getSourceCollectionType(node) == "csv") { - saved = saveCollectionAsCsv(CollectionEditor::getSourceCollectionPath(node), - collection.getCsvCollection()); + auto saveSingleCollection = [&](CollectionDetails &singleCollection) { + + const ModelNode node = singleCollection.reference().node; + QString path = CollectionEditor::getSourceCollectionPath(node); + QString saveFormat = CollectionEditor::getSourceCollectionType(node); + + if (!filePath.isEmpty()) { + QUrl url(filePath); + path = url.isLocalFile() ? QFileInfo(url.toLocalFile()).absoluteFilePath() : url.toString(); + saveFormat = url.isLocalFile() ? QFileInfo(url.toLocalFile()).suffix().toLower() : saveFormat; + } + + saved = saveCollectionFromString(path, (saveFormat == "json") ? singleCollection.getCollectionAsJsonString() : + (saveFormat == "csv") ? singleCollection.getCollectionAsCsvString() : QString()); + + if (saved && filePath.isEmpty()) + singleCollection.markSaved(); + }; + + if (!collection) { + for (CollectionDetails &openedCollection : m_openedCollections) + saveSingleCollection(openedCollection); + } else { + saveSingleCollection(*collection); } - if (saved) - collection.markSaved(); return saved; } -bool CollectionDetailsModel::saveCollectionAsJson(const QString &path, const QJsonArray &content, const QString &collectionName) -{ - QFile sourceFile(path); - QJsonDocument document; - - if (sourceFile.exists() && sourceFile.open(QFile::ReadWrite)) { - QJsonParseError jpe; - document = QJsonDocument::fromJson(sourceFile.readAll(), &jpe); - - if (jpe.error == QJsonParseError::NoError) { - QJsonObject collectionMap = document.object(); - collectionMap[collectionName] = content; - document.setObject(collectionMap); - } - - sourceFile.resize(0); - - } else if (sourceFile.open(QFile::WriteOnly)) { - QJsonObject collection; - collection[collectionName] = content; - document.setObject(collection); - } - - if (sourceFile.write(document.toJson())) - return true; - - return false; -} - -bool CollectionDetailsModel::saveCollectionAsCsv(const QString &path, const QString &content) +bool CollectionDetailsModel::saveCollectionFromString(const QString &path, const QString &content) { QFile file(path); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h index 99611e0c9b0..78fab1685f9 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h @@ -63,11 +63,8 @@ public: void loadCollection(const ModelNode &sourceNode, const QString &collection); - Q_INVOKABLE bool exportCollection(const QUrl &url, - const QString &collectionName, - const QString &exportType); - Q_INVOKABLE bool saveCurrentCollection(); + Q_INVOKABLE bool exportCollection(const QString &filePath); signals: void collectionNameChanged(const QString &collectionName); @@ -85,9 +82,8 @@ private: void setCollectionName(const QString &newCollectionName); void loadJsonCollection(const QString &source, const QString &collection); void loadCsvCollection(const QString &source, const QString &collectionName); - bool saveCollection(CollectionDetails &collection); - bool saveCollectionAsJson(const QString &path, const QJsonArray &content, const QString &collectionName); - bool saveCollectionAsCsv(const QString &path, const QString &content); + bool saveCollection(const QString &filePath = {}, CollectionDetails *collection = nullptr); + bool saveCollectionFromString(const QString &path, const QString &content); QVariant variantFromString(const QString &value); QHash m_openedCollections; From 2af5ce7fa95120ab175141668d2b3af3771c469f Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Mon, 11 Dec 2023 16:48:34 +0200 Subject: [PATCH 089/101] EffectMaker: Generate unique effect name when saving Change-Id: Ib602b778d810fe0d6c0d70879b1002c1749fe196 Reviewed-by: Miikka Heikkinen --- .../effectMakerQmlSources/EffectMaker.qml | 6 +----- .../effectMakerQmlSources/SaveAsDialog.qml | 9 ++++----- src/plugins/effectmakernew/effectmakermodel.cpp | 13 +++++++++++++ src/plugins/effectmakernew/effectmakermodel.h | 1 + 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index 07cfba3cf6d..b19786b2ac7 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -18,13 +18,9 @@ Item { SaveAsDialog { id: saveDialog - compositionName: EffectMakerBackend.effectMakerModel.currentComposition anchors.centerIn: parent - onAccepted: { - let name = saveDialog.compositionName - EffectMakerBackend.effectMakerModel.saveComposition(name) - } + onAccepted: EffectMakerBackend.effectMakerModel.saveComposition(saveDialog.compositionName) } SaveChangesDialog { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml index bf136210aa6..fa83def976b 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml @@ -21,7 +21,8 @@ StudioControls.Dialog { property string compositionName: "" onOpened: { - nameText.text = EffectMakerBackend.effectMakerModel.currentComposition + let model = EffectMakerBackend.effectMakerModel + nameText.text = model.currentComposition === "" ? model.getUniqueEffectName() : model.currentComposition emptyText.text = "" nameText.forceActiveFocus() } @@ -83,10 +84,8 @@ StudioControls.Dialog { text: qsTr("Save") enabled: nameText.text !== "" onClicked: { - if (btnSave.enabled) { - root.compositionName = nameText.text - root.accept() //TODO: Check if name is unique - } + root.compositionName = nameText.text + root.accept() // TODO: confirm before overriding effect with same name } } diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index fa9d2d31c2f..54c556c555a 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -164,6 +164,19 @@ void EffectMakerModel::clear() emit nodesChanged(); } +QString EffectMakerModel::getUniqueEffectName() const +{ + const QString effectsDir = QmlDesigner::ModelNodeOperations::getEffectsDefaultDirectory(); + const QString path = effectsDir + QDir::separator() + "Effect%1.qep"; + + int num = 0; + + while (QFile::exists(path.arg(++num, 2, 10, QChar('0')))) + ; // empty body + + return QString("Effect%1").arg(num, 2, 10, QChar('0')); +} + QString EffectMakerModel::fragmentShader() const { return m_fragmentShader; diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h index c06a1d5749b..abcb367ad7a 100644 --- a/src/plugins/effectmakernew/effectmakermodel.h +++ b/src/plugins/effectmakernew/effectmakermodel.h @@ -65,6 +65,7 @@ public: Q_INVOKABLE void moveNode(int fromIdx, int toIdx); Q_INVOKABLE void removeNode(int idx); Q_INVOKABLE void clear(); + Q_INVOKABLE QString getUniqueEffectName() const; bool shadersUpToDate() const; void setShadersUpToDate(bool newShadersUpToDate); From e984536b6f778f48e2e881b37951616b80a49804 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Mon, 11 Dec 2023 19:04:56 +0200 Subject: [PATCH 090/101] QmlDesigner: Fix opening the new effect maker Change-Id: I23d278dfaa430df09cd31aa63e8034a7787bac7a Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Miikka Heikkinen --- .../assetslibrary/assetslibrarywidget.cpp | 25 +------------------ .../componentcore/modelnodeoperations.cpp | 24 ++++++++++++++++++ .../componentcore/modelnodeoperations.h | 2 ++ .../components/componentcore/viewmanager.cpp | 6 +++++ .../components/componentcore/viewmanager.h | 2 ++ 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index a785fea76f0..5c6ebf07c5d 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -8,25 +8,17 @@ #include "assetslibrarymodel.h" #include "assetslibraryview.h" #include "designeractionmanager.h" -#include "designmodewidget.h" #include "modelnodeoperations.h" #include "qmldesignerconstants.h" #include "qmldesignerplugin.h" #include "theme.h" -#include -#include - #include #include #include #include -#include -#include -#include - #include #include #include @@ -368,24 +360,9 @@ QSet AssetsLibraryWidget::supportedAssetSuffixes(bool complex) return suffixes; } -bool isEffectMakerActivated() -{ - const QVector specs = ExtensionSystem::PluginManager::plugins(); - return std::find_if(specs.begin(), specs.end(), - [](ExtensionSystem::PluginSpec *spec) { - return spec->name() == "EffectMakerNew" && spec->isEffectivelyEnabled(); - }) - != specs.end(); -} - void AssetsLibraryWidget::openEffectMaker(const QString &filePath) { - if (isEffectMakerActivated()) { // new effect maker - m_assetsView->emitCustomNotification("open_effectmaker_composition", {}, {filePath}); - QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("Effect Maker", true); - } else { // old effect maker - ModelNodeOperations::openEffectMaker(filePath); - } + ModelNodeOperations::openEffectMaker(filePath); } QString AssetsLibraryWidget::qmlSourcesPath() diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index ffa51710f6f..79ff364c403 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -43,6 +43,9 @@ #include #include +#include +#include + #include #include @@ -1620,7 +1623,28 @@ void updateImported3DAsset(const SelectionContext &selectionContext) } } +bool isNewEffectMakerActivated() +{ + const QVector specs = ExtensionSystem::PluginManager::plugins(); + return std::find_if(specs.begin(), specs.end(), + [](ExtensionSystem::PluginSpec *spec) { + return spec->name() == "EffectMakerNew" && spec->isEffectivelyEnabled(); + }) + != specs.end(); +} + void openEffectMaker(const QString &filePath) +{ + if (ModelNodeOperations::isNewEffectMakerActivated()) { + QmlDesignerPlugin::instance()->viewManager() + .emitCustomNotification("open_effectmaker_composition", {}, {filePath}); + QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("Effect Maker", true); + } else { + ModelNodeOperations::openOldEffectMaker(filePath); + } +} + +void openOldEffectMaker(const QString &filePath) { const ProjectExplorer::Target *target = ProjectExplorer::ProjectTree::currentTarget(); if (!target) { diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h index 7d7a985283a..c8042887e18 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -127,9 +127,11 @@ void updateImported3DAsset(const SelectionContext &selectionContext); QMLDESIGNERCOMPONENTS_EXPORT Utils::FilePath getEffectsImportDirectory(); QMLDESIGNERCOMPONENTS_EXPORT QString getEffectsDefaultDirectory(const QString &defaultDir = {}); void openEffectMaker(const QString &filePath); +void openOldEffectMaker(const QString &filePath); QString getEffectIcon(const QString &effectPath); bool useLayerEffect(); bool validateEffect(const QString &effectPath); +bool isNewEffectMakerActivated(); Utils::FilePath getImagesDefaultDirectory(); diff --git a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp index d26618dbdad..05d6f5fdf0c 100644 --- a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp @@ -458,6 +458,12 @@ const AbstractView *ViewManager::view() const return &d->nodeInstanceView; } +void ViewManager::emitCustomNotification(const QString &identifier, const QList &nodeList, + const QList &data) +{ + d->nodeInstanceView.emitCustomNotification(identifier, nodeList, data); +} + QWidgetAction *ViewManager::componentViewAction() const { return d->componentView.action(); diff --git a/src/plugins/qmldesigner/components/componentcore/viewmanager.h b/src/plugins/qmldesigner/components/componentcore/viewmanager.h index 935ff54cfdb..3cabf5109ec 100644 --- a/src/plugins/qmldesigner/components/componentcore/viewmanager.h +++ b/src/plugins/qmldesigner/components/componentcore/viewmanager.h @@ -72,6 +72,8 @@ public: void nextFileIsCalledInternally(); const AbstractView *view() const; + void emitCustomNotification(const QString &identifier, const QList &nodeList, + const QList &data); void exportAsImage(); QImage takeFormEditorScreenshot(); From 9d8aa76b4cb743bf3214893f4a2c8b32ddf26b3b Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Mon, 11 Dec 2023 17:36:03 +0200 Subject: [PATCH 091/101] EffectMaker: Show save popup when adding a new effect when there is an untitled effect composition in the effect maker. Change-Id: I3d905202e52b1242949d72f1870d4cc06efe080b Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Miikka Heikkinen --- .../effectMakerQmlSources/EffectMaker.qml | 16 ++++++++++++--- .../effectMakerQmlSources/SaveAsDialog.qml | 20 ++++++++++++++++--- .../SaveChangesDialog.qml | 13 ++++++++++-- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index b19786b2ac7..709380d8c31 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -19,15 +19,25 @@ Item { SaveAsDialog { id: saveDialog anchors.centerIn: parent - - onAccepted: EffectMakerBackend.effectMakerModel.saveComposition(saveDialog.compositionName) } SaveChangesDialog { id: saveChangesDialog anchors.centerIn: parent - onAccepted: EffectMakerBackend.effectMakerModel.clear() + onSave: { + if (EffectMakerBackend.effectMakerModel.currentComposition === "") { + // if current composition is unsaved, show save as dialog and clear afterwards + saveDialog.clearOnClose = true + saveDialog.open() + } else { + EffectMakerBackend.effectMakerModel.clear() + } + } + + onDiscard: { + EffectMakerBackend.effectMakerModel.clear() + } } Column { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml index fa83def976b..a006c4ed7fe 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml @@ -18,7 +18,7 @@ StudioControls.Dialog { implicitWidth: 250 implicitHeight: 160 - property string compositionName: "" + property bool clearOnClose: false // clear the effect maker after saving onOpened: { let model = EffectMakerBackend.effectMakerModel @@ -84,14 +84,28 @@ StudioControls.Dialog { text: qsTr("Save") enabled: nameText.text !== "" onClicked: { - root.compositionName = nameText.text + EffectMakerBackend.effectMakerModel.saveComposition(nameText.text) + + if (root.clearOnClose) { + EffectMakerBackend.effectMakerModel.clear() + root.clearOnClose = false + } + root.accept() // TODO: confirm before overriding effect with same name } } HelperWidgets.Button { text: qsTr("Cancel") - onClicked: root.reject() + + onClicked: { + if (root.clearOnClose) { + EffectMakerBackend.effectMakerModel.clear() + root.clearOnClose = false + } + + root.reject() + } } } } diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveChangesDialog.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveChangesDialog.qml index e119d15f348..c048c645d84 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveChangesDialog.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveChangesDialog.qml @@ -18,6 +18,9 @@ StudioControls.Dialog { implicitWidth: 300 implicitHeight: 130 + signal save() + signal discard() + contentItem: Item { Text { text: qsTr("Current composition has unsaved changes.") @@ -41,7 +44,10 @@ StudioControls.Dialog { text: qsTr("Save") onClicked: { let name = EffectMakerBackend.effectMakerModel.currentComposition - EffectMakerBackend.effectMakerModel.saveComposition(name) + if (name !== "") + EffectMakerBackend.effectMakerModel.saveComposition(name) + + root.save() root.accept() } } @@ -49,7 +55,10 @@ StudioControls.Dialog { HelperWidgets.Button { width: 110 text: qsTr("Discard Changes") - onClicked: root.accept() + onClicked: { + root.discard() + root.accept() + } } } } From d9774e7faf7a5ff9d388d54d777e769b4262b92e Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Tue, 12 Dec 2023 15:15:15 +0200 Subject: [PATCH 092/101] EffectMaker: confirm save changes before opening an composition Change-Id: I05659e4cdeba5dc5f437d2fb99bc3768c6a1522d Reviewed-by: Miikka Heikkinen Reviewed-by: Qt CI Patch Build Bot --- .../effectMakerQmlSources/EffectMaker.qml | 16 ++++++++++++++-- src/plugins/effectmakernew/effectmakerview.cpp | 9 +-------- .../effectmakernew/effectmakerwidget.cpp | 18 +++++++++++++++++- src/plugins/effectmakernew/effectmakerwidget.h | 3 +++ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index 709380d8c31..519854d545f 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -16,6 +16,16 @@ Item { property int moveToIdx: 0 property bool previewAnimationRunning: false + // Invoked after save changes is done + property var onSaveChangesCallback: () => {} + + // Invoked from C++ side when open composition is requested and there are unsaved changes + function promptToSaveBeforeOpen() { + root.onSaveChangesCallback = () => { EffectMakerBackend.rootView.doOpenComposition() } + + saveChangesDialog.open() + } + SaveAsDialog { id: saveDialog anchors.centerIn: parent @@ -31,12 +41,12 @@ Item { saveDialog.clearOnClose = true saveDialog.open() } else { - EffectMakerBackend.effectMakerModel.clear() + root.onSaveChangesCallback() } } onDiscard: { - EffectMakerBackend.effectMakerModel.clear() + root.onSaveChangesCallback() } } @@ -47,6 +57,8 @@ Item { EffectMakerTopBar { onAddClicked: { + root.onSaveChangesCallback = () => { EffectMakerBackend.effectMakerModel.clear() } + if (EffectMakerBackend.effectMakerModel.hasUnsavedChanges) saveChangesDialog.open() else diff --git a/src/plugins/effectmakernew/effectmakerview.cpp b/src/plugins/effectmakernew/effectmakerview.cpp index 637c12f6d5a..11624efdeb0 100644 --- a/src/plugins/effectmakernew/effectmakerview.cpp +++ b/src/plugins/effectmakernew/effectmakerview.cpp @@ -7,17 +7,10 @@ #include "effectmakernodesmodel.h" #include "effectmakerwidget.h" -#include "nodeinstanceview.h" #include "qmldesignerconstants.h" #include -#include -#include -#include -#include -#include - namespace EffectMaker { EffectMakerContext::EffectMakerContext(QWidget *widget) @@ -66,7 +59,7 @@ void EffectMakerView::customNotification([[maybe_unused]] const AbstractView *vi { if (identifier == "open_effectmaker_composition" && data.count() > 0) { const QString compositionPath = data[0].toString(); - m_widget->effectMakerModel()->openComposition(compositionPath); + m_widget->openComposition(compositionPath); } } diff --git a/src/plugins/effectmakernew/effectmakerwidget.cpp b/src/plugins/effectmakernew/effectmakerwidget.cpp index 877d0e2d523..db549501f37 100644 --- a/src/plugins/effectmakernew/effectmakerwidget.cpp +++ b/src/plugins/effectmakernew/effectmakerwidget.cpp @@ -12,7 +12,6 @@ //#include "qmldesigner/designercore/imagecache/midsizeimagecacheprovider.h" #include "qmldesignerconstants.h" #include "qmldesignerplugin.h" -#include "qqmlcontext.h" #include "theme.h" #include @@ -30,7 +29,9 @@ #include #include +#include #include +#include #include namespace EffectMaker { @@ -193,6 +194,21 @@ void EffectMakerWidget::initView() reloadQmlSource(); } +void EffectMakerWidget::openComposition(const QString &path) +{ + m_compositionPath = path; + + if (effectMakerModel()->hasUnsavedChanges()) + QMetaObject::invokeMethod(quickWidget()->rootObject(), "promptToSaveBeforeOpen"); + else + doOpenComposition(); +} + +void EffectMakerWidget::doOpenComposition() +{ + effectMakerModel()->openComposition(m_compositionPath); +} + void EffectMakerWidget::reloadQmlSource() { const QString effectMakerQmlPath = qmlSourcesPath() + "/EffectMaker.qml"; diff --git a/src/plugins/effectmakernew/effectmakerwidget.h b/src/plugins/effectmakernew/effectmakerwidget.h index 9204026a9c9..35f43f99b3e 100644 --- a/src/plugins/effectmakernew/effectmakerwidget.h +++ b/src/plugins/effectmakernew/effectmakerwidget.h @@ -39,6 +39,7 @@ public: void delayedUpdateModel(); void updateModel(); void initView(); + void openComposition(const QString &path); StudioQuickWidget *quickWidget() const; QPointer effectMakerModel() const; @@ -46,6 +47,7 @@ public: Q_INVOKABLE void addEffectNode(const QString &nodeQenPath); Q_INVOKABLE void focusSection(int section); + Q_INVOKABLE void doOpenComposition(); Q_INVOKABLE QRect screenRect() const; Q_INVOKABLE QPoint globalPos(const QPoint &point) const; @@ -74,6 +76,7 @@ private: }; ImportScanData m_importScan; + QString m_compositionPath; }; } // namespace EffectMaker From 82a0ae5cafb9c56ce88583a46f7a532456bf1e3a Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Wed, 13 Dec 2023 11:34:07 +0200 Subject: [PATCH 093/101] QmlDesigner: Add 'save as' icon and update zoom and save icons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Id05dd67407dd8a4db0056caa94c61b459bd4ab23 Reviewed-by: Henning Gründl --- .../imports/StudioTheme/InternalConstants.qml | 189 +++++++++--------- .../imports/StudioTheme/icons.ttf | Bin 66032 -> 66308 bytes .../components/componentcore/theme.h | 1 + 3 files changed, 96 insertions(+), 94 deletions(-) diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml index a727c0d4215..92d0d771a3c 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml @@ -282,100 +282,101 @@ QtObject { readonly property string s_snapping: "\u012D" readonly property string s_timeline: "\u012E" readonly property string s_visibility: "\u012F" - readonly property string saveLogs_medium: "\u0130" - readonly property string save_medium: "\u0131" - readonly property string scale_medium: "\u0132" - readonly property string search: "\u0133" - readonly property string search_small: "\u0134" - readonly property string sectionToggle: "\u0135" - readonly property string selectFill_medium: "\u0136" - readonly property string selectOutline_medium: "\u0137" - readonly property string selectParent_small: "\u0138" - readonly property string selection_small: "\u0139" - readonly property string settings_medium: "\u013A" - readonly property string signal_small: "\u013B" - readonly property string snapping_conf_medium: "\u013C" - readonly property string snapping_medium: "\u013D" - readonly property string snapping_small: "\u013E" - readonly property string sortascending_medium: "\u013F" - readonly property string sortdescending_medium: "\u0140" - readonly property string sphere_medium: "\u0141" - readonly property string sphere_small: "\u0142" - readonly property string splitColumns: "\u0143" - readonly property string splitRows: "\u0144" - readonly property string splitScreen_medium: "\u0145" - readonly property string spotLight_small: "\u0146" - readonly property string stackedContainer_small: "\u0147" - readonly property string startNode: "\u0148" - readonly property string step_medium: "\u0149" - readonly property string stop_medium: "\u014A" - readonly property string tableView_medium: "\u014B" - readonly property string testIcon: "\u014C" - readonly property string textAlignBottom: "\u014D" - readonly property string textAlignCenter: "\u014E" - readonly property string textAlignJustified: "\u014F" - readonly property string textAlignLeft: "\u0150" - readonly property string textAlignMiddle: "\u0151" - readonly property string textAlignRight: "\u0152" - readonly property string textAlignTop: "\u0153" - readonly property string textBulletList: "\u0154" - readonly property string textFullJustification: "\u0155" - readonly property string textNumberedList: "\u0156" - readonly property string textures_medium: "\u0157" - readonly property string tickIcon: "\u0158" - readonly property string tickMark_small: "\u0159" - readonly property string timeline_small: "\u015A" - readonly property string toEndFrame_medium: "\u015B" - readonly property string toNextFrame_medium: "\u015C" - readonly property string toPrevFrame_medium: "\u015D" - readonly property string toStartFrame_medium: "\u015E" - readonly property string topToolbar_annotations: "\u015F" - readonly property string topToolbar_closeFile: "\u0160" - readonly property string topToolbar_designMode: "\u0161" - readonly property string topToolbar_enterComponent: "\u0162" - readonly property string topToolbar_home: "\u0163" - readonly property string topToolbar_makeComponent: "\u0164" - readonly property string topToolbar_navFile: "\u0165" - readonly property string topToolbar_runProject: "\u0166" - readonly property string translationCreateFiles: "\u0167" - readonly property string translationCreateReport: "\u0168" - readonly property string translationExport: "\u0169" - readonly property string translationImport: "\u016A" - readonly property string translationSelectLanguages: "\u016B" - readonly property string translationTest: "\u016C" - readonly property string transparent: "\u016D" - readonly property string triState: "\u016E" - readonly property string triangleArcA: "\u016F" - readonly property string triangleArcB: "\u0170" - readonly property string triangleCornerA: "\u0171" - readonly property string triangleCornerB: "\u0172" - readonly property string unLinked: "\u0173" - readonly property string undo: "\u0174" - readonly property string unify_medium: "\u0175" - readonly property string unpin: "\u0176" - readonly property string upDownIcon: "\u0177" - readonly property string upDownSquare2: "\u0178" - readonly property string updateAvailable_medium: "\u0179" - readonly property string updateContent_medium: "\u017A" - readonly property string visibilityOff: "\u017B" - readonly property string visibilityOn: "\u017C" - readonly property string visible_medium: "\u017D" - readonly property string visible_small: "\u017E" - readonly property string warning_medium: "\u017F" - readonly property string wildcard: "\u0180" - readonly property string wizardsAutomotive: "\u0181" - readonly property string wizardsDesktop: "\u0182" - readonly property string wizardsGeneric: "\u0183" - readonly property string wizardsMcuEmpty: "\u0184" - readonly property string wizardsMcuGraph: "\u0185" - readonly property string wizardsMobile: "\u0186" - readonly property string wizardsUnknown: "\u0187" - readonly property string zoomAll: "\u0188" - readonly property string zoomIn: "\u0189" - readonly property string zoomIn_medium: "\u018A" - readonly property string zoomOut: "\u018B" - readonly property string zoomOut_medium: "\u018C" - readonly property string zoomSelection: "\u018D" + readonly property string saveAs_medium: "\u0130" + readonly property string saveLogs_medium: "\u0131" + readonly property string save_medium: "\u0132" + readonly property string scale_medium: "\u0133" + readonly property string search: "\u0134" + readonly property string search_small: "\u0135" + readonly property string sectionToggle: "\u0136" + readonly property string selectFill_medium: "\u0137" + readonly property string selectOutline_medium: "\u0138" + readonly property string selectParent_small: "\u0139" + readonly property string selection_small: "\u013A" + readonly property string settings_medium: "\u013B" + readonly property string signal_small: "\u013C" + readonly property string snapping_conf_medium: "\u013D" + readonly property string snapping_medium: "\u013E" + readonly property string snapping_small: "\u013F" + readonly property string sortascending_medium: "\u0140" + readonly property string sortdescending_medium: "\u0141" + readonly property string sphere_medium: "\u0142" + readonly property string sphere_small: "\u0143" + readonly property string splitColumns: "\u0144" + readonly property string splitRows: "\u0145" + readonly property string splitScreen_medium: "\u0146" + readonly property string spotLight_small: "\u0147" + readonly property string stackedContainer_small: "\u0148" + readonly property string startNode: "\u0149" + readonly property string step_medium: "\u014A" + readonly property string stop_medium: "\u014B" + readonly property string tableView_medium: "\u014C" + readonly property string testIcon: "\u014D" + readonly property string textAlignBottom: "\u014E" + readonly property string textAlignCenter: "\u014F" + readonly property string textAlignJustified: "\u0150" + readonly property string textAlignLeft: "\u0151" + readonly property string textAlignMiddle: "\u0152" + readonly property string textAlignRight: "\u0153" + readonly property string textAlignTop: "\u0154" + readonly property string textBulletList: "\u0155" + readonly property string textFullJustification: "\u0156" + readonly property string textNumberedList: "\u0157" + readonly property string textures_medium: "\u0158" + readonly property string tickIcon: "\u0159" + readonly property string tickMark_small: "\u015A" + readonly property string timeline_small: "\u015B" + readonly property string toEndFrame_medium: "\u015C" + readonly property string toNextFrame_medium: "\u015D" + readonly property string toPrevFrame_medium: "\u015E" + readonly property string toStartFrame_medium: "\u015F" + readonly property string topToolbar_annotations: "\u0160" + readonly property string topToolbar_closeFile: "\u0161" + readonly property string topToolbar_designMode: "\u0162" + readonly property string topToolbar_enterComponent: "\u0163" + readonly property string topToolbar_home: "\u0164" + readonly property string topToolbar_makeComponent: "\u0165" + readonly property string topToolbar_navFile: "\u0166" + readonly property string topToolbar_runProject: "\u0167" + readonly property string translationCreateFiles: "\u0168" + readonly property string translationCreateReport: "\u0169" + readonly property string translationExport: "\u016A" + readonly property string translationImport: "\u016B" + readonly property string translationSelectLanguages: "\u016C" + readonly property string translationTest: "\u016D" + readonly property string transparent: "\u016E" + readonly property string triState: "\u016F" + readonly property string triangleArcA: "\u0170" + readonly property string triangleArcB: "\u0171" + readonly property string triangleCornerA: "\u0172" + readonly property string triangleCornerB: "\u0173" + readonly property string unLinked: "\u0174" + readonly property string undo: "\u0175" + readonly property string unify_medium: "\u0176" + readonly property string unpin: "\u0177" + readonly property string upDownIcon: "\u0178" + readonly property string upDownSquare2: "\u0179" + readonly property string updateAvailable_medium: "\u017A" + readonly property string updateContent_medium: "\u017B" + readonly property string visibilityOff: "\u017C" + readonly property string visibilityOn: "\u017D" + readonly property string visible_medium: "\u017E" + readonly property string visible_small: "\u017F" + readonly property string warning_medium: "\u0180" + readonly property string wildcard: "\u0181" + readonly property string wizardsAutomotive: "\u0182" + readonly property string wizardsDesktop: "\u0183" + readonly property string wizardsGeneric: "\u0184" + readonly property string wizardsMcuEmpty: "\u0185" + readonly property string wizardsMcuGraph: "\u0186" + readonly property string wizardsMobile: "\u0187" + readonly property string wizardsUnknown: "\u0188" + readonly property string zoomAll: "\u0189" + readonly property string zoomIn: "\u018A" + readonly property string zoomIn_medium: "\u018B" + readonly property string zoomOut: "\u018C" + readonly property string zoomOut_medium: "\u018D" + readonly property string zoomSelection: "\u018E" readonly property font iconFont: Qt.font({ "family": controlIcons.name, diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf index 42e3a73fedb69329f00cbfeb2558ea3cd7226ad1..c650a651fe1738c65a10e8ea365893af4251f671 100644 GIT binary patch delta 1190 zcmey+%+k`vQqRE1z`(%E(7?dV5a8w(;=9nL`X2)$(+dU$1{wcgeWS<)X;usjj1deB z3<=4(i3M8WIuZ;FEDIPIn8K3FN)#9rnJO6=*nTiDFtDU278m^g&%n&U$n=1Lfq^4E zr!wugQFapp1LqwEh8qBDuY#Ei=1zC*DOw^RvM3{Yeg@kzHgrtPxc!h<*j9M$_r6nHK z>i^r%$muT(ZtMH z6eP)fkC9VYlI!1_qG@@%b8~m!*`1s8FMrp(*w}d>f^i$KurLqf93fs_p*eg)5T*sM z&}2p~NnuV#(WIQ+cR||nrk41}%m?Y1w`)G5v=A>NkMJB&;LZ`25}L!vBg`noJBMNN zuKSH(#~YI3ct%CAqZx^F>c1|qGjTeQFBaiKVJV@_TOLF(aT+ohGw3oHG8j!3eQd#H zXsl~!q-$hgWIWmDQNZNoj~6lKZ}xg}hlz5C4$Kv?h)RfH9+|3hz Mg|KtObEn1$05bwzM*si- delta 788 zcmZo^WBJg`QqRE1z`(%E(7?dV5a8w(;=54(_FD!<#w!dA3^M+~`bLop(kvMm7$X=M z7!s0m6AQG$b;KDMSmrP=Foh+Tl_)SMGF37#uzg`*U|>m4EH3!}pMjZyk?{-z0|Q5T zPGuVJrouT444gL@7_Qf3q$Z|lF8;Egfq~%;0|SFuMn-CVBG=FVtqcr|A`A=+DjB&Y z6|x>89t;eOI~W+4p5){wCtkTc&xC=2?FRz`)4klpiUP)S4Br_T7%dnW7!>jnb5jqh z?^I=Aco@RKz;wAFzqmwWzo!oa!xIe#2H7QG&oMGEa30J~j_0@e%D~P1f`Ng7;bG4W zkRuo#_AuSpKZ((nF>kURV=QCu<~fYsOp{+S@0h%pMTfC>^92@vmiidKef~!NY5w#4 z*Z5xu;0p)~*c8|oWD@iw*dn+u_)kbq$gxn4P_xjK&~;%(VT-~xgfoPjgwG4#6Co54 z7qKGZOQcuiw8%G69#K=G4Weg7?~8sBqZ1PsGa=?k%(qyJ*u1#7xHIuO@pbVl;_oG> zBy=PkOJqrGNL-a9kz|nMWtWta)R43-=}WRs@}d;8l%SNflo=_vQe#q2rE#R0rIn?f zNMDwrkP(z|D$^o!P8Lg6T-JiDPuV)zdD;6I7&hPG6r3~p>#`NXtPBkQEtp?0D=-K# zh%sn0STi_JUb9?Rg3(A!)KG*?n^8&4)X>Dtn90b@L`{iJWb)1BDuVy~ee?2s89{_` zx|dhF=j6Z3m4q3$=KA^Ng7Ci+o*-cchRyOTE||0OGe|R-Po6hfnvrR;A+IEpvC-t6 zlVyZT1bGe!N(dg{5ri=&^D9aTGghI9fg~p{d(a3rMSb$T$uitZY9?mJibi50Y|0>m zc>Zn$8Ns*b_C4(-5A%o#$(I*yMMwYsUhPp-u nM#htU9tTWb{$vqj-e#|-cbGP7yvP^cyz+MdJ2yNn+}IBQT)z86 diff --git a/src/plugins/qmldesigner/components/componentcore/theme.h b/src/plugins/qmldesigner/components/componentcore/theme.h index 5aa2e3ee7f8..3ffc41c3c61 100644 --- a/src/plugins/qmldesigner/components/componentcore/theme.h +++ b/src/plugins/qmldesigner/components/componentcore/theme.h @@ -290,6 +290,7 @@ public: s_snapping, s_timeline, s_visibility, + saveAs_medium, saveLogs_medium, save_medium, scale_medium, From ff03588f7edfef433c26318655b676d7205652b9 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Wed, 13 Dec 2023 12:11:06 +0200 Subject: [PATCH 094/101] EffectMaker: Add 'save as' functunality Also some tweaks Change-Id: Icc4767b816d1917cd674b20283d43e33ffb36219 Reviewed-by: Reviewed-by: Miikka Heikkinen Reviewed-by: Qt CI Patch Build Bot --- .../effectMakerQmlSources/EffectMaker.qml | 18 +++++-- .../EffectMakerPreview.qml | 22 ++++----- .../EffectMakerTopBar.qml | 48 +++++++++++-------- .../effectMakerQmlSources/SaveAsDialog.qml | 6 +-- 4 files changed, 57 insertions(+), 37 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index 519854d545f..800493d5f99 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -26,8 +26,16 @@ Item { saveChangesDialog.open() } + Connections { + target: EffectMakerBackend.effectMakerModel + function onIsEmptyChanged() { + if (EffectMakerBackend.effectMakerModel.isEmpty) + saveAsDialog.close() + } + } + SaveAsDialog { - id: saveDialog + id: saveAsDialog anchors.centerIn: parent } @@ -38,8 +46,8 @@ Item { onSave: { if (EffectMakerBackend.effectMakerModel.currentComposition === "") { // if current composition is unsaved, show save as dialog and clear afterwards - saveDialog.clearOnClose = true - saveDialog.open() + saveAsDialog.clearOnClose = true + saveAsDialog.open() } else { root.onSaveChangesCallback() } @@ -69,10 +77,12 @@ Item { let name = EffectMakerBackend.effectMakerModel.currentComposition if (name === "") - saveDialog.open() + saveAsDialog.open() else EffectMakerBackend.effectMakerModel.saveComposition(name) } + + onSaveAsClicked: saveAsDialog.open() } EffectMakerPreview { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml index 9b58cd56bd2..4636159f481 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml @@ -84,17 +84,6 @@ Column { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter - HelperWidgets.AbstractButton { - enabled: sourceImage.scale > .4 - style: StudioTheme.Values.viewBarButtonStyle - buttonIcon: StudioTheme.Constants.zoomOut_medium - tooltip: qsTr("Zoom out") - - onClicked: { - sourceImage.scale -= .2 - } - } - HelperWidgets.AbstractButton { enabled: sourceImage.scale < 2 style: StudioTheme.Values.viewBarButtonStyle @@ -106,6 +95,17 @@ Column { } } + HelperWidgets.AbstractButton { + enabled: sourceImage.scale > .4 + style: StudioTheme.Values.viewBarButtonStyle + buttonIcon: StudioTheme.Constants.zoomOut_medium + tooltip: qsTr("Zoom out") + + onClicked: { + sourceImage.scale -= .2 + } + } + HelperWidgets.AbstractButton { enabled: sourceImage.scale !== 1 style: StudioTheme.Values.viewBarButtonStyle diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml index 2c7ff15cd5e..f7816396a24 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml @@ -17,30 +17,40 @@ Rectangle { signal addClicked signal saveClicked + signal saveAsClicked - HelperWidgets.AbstractButton { - id: addButton - + Row { + spacing: 5 anchors.verticalCenter: parent.verticalCenter - x: 5 - style: StudioTheme.Values.viewBarButtonStyle - buttonIcon: StudioTheme.Constants.add_medium - tooltip: qsTr("Add new composition") - onClicked: root.addClicked() + HelperWidgets.AbstractButton { + style: StudioTheme.Values.viewBarButtonStyle + buttonIcon: StudioTheme.Constants.add_medium + tooltip: qsTr("Add new composition") + + onClicked: root.addClicked() + } + + HelperWidgets.AbstractButton { + style: StudioTheme.Values.viewBarButtonStyle + buttonIcon: StudioTheme.Constants.save_medium + tooltip: qsTr("Save current composition") + enabled: EffectMakerBackend.effectMakerModel.hasUnsavedChanges + || EffectMakerBackend.effectMakerModel.currentComposition === "" + + onClicked: root.saveClicked() + } + + HelperWidgets.AbstractButton { + style: StudioTheme.Values.viewBarButtonStyle + buttonIcon: StudioTheme.Constants.saveAs_medium + tooltip: qsTr("Save current composition with a new name") + enabled: !EffectMakerBackend.effectMakerModel.isEmpty + + onClicked: root.saveAsClicked() + } } - HelperWidgets.AbstractButton { - anchors.verticalCenter: parent.verticalCenter - x: addButton.x + addButton.width + 5 - style: StudioTheme.Values.viewBarButtonStyle - buttonIcon: StudioTheme.Constants.save_medium - tooltip: qsTr("Save current composition") - enabled: EffectMakerBackend.effectMakerModel.hasUnsavedChanges - || EffectMakerBackend.effectMakerModel.currentComposition === "" - - onClicked: root.saveClicked() - } Text { readonly property string compName: EffectMakerBackend.effectMakerModel.currentComposition diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml index a006c4ed7fe..8e762cebbd8 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/SaveAsDialog.qml @@ -21,10 +21,10 @@ StudioControls.Dialog { property bool clearOnClose: false // clear the effect maker after saving onOpened: { - let model = EffectMakerBackend.effectMakerModel - nameText.text = model.currentComposition === "" ? model.getUniqueEffectName() : model.currentComposition - emptyText.text = "" + nameText.text = EffectMakerBackend.effectMakerModel.getUniqueEffectName() + nameText.selectAll() nameText.forceActiveFocus() + emptyText.text = "" } contentItem: Item { From 434d0faaa0c4eb82028da360722c14bc7178b791 Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Wed, 13 Dec 2023 15:54:57 +0200 Subject: [PATCH 095/101] EffectMaker: Add 'assign to selected' feature Fixes: QDS-11444 Change-Id: I17b5397b88eeccaae585e84d7ce62f4f80474f87 Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Reviewed-by: Miikka Heikkinen --- .../effectMakerQmlSources/EffectMaker.qml | 4 ++++ .../effectMakerQmlSources/EffectMakerTopBar.qml | 10 ++++++++++ src/plugins/effectmakernew/effectmakermodel.cpp | 7 +++++++ src/plugins/effectmakernew/effectmakermodel.h | 2 ++ src/plugins/effectmakernew/effectmakerview.cpp | 12 +++++++++++- src/plugins/effectmakernew/effectmakerview.h | 1 - .../components/componentcore/modelnodeoperations.h | 3 ++- 7 files changed, 36 insertions(+), 3 deletions(-) diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index 800493d5f99..81be29f9ae2 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -83,6 +83,10 @@ Item { } onSaveAsClicked: saveAsDialog.open() + + onAssignToSelectedClicked: { + EffectMakerBackend.effectMakerModel.assignToSelected() + } } EffectMakerPreview { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml index f7816396a24..9c962655e3a 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerTopBar.qml @@ -18,6 +18,7 @@ Rectangle { signal addClicked signal saveClicked signal saveAsClicked + signal assignToSelectedClicked Row { spacing: 5 @@ -49,6 +50,15 @@ Rectangle { onClicked: root.saveAsClicked() } + + HelperWidgets.AbstractButton { + style: StudioTheme.Values.viewBarButtonStyle + buttonIcon: StudioTheme.Constants.assignTo_medium + tooltip: qsTr("Assign current composition to selected item") + enabled: EffectMakerBackend.effectMakerModel.currentComposition !== "" + + onClicked: root.assignToSelectedClicked() + } } diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index 54c556c555a..e13e2e39a9a 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -164,6 +164,13 @@ void EffectMakerModel::clear() emit nodesChanged(); } +void EffectMakerModel::assignToSelected() +{ + const QString effectsAssetsDir = QmlDesigner::ModelNodeOperations::getEffectsDefaultDirectory(); + const QString path = effectsAssetsDir + QDir::separator() + m_currentComposition + ".qep"; + emit assignToSelectedTriggered(path); +} + QString EffectMakerModel::getUniqueEffectName() const { const QString effectsDir = QmlDesigner::ModelNodeOperations::getEffectsDefaultDirectory(); diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h index abcb367ad7a..7f73ed4cdca 100644 --- a/src/plugins/effectmakernew/effectmakermodel.h +++ b/src/plugins/effectmakernew/effectmakermodel.h @@ -65,6 +65,7 @@ public: Q_INVOKABLE void moveNode(int fromIdx, int toIdx); Q_INVOKABLE void removeNode(int idx); Q_INVOKABLE void clear(); + Q_INVOKABLE void assignToSelected(); Q_INVOKABLE QString getUniqueEffectName() const; bool shadersUpToDate() const; @@ -105,6 +106,7 @@ signals: void nodesChanged(); void resourcesSaved(const QByteArray &type, const Utils::FilePath &path); void hasUnsavedChangesChanged(); + void assignToSelectedTriggered(const QString &effectPath); private: enum Roles { diff --git a/src/plugins/effectmakernew/effectmakerview.cpp b/src/plugins/effectmakernew/effectmakerview.cpp index 11624efdeb0..42624826943 100644 --- a/src/plugins/effectmakernew/effectmakerview.cpp +++ b/src/plugins/effectmakernew/effectmakerview.cpp @@ -9,6 +9,8 @@ #include "qmldesignerconstants.h" +#include + #include namespace EffectMaker { @@ -44,6 +46,15 @@ QmlDesigner::WidgetInfo EffectMakerView::widgetInfo() if (m_widget.isNull()) { m_widget = new EffectMakerWidget{this}; + connect(m_widget->effectMakerModel(), &EffectMakerModel::assignToSelectedTriggered, this, + [&] (const QString &effectPath) { + executeInTransaction("EffectMakerView::widgetInfo", [&] { + const QList selectedNodes = selectedModelNodes(); + for (const QmlDesigner::ModelNode &node : selectedNodes) + QmlDesigner::ModelNodeOperations::handleItemLibraryEffectDrop(effectPath, node); + }); + }); + auto context = new EffectMakerContext(m_widget.data()); Core::ICore::addContextObject(context); } @@ -78,4 +89,3 @@ void EffectMakerView::modelAboutToBeDetached(QmlDesigner::Model *model) } } // namespace EffectMaker - diff --git a/src/plugins/effectmakernew/effectmakerview.h b/src/plugins/effectmakernew/effectmakerview.h index 2bed1cfc103..297e5acc776 100644 --- a/src/plugins/effectmakernew/effectmakerview.h +++ b/src/plugins/effectmakernew/effectmakerview.h @@ -43,4 +43,3 @@ private: }; } // namespace EffectMaker - diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h index c8042887e18..dec37f0f9ef 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -136,7 +136,8 @@ bool isNewEffectMakerActivated(); Utils::FilePath getImagesDefaultDirectory(); //Item Library and Assets related drop operations -ModelNode handleItemLibraryEffectDrop(const QString &effectPath, const ModelNode &targetNode); +QMLDESIGNERCOMPONENTS_EXPORT ModelNode handleItemLibraryEffectDrop(const QString &effectPath, + const ModelNode &targetNode); void handleTextureDrop(const QMimeData *mimeData, const ModelNode &targetModelNode); void handleMaterialDrop(const QMimeData *mimeData, const ModelNode &targetNode); ModelNode handleItemLibraryImageDrop(const QString &imagePath, From 0f2a69408b39560011316b05b4a2d661e2e1a2a9 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 13 Dec 2023 22:31:44 +0100 Subject: [PATCH 096/101] Edit3DWidget: Avoid using sender() Amends b662c50e0a32e7444313758af935e03e20c51892 Amends 23f12f7b42cf64493ee28832d9e48eda85587f21 Change-Id: I71adb71c47e90aa257158eb7e600b99860432b3e Reviewed-by: Miikka Heikkinen --- .../components/edit3d/edit3dwidget.cpp | 29 +++++++------------ .../components/edit3d/edit3dwidget.h | 4 +-- 2 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index b56986e79df..ff5852c6312 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -8,7 +8,6 @@ #include "edit3dcanvas.h" #include "edit3dtoolbarmenu.h" #include "edit3dview.h" -#include "edit3dviewconfig.h" #include "externaldependenciesinterface.h" #include "materialutils.h" #include "metainfo.h" @@ -312,8 +311,8 @@ void Edit3DWidget::createContextMenu() auto addOverrideMenuAction = [&](const QString &label, const QString &toolTip, MaterialOverrideType type) { - QAction *action = overridesSubMenu->addAction( - label, this, &Edit3DWidget::onMatOverrideAction); + QAction *action = overridesSubMenu->addAction(label); + connect(action, &QAction::triggered, this, [this, action] { onMatOverrideAction(action); }); action->setData(int(type)); action->setCheckable(true); action->setToolTip(toolTip); @@ -457,11 +456,8 @@ void Edit3DWidget::updateCreateSubMenu(const QList &entriesL m_createSubMenu->addMenu(catMenu); } - QAction *action = catMenu->addAction( - getEntryIcon(entry), - entry.name(), - this, - &Edit3DWidget::onCreateAction); + QAction *action = catMenu->addAction(getEntryIcon(entry), entry.name()); + connect(action, &QAction::triggered, this, [this, action] { onCreateAction(action); }); action->setData(entry.name()); m_nameToEntry.insert(entry.name(), entry); } @@ -469,10 +465,9 @@ void Edit3DWidget::updateCreateSubMenu(const QList &entriesL } // Action triggered from the "create" sub-menu -void Edit3DWidget::onCreateAction() +void Edit3DWidget::onCreateAction(QAction *action) { - QAction *action = qobject_cast(sender()); - if (!action || !m_view || !m_view->model() || isSceneLocked()) + if (!m_view || !m_view->model() || isSceneLocked()) return; m_view->executeInTransaction(__FUNCTION__, [&] { @@ -499,10 +494,9 @@ void Edit3DWidget::onCreateAction() }); } -void Edit3DWidget::onMatOverrideAction() +void Edit3DWidget::onMatOverrideAction(QAction *action) { - QAction *action = qobject_cast(sender()); - if (!action || !m_view || !m_view->model()) + if (!m_view || !m_view->model()) return; QVariantList list; @@ -522,17 +516,16 @@ void Edit3DWidget::onMatOverrideAction() void Edit3DWidget::onWireframeAction() { - QAction *action = qobject_cast(sender()); - if (!action || !m_view || !m_view->model()) + if (!m_view || !m_view->model()) return; QVariantList list; for (int i = 0; i < m_view->splitToolStates().size(); ++i) { Edit3DView::SplitToolState state = m_view->splitToolStates()[i]; if (i == m_view->activeSplit()) { - state.showWireframe = action->isChecked(); + state.showWireframe = m_wireFrameAction->isChecked(); m_view->setSplitToolState(i, state); - list.append(action->isChecked()); + list.append(m_wireFrameAction->isChecked()); } else { list.append(state.showWireframe); } diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h index 67e23b0b98c..0c9c807473b 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h @@ -53,8 +53,8 @@ public: void updateCreateSubMenu(const QList &entriesList); private slots: - void onCreateAction(); - void onMatOverrideAction(); + void onCreateAction(QAction *action); + void onMatOverrideAction(QAction *action); void onWireframeAction(); void onResetAllOverridesAction(); From 2f4fa0b62d46375fc17175111fd37daa632854e9 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 13 Dec 2023 23:33:35 +0100 Subject: [PATCH 097/101] Qt5NodeInstanceServer: Avoid using sender() Amends b4db8a2d84c5b71c81b7feb3bc1d1328ea2247c6 Change-Id: I9dc446d376bce9d91eb9d7a753003e0d92e10889 Reviewed-by: Miikka Heikkinen --- .../instances/qt5nodeinstanceserver.cpp | 17 +++++------------ .../instances/qt5nodeinstanceserver.h | 2 -- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceserver.cpp b/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceserver.cpp index 4c163bf69ff..db4199b64a1 100644 --- a/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceserver.cpp +++ b/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceserver.cpp @@ -268,22 +268,15 @@ void Qt5NodeInstanceServer::setPipelineCacheConfig([[maybe_unused]] QQuickWindow #ifdef USE_SHADER_CACHE QtQuick3DEditorHelpers::ShaderCache::setAutomaticDiskCache(false); auto wa = QQuick3DSceneManager::getOrSetWindowAttachment(*w); - connect(wa, &QQuick3DWindowAttachment::renderContextInterfaceChanged, - this, &Qt5NodeInstanceServer::handleRciSet); + connect(wa, &QQuick3DWindowAttachment::renderContextInterfaceChanged, this, [this, wa] { + auto context = wa->rci().get(); + if (context && context->shaderCache()) + context->shaderCache()->persistentShaderBakingCache().load(m_shaderCacheFile); + }); #endif #endif } -void Qt5NodeInstanceServer::handleRciSet() -{ -#ifdef USE_SHADER_CACHE - auto wa = qobject_cast(sender()); - auto context = wa ? wa->rci().get() : nullptr; - if (context && context->shaderCache()) - context->shaderCache()->persistentShaderBakingCache().load(m_shaderCacheFile); -#endif -} - bool Qt5NodeInstanceServer::initRhi([[maybe_unused]] RenderViewData &viewData) { if (!viewData.renderControl) { diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceserver.h b/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceserver.h index 9294a064e08..d684046fc5b 100644 --- a/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceserver.h +++ b/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceserver.h @@ -77,8 +77,6 @@ protected: virtual QImage grabRenderControl(RenderViewData &viewData); private: - void handleRciSet(); - RenderViewData m_viewData; QByteArray m_pipelineCacheData; QString m_pipelineCacheLocation; From d6bc19e54da84c6227c854aa3ce65a0581440867 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Wed, 13 Dec 2023 23:49:50 +0100 Subject: [PATCH 098/101] Qt5InformationNodeInstanceServer: Avoid using sender() Get rid of some unused includes. Change-Id: Ib8dd5f9672c446c5c571e79ed1f26f3f4af2b65d Reviewed-by: Miikka Heikkinen --- .../qt5informationnodeinstanceserver.cpp | 23 ++++++++++--------- .../qt5informationnodeinstanceserver.h | 4 +--- .../instances/quick3dnodeinstance.cpp | 13 +++++------ 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp index 180390def44..2200a402531 100644 --- a/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp +++ b/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp @@ -10,13 +10,10 @@ #include #include "servernodeinstance.h" -#include "childrenchangeeventfilter.h" #include "propertyabstractcontainer.h" #include "propertybindingcontainer.h" #include "propertyvaluecontainer.h" #include "instancecontainer.h" -#include "createinstancescommand.h" -#include "changefileurlcommand.h" #include "clearscenecommand.h" #include "reparentinstancescommand.h" #include "update3dviewstatecommand.h" @@ -28,8 +25,7 @@ #include "removepropertiescommand.h" #include "valueschangedcommand.h" #include "informationchangedcommand.h" -#include "pixmapchangedcommand.h" -#include "commondefines.h" +#include "imagecontainer.h" #include "changestatecommand.h" #include "childrenchangedcommand.h" #include "completecomponentcommand.h" @@ -44,7 +40,6 @@ #include "requestmodelnodepreviewimagecommand.h" #include "changeauxiliarycommand.h" -#include "dummycontextobject.h" #include "../editor3d/generalhelper.h" #include "../editor3d/mousearea3d.h" #include "../editor3d/camerageometry.h" @@ -2775,15 +2770,21 @@ void Qt5InformationNodeInstanceServer::handlePickTarget( if (checkNode->property("_pickTarget").isNull()) { if (checkRepeater) { QObject::connect(checkRepeater, &QQuick3DRepeater::objectAdded, - this, &Qt5InformationNodeInstanceServer::handleDynamicAddObject); + this, [this, checkNode] { + handleDynamicAddObject(checkNode); + }); #if defined(QUICK3D_ASSET_UTILS_MODULE) } else if (checkRunLoader) { QObject::connect(checkRunLoader, &QQuick3DRuntimeLoader::statusChanged, - this, &Qt5InformationNodeInstanceServer::handleDynamicAddObject); + this, [this, checkNode] { + handleDynamicAddObject(checkNode); + }); #endif } else { QObject::connect(checkLoader, &QQuick3DLoader::loaded, - this, &Qt5InformationNodeInstanceServer::handleDynamicAddObject); + this, [this, checkNode] { + handleDynamicAddObject(checkNode); + }); } } checkNode->setProperty("_pickTarget", QVariant::fromValue(obj)); @@ -2804,9 +2805,9 @@ bool Qt5InformationNodeInstanceServer::isInformationServer() const // This method should be connected to signals indicating a new object has been constructed outside // normal scene creation. E.g. QQuick3DRepeater::objectAdded. -void Qt5InformationNodeInstanceServer::handleDynamicAddObject() +void Qt5InformationNodeInstanceServer::handleDynamicAddObject(QObject *object) { - m_dynamicObjectConstructors.insert(sender()); + m_dynamicObjectConstructors.insert(object); m_dynamicAddObjectTimer.start(); } diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.h index b603bb134eb..cb7dd20a96e 100644 --- a/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.h +++ b/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.h @@ -8,8 +8,6 @@ #include "valueschangedcommand.h" #include "changeselectioncommand.h" #include "requestmodelnodepreviewimagecommand.h" -#include "propertybindingcontainer.h" -#include "propertyabstractcontainer.h" #include "animationdriver.h" #ifdef QUICK3D_PARTICLES_MODULE @@ -61,7 +59,7 @@ public: void handlePickTarget(const ServerNodeInstance &instance) override; bool isInformationServer() const override; - void handleDynamicAddObject(); + void handleDynamicAddObject(QObject *object); private slots: void handleSelectionChanged(const QVariant &objs); diff --git a/src/tools/qml2puppet/qml2puppet/instances/quick3dnodeinstance.cpp b/src/tools/qml2puppet/qml2puppet/instances/quick3dnodeinstance.cpp index 9ab66649cfa..938de00c5bd 100644 --- a/src/tools/qml2puppet/qml2puppet/instances/quick3dnodeinstance.cpp +++ b/src/tools/qml2puppet/qml2puppet/instances/quick3dnodeinstance.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "quick3dnodeinstance.h" -#include "qt5nodeinstanceserver.h" #include "qt5informationnodeinstanceserver.h" #ifdef QUICK3D_MODULE @@ -50,16 +49,16 @@ void Quick3DNodeInstance::initialize( #endif if (auto infoServer = qobject_cast(nodeInstanceServer())) { if (repObj) { - QObject::connect(repObj, &QQuick3DRepeater::objectAdded, - infoServer, &Qt5InformationNodeInstanceServer::handleDynamicAddObject); + QObject::connect(repObj, &QQuick3DRepeater::objectAdded, infoServer, + [infoServer, obj] { infoServer->handleDynamicAddObject(obj); }); #if defined(QUICK3D_ASSET_UTILS_MODULE) } else if (runLoadObj) { - QObject::connect(runLoadObj, &QQuick3DRuntimeLoader::statusChanged, - infoServer, &Qt5InformationNodeInstanceServer::handleDynamicAddObject); + QObject::connect(runLoadObj, &QQuick3DRuntimeLoader::statusChanged, infoServer, + [infoServer, obj] { infoServer->handleDynamicAddObject(obj); }); #endif } else { - QObject::connect(loadObj, &QQuick3DLoader::loaded, - infoServer, &Qt5InformationNodeInstanceServer::handleDynamicAddObject); + QObject::connect(loadObj, &QQuick3DLoader::loaded, infoServer, + [infoServer, obj] { infoServer->handleDynamicAddObject(obj); }); } } } From 4d042e5b7d31cc2ad5b4191f3a2d654228c4bf07 Mon Sep 17 00:00:00 2001 From: Johanna Vanhatapio Date: Thu, 7 Dec 2023 16:56:06 +0200 Subject: [PATCH 099/101] Doc: Update info on baking lights Fixes: QDS-11174 Change-Id: I8f92c3cca0faaa3f4b1db11caa8825677c80121e Reviewed-by: Miikka Heikkinen Reviewed-by: Mats Honkamaa Reviewed-by: Qt CI Patch Build Bot --- .../images/icons/bakelights.png | Bin 0 -> 502 bytes .../qtdesignstudio-3d-editor.qdoc | 7 ++ .../qtdesignstudio-3d-lights.qdoc | 62 ++++++++++-------- 3 files changed, 43 insertions(+), 26 deletions(-) create mode 100644 doc/qtdesignstudio/images/icons/bakelights.png diff --git a/doc/qtdesignstudio/images/icons/bakelights.png b/doc/qtdesignstudio/images/icons/bakelights.png new file mode 100644 index 0000000000000000000000000000000000000000..21ca61375669785d6c1b46540e92c85dc02633f4 GIT binary patch literal 502 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!s7I14-?iy0XBj({-ZRBb+K z1_lQ95>H=O_UAl2oRR_uuLfRVU|^i;>Eak-(OY|YZ+1wa0PBbQdeS0-TLicjy_)1* zn^Y1!q`5hxqB_FD#JVClnj+?&3KD4Qt#{B`9a840+|kPDxZ%PK4Gl9VgI3QoQEzfS z-Ed%gHurbhxjE*=?{}|NkuN+luhz?m+cQq&o_0+y_tEUc#Z#YHPy5Il?J1`cc_ed7 z_nzjhD#o7A3|fL`yb1Y~J?Zz?si|`gNZCy}A#qME($6Sx&vA+O3%Zjhue3FjZ%!87>V*f?@9-K}n9=Xp6XUpt z8B5IyWM_LW)4rBlc0ok);_WlhJHqOOtv%hOuf#U4yEoC~ZRNut%QL(MxBd$5`e8mn z=5X1h+gGo4?X|wJ{oFg}_uF%C#q+4nT>o7$hp*t;#aHpmzW-Qh{yS^Za?g7YQzq7{ z&h+}ka#&RQn9J@ddXKo$3U}U`cZf+WYi&{Z>Ej#!$$vQAJL6`Vpeh3c1B0ilpUXO@ GgeCw0KiJOz literal 0 HcmV?d00001 diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc index 4c45f87ad8b..7111d2db90e 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc @@ -153,6 +153,13 @@ For more information about the available scene light types and their properties, see \l{Lights}. + \section1 Baking Lights + + Bake lights to light static elements in your scene. To bake lights, + select \inlineimage icons/bakelights.png to open the + \uicontrol {Lights Baking Setup} dialog. For more information, see + \l {Baking Lightmaps}. + \section1 Selecting Components To move, rotate, or scale components in the scene, you need to select them diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc index ec1de943f2b..af994d58774 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc @@ -213,10 +213,11 @@ \note Lightmaps baking is released as technical preview in \QDS 4.1. - Baked lightmaps allow pre-generating the direct lighting from lights such as DirectionalLight, - PointLight, and SpotLight, including the shadows cast by the lights. At run time, instead of - performing the appropriate calculations in the fragment shader, and, in case of shadows, - generating the potentially costly shadow maps in real time, the pre-generated light map is + Baked lightmaps allow pre-generating the direct lighting from lights, + such as DirectionalLight, PointLight, and SpotLight, including the shadows + cast by the lights. At run time, instead of performing the appropriate + calculations in the fragment shader, and, in case of shadows, generating + the potentially costly shadow maps in real time, the pre-generated light map is sampled instead. \section2 Baking Lightmaps @@ -224,47 +225,56 @@ To bake lightmaps for models in your 3D scene: \list 1 - \li Right-click anywhere in the \uicontrol 3D view and select \uicontrol {Bake Lights}. - \li In the \uicontrol {Lights Baking Setup} dialog: + \li Select \inlineimage icons/bakelights.png in the \uicontrol 3D view + toolbar or right-click anywhere in the \uicontrol 3D view and select + \uicontrol {Bake Lights} to open the \uicontrol {Lights Baking Setup} + dialog to define settings for baking lights. + \li Set \uicontrol {Bake Mode} for each light source: \list - \li For every light you want to use to bake lightmaps, set \uicontrol {Bake Mode} to BakeModeAll. - \li For every 3D model you want to bake lightmaps, select \uicontrol {In Use} and - \uicontrol {Enabled}, and set the desired \uicontrol {Resolution}. + \li To bake both direct (diffuse and shadow) and indirect lighting, + select \uicontrol {Bake All}. + \li To bake only indirect lighting, select \uicontrol {Bake Indirect}. + \li To not include a light source in the baking of lights, select + \uicontrol {Baking Disabled}. \endlist - \li Optional. If you have components with unexposed models or lights (for example, imported - 3D models created in other software), select \uicontrol {Expose models and lights} to add the - models and light of that component to the \uicontrol Models and \uicontrol Lights sections of - the dialog. + \li For every 3D model you want to bake into a lightmap, select + \uicontrol {In Use} and \uicontrol {Enabled}, and set the desired + \uicontrol {Resolution}. + \li Optional. If you have components with unexposed models or lights + (for example, imported 3D models created in other software), select + \uicontrol {Expose models and lights} to add the models and light of + that component to the \uicontrol Models and \uicontrol Lights sections + of the dialog. \li Select \uicontrol Bake. \endlist \image bake-lights-dialog.png \section2 Manually Baking Lightmaps for a 3D Model - Baked lightmap components are not visible in the \uicontrol Navigator view by default. To make - them visible, select \inlineimage icons/visibilityon.png + \note Baked lightmap components are not visible in the \uicontrol Navigator view by + default. To make them visible, select \inlineimage icons/visibilityon.png in the \uicontrol Navigator view. To bake lightmaps for a 3D model: \list 1 - \li From \uicontrol Components, drag a \uicontrol {Baked Lightmap} component to - the 3D model in the \uicontrol Navigator view. + \li From \uicontrol Components, drag a \uicontrol {Baked Lightmap} component + to the 3D model in the \uicontrol Navigator view. \image baked-lightmaps-navigator.png - \li In the \uicontrol Navigator view, select \e bakedLightmap and in the \uicontrol Properties - view: + \li In the \uicontrol Navigator view, select \e bakedLightmap, and in the + \uicontrol Properties view: \list \li Select \uicontrol Enabled. - \li In \uicontrol Key, set the filename base for the generated light maps. This must be - a unique name. - \li In \uicontrol {Load Prefix}, set the relative path to the folder where the generated - light map files are saved. + \li In \uicontrol Key, set the filename base for the generated light maps. + This must be a unique name. + \li In \uicontrol {Load Prefix}, set the relative path to the folder where + the generated light map files are saved. \endlist \li In the \uicontrol Navigator view, select the 3D model and in the \uicontrol Properties - view, select \uicontrol {Used in Baked Lighting}. + view, select \uicontrol {Used in Baked Lighting}. \li Optional. Adjust \uicontrol Resolution to set the light map resoution. This effects how - accurate and time-consuming the lightmap baking is. + accurate and time-consuming the lightmap baking is. \li In the \uicontrol Navigator view, select the light component that you want to bake - lightmaps for, and in the \uicontrol Properties view, set \uicontrol {Bake Mode} to BakeModeAll. + lightmaps for, and in the \uicontrol Properties view, set \uicontrol {Bake Mode} to BakeModeAll. \li Right-click anywhere in the \uicontrol 3D view and select \uicontrol {Bake Lights}. \li Select \uicontrol {Setup baking manually}, and then select \uicontrol Bake. \endlist From 6b6f74ccadac8da397bffee2719129fee2370621 Mon Sep 17 00:00:00 2001 From: Shrief Gabr Date: Thu, 14 Dec 2023 13:52:48 +0200 Subject: [PATCH 100/101] QmlDesigner: Create data type warnings for CollectionDetailsModel Task-number: QDS-11079 Change-Id: I8cb5167d71ff96d01313bc559401e16f0925afbb Reviewed-by: Miikka Heikkinen Reviewed-by: Ali Kianian Reviewed-by: Mahmoud Badri --- .../CollectionDetailsView.qml | 16 +++++++++--- .../collectioneditor/collectiondetails.cpp | 14 +++++++++++ .../collectioneditor/collectiondetails.h | 21 ++++++++++++++++ .../collectiondetailsmodel.cpp | 25 ++++++++++++++++--- .../collectioneditor/collectiondetailsmodel.h | 5 ++-- 5 files changed, 72 insertions(+), 9 deletions(-) diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml index d2c7f17ca33..e208553a4c5 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/CollectionDetailsView.qml @@ -4,6 +4,7 @@ import QtQuick import QtQuick.Controls import QtQuick.Layouts +import CollectionDetails 1.0 as CollectionDetails import HelperWidgets 2.0 as HelperWidgets import StudioTheme 1.0 as StudioTheme import StudioControls 1.0 as StudioControls @@ -207,13 +208,23 @@ Rectangle { id: itemCell implicitWidth: 100 implicitHeight: itemText.height + border.color: dataTypeWarning !== CollectionDetails.Warning.None ? + StudioTheme.Values.themeWarning : StudioTheme.Values.themeControlBackgroundInteraction border.width: 1 + HelperWidgets.ToolTipArea { + anchors.fill: parent + text: root.model.warningToString(dataTypeWarning) + enabled: dataTypeWarning !== CollectionDetails.Warning.None && text !== "" + hoverEnabled: true + acceptedButtons: Qt.NoButton + } + Text { id: itemText - text: display ? display : "" - + text: display + color: StudioTheme.Values.themePlaceholderTextColorInteraction width: parent.width leftPadding: 5 topPadding: 3 @@ -239,7 +250,6 @@ Rectangle { PropertyChanges { target: itemCell color: StudioTheme.Values.themeControlBackground - border.color: StudioTheme.Values.themeControlBackgroundInteraction } PropertyChanges { diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp index e0bc86f99f6..98eef0daea2 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.cpp @@ -22,6 +22,10 @@ struct CollectionProperty DataType type; }; +const QMap DataTypeWarning::dataTypeWarnings = { + {DataTypeWarning::CellDataTypeMismatch, "Cell and column data types do not match."} +}; + class CollectionDetails::Private { using SourceFormat = CollectionEditor::SourceFormat; @@ -345,6 +349,13 @@ CollectionDetails::DataType CollectionDetails::typeAt(int row, int column) const return {}; } +DataTypeWarning::Warning CollectionDetails::cellWarningCheck(int row, int column) const +{ + if (typeAt(column) != typeAt(row, column) && !d->elements.at(row).isEmpty()) + return DataTypeWarning::Warning::CellDataTypeMismatch; + return DataTypeWarning::Warning::None; +} + bool CollectionDetails::containsPropertyName(const QString &propertyName) { if (!isValid()) @@ -394,6 +405,9 @@ void CollectionDetails::registerDeclarativeType() typedef CollectionDetails::DataType DataType; qRegisterMetaType("DataType"); qmlRegisterUncreatableType("CollectionDetails", 1, 0, "DataType", "Enum type"); + + qRegisterMetaType("Warning"); + qmlRegisterUncreatableType("CollectionDetails", 1, 0, "Warning", "Enum type"); } CollectionDetails &CollectionDetails::operator=(const CollectionDetails &other) diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h index 694947b126a..c35068ce6f0 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetails.h @@ -35,6 +35,26 @@ struct CollectionReference struct CollectionProperty; +struct DataTypeWarning { + Q_GADGET + +public: + enum Warning { None, CellDataTypeMismatch }; + Q_ENUM(Warning) + + Warning warning = None; + DataTypeWarning(Warning warning) + : warning(warning) + {} + + static QString getDataTypeWarningString(Warning warning) { + return dataTypeWarnings.value(warning); + } + +private: + static const QMap dataTypeWarnings; +}; + class CollectionDetails { Q_GADGET @@ -71,6 +91,7 @@ public: QString propertyAt(int column) const; DataType typeAt(int column) const; DataType typeAt(int row, int column) const; + DataTypeWarning::Warning cellWarningCheck(int row, int column) const; bool containsPropertyName(const QString &propertyName); bool isValid() const; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp index 49398b2aea2..533c2d72b6c 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp @@ -102,6 +102,7 @@ QHash CollectionDetailsModel::roleNames() const roles.insert(SelectedRole, "itemSelected"); roles.insert(DataTypeRole, "dataType"); roles.insert(ColumnDataTypeRole, "columnType"); + roles.insert(DataTypeWarningRole, "dataTypeWarning"); } return roles; } @@ -133,6 +134,9 @@ QVariant CollectionDetailsModel::data(const QModelIndex &index, int role) const if (role == Qt::EditRole) return m_currentCollection.data(index.row(), index.column()); + if (role == DataTypeWarningRole ) + return QVariant::fromValue(m_currentCollection.cellWarningCheck(index.row(), index.column())); + return m_currentCollection.data(index.row(), index.column()).toString(); } @@ -142,11 +146,19 @@ bool CollectionDetailsModel::setData(const QModelIndex &index, const QVariant &v return {}; if (role == Qt::EditRole) { + DataTypeWarning::Warning prevWarning = m_currentCollection.cellWarningCheck(index.row(), index.column()); bool changed = m_currentCollection.setPropertyValue(index.row(), index.column(), value); + if (changed) { - emit dataChanged(index, index, {Qt::DisplayRole, Qt::EditRole}); - return true; + QList roles = {Qt::DisplayRole, Qt::EditRole}; + + if (prevWarning != m_currentCollection.cellWarningCheck(index.row(), index.column())) + roles << DataTypeWarningRole; + + emit dataChanged(index, index, roles); } + + return true; } return false; @@ -326,7 +338,8 @@ bool CollectionDetailsModel::setPropertyType(int column, const QString &newValue newValue)); if (changed) { emit headerDataChanged(Qt::Horizontal, column, column); - emit dataChanged(index(0, column), index(rowCount() - 1, column), {Qt::DisplayRole, DataTypeRole}); + emit dataChanged(index(0, column), index(rowCount() - 1, column), + {Qt::DisplayRole, DataTypeRole, DataTypeWarningRole}); } return changed; @@ -623,4 +636,10 @@ bool CollectionDetailsModel::saveCollectionFromString(const QString &path, const return false; } +QString CollectionDetailsModel::warningToString(DataTypeWarning::Warning warning) const +{ + return DataTypeWarning::getDataTypeWarningString(warning); +} + + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h index 78fab1685f9..bf87d3838f1 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.h @@ -22,8 +22,7 @@ class CollectionDetailsModel : public QAbstractTableModel Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged) public: - enum DataRoles { SelectedRole = Qt::UserRole + 1, DataTypeRole, ColumnDataTypeRole }; - + enum DataRoles { SelectedRole = Qt::UserRole + 1, DataTypeRole, ColumnDataTypeRole, DataTypeWarningRole }; explicit CollectionDetailsModel(QObject *parent = nullptr); QHash roleNames() const override; @@ -58,7 +57,7 @@ public: Q_INVOKABLE bool setPropertyType(int column, const QString &newValue); Q_INVOKABLE bool selectRow(int row); Q_INVOKABLE void deselectAll(); - + Q_INVOKABLE QString warningToString(DataTypeWarning::Warning warning) const; static Q_INVOKABLE QStringList typesList(); void loadCollection(const ModelNode &sourceNode, const QString &collection); From dc42b62ddf3fbd41bf5b16922e77de6bb6cdaafc Mon Sep 17 00:00:00 2001 From: Mahmoud Badri Date: Thu, 7 Dec 2023 18:32:55 +0200 Subject: [PATCH 101/101] Effect Maker: Enable helper nodes Helper nodes are nodes that another node depends on and are added automatically when the depending node is added. Helper nodes are placed before all other nodes. Helper nodes that do not contain any properties are not shown. Helper nodes keep reference count and are removed when last referring node is removed. Task-number: QDS-11193 Change-Id: I036019afb1414ec6e98b2f949a18bd217753a910 Reviewed-by: Mahmoud Badri Reviewed-by: Qt CI Patch Build Bot --- .../effectMakerQmlSources/BlurHelper.qml | 68 ++++++++++++ .../EffectCompositionNode.qml | 8 +- .../effectMakerQmlSources/EffectMaker.qml | 3 +- .../EffectMakerPreview.qml | 7 ++ .../effectmakernew/compositionnode.cpp | 53 ++++++++- src/plugins/effectmakernew/compositionnode.h | 13 ++- .../effectmakernew/effectmakermodel.cpp | 103 ++++++++++++++++-- src/plugins/effectmakernew/effectmakermodel.h | 9 +- .../effectmakernew/effectmakernodesmodel.cpp | 14 +-- .../effectmakernew/effectmakerwidget.cpp | 6 + src/plugins/effectmakernew/effectutils.cpp | 11 ++ src/plugins/effectmakernew/effectutils.h | 2 + 12 files changed, 264 insertions(+), 33 deletions(-) create mode 100644 share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml new file mode 100644 index 00000000000..e68a0bc8a25 --- /dev/null +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml @@ -0,0 +1,68 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: BSD-3-Clause + +// This file should match the BlurHelper.qml in qtquickdesigner repository, except for shader paths + +import QtQuick + +Item { + id: rootItem + property alias blurSrc1: blurredItemSource1 + property alias blurSrc2: blurredItemSource2 + property alias blurSrc3: blurredItemSource3 + property alias blurSrc4: blurredItemSource4 + property alias blurSrc5: blurredItemSource5 + + component BlurItem: ShaderEffect { + property vector2d offset: Qt.vector2d((1.0 + rootItem.blurMultiplier) / width, + (1.0 + rootItem.blurMultiplier) / height) + visible: false + layer.enabled: true + layer.smooth: true + vertexShader: g_propertyData.blur_vs_path + fragmentShader: g_propertyData.blur_fs_path + } + + QtObject { + id: priv + property bool useBlurItem1: true + property bool useBlurItem2: rootItem.blurMax > 2 + property bool useBlurItem3: rootItem.blurMax > 8 + property bool useBlurItem4: rootItem.blurMax > 16 + property bool useBlurItem5: rootItem.blurMax > 32 + } + + BlurItem { + id: blurredItemSource1 + property Item src: priv.useBlurItem1 ? source : null + // Size of the first blurred item is by default half of the source. + // Increase for quality and decrease for performance & more blur. + readonly property int blurItemSize: 8 + width: src ? Math.ceil(src.width / 16) * blurItemSize : 0 + height: src ? Math.ceil(src.height / 16) * blurItemSize : 0 + } + BlurItem { + id: blurredItemSource2 + property Item src: priv.useBlurItem2 ? blurredItemSource1 : null + width: blurredItemSource1.width * 0.5 + height: blurredItemSource1.height * 0.5 + } + BlurItem { + id: blurredItemSource3 + property Item src: priv.useBlurItem3 ? blurredItemSource2 : null + width: blurredItemSource2.width * 0.5 + height: blurredItemSource2.height * 0.5 + } + BlurItem { + id: blurredItemSource4 + property Item src: priv.useBlurItem4 ? blurredItemSource3 : null + width: blurredItemSource3.width * 0.5 + height: blurredItemSource3.height * 0.5 + } + BlurItem { + id: blurredItemSource5 + property Item src: priv.useBlurItem5 ? blurredItemSource4 : null + width: blurredItemSource4.width * 0.5 + height: blurredItemSource4.height * 0.5 + } +} diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml index cf9c3d668b0..2ccaeaf36c3 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectCompositionNode.qml @@ -17,16 +17,17 @@ HelperWidgets.Section { caption: nodeName category: "EffectMaker" - draggable: true + draggable: !isDependency fillBackground: true - showCloseButton: true + showCloseButton: !isDependency closeButtonToolTip: qsTr("Remove") + visible: repeater.count > 0 || !isDependency onCloseButtonClicked: { EffectMakerBackend.effectMakerModel.removeNode(root.modelIndex) } - showEyeButton: true + showEyeButton: !isDependency eyeEnabled: nodeEnabled eyeButtonToolTip: qsTr("Enable/Disable Node") @@ -38,6 +39,7 @@ HelperWidgets.Section { spacing: 10 Repeater { + id: repeater model: nodeUniformsModel EffectCompositionNodeUniform { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml index 81be29f9ae2..d3ccb36a749 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMaker.qml @@ -213,7 +213,8 @@ Item { currItem.y = root.secsY[i] } } else if (i < root.moveFromIdx) { - if (root.draggedSec.y < currItem.y + (currItem.height - root.draggedSec.height) * .5) { + if (!repeater.model.isDependencyNode(i) + && root.draggedSec.y < currItem.y + (currItem.height - root.draggedSec.height) * .5) { currItem.y = root.secsY[i] + root.draggedSec.height root.moveToIdx = Math.min(root.moveToIdx, i) } else { diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml index 4636159f481..ea0b2d12954 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/EffectMakerPreview.qml @@ -194,6 +194,13 @@ Column { } } + BlurHelper { + id: blurHelper + anchors.fill: parent + property int blurMax: g_propertyData.blur_helper_max_level ? g_propertyData.blur_helper_max_level : 64 + property real blurMultiplier: g_propertyData.blurMultiplier ? g_propertyData.blurMultiplier : 0 + } + Item { id: componentParent width: source.width diff --git a/src/plugins/effectmakernew/compositionnode.cpp b/src/plugins/effectmakernew/compositionnode.cpp index 8cd5bda971e..9520e50d050 100644 --- a/src/plugins/effectmakernew/compositionnode.cpp +++ b/src/plugins/effectmakernew/compositionnode.cpp @@ -14,7 +14,8 @@ namespace EffectMaker { -CompositionNode::CompositionNode(const QString &effectName, const QString &qenPath, const QJsonObject &jsonObject) +CompositionNode::CompositionNode(const QString &effectName, const QString &qenPath, + const QJsonObject &jsonObject) { QJsonObject json; if (jsonObject.isEmpty()) { @@ -58,6 +59,11 @@ QString CompositionNode::description() const return m_description; } +QString CompositionNode::id() const +{ + return m_id; +} + QObject *CompositionNode::uniformsModel() { return &m_unifomrsModel; @@ -81,6 +87,11 @@ void CompositionNode::setIsEnabled(bool newIsEnabled) } } +bool CompositionNode::isDependency() const +{ + return m_refCount > 0; +} + CompositionNode::NodeType CompositionNode::type() const { return m_type; @@ -102,6 +113,13 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c m_fragmentCode = EffectUtils::codeFromJsonArray(json.value("fragmentCode").toArray()); m_vertexCode = EffectUtils::codeFromJsonArray(json.value("vertexCode").toArray()); + m_id = json.value("id").toString(); + if (m_id.isEmpty() && !qenPath.isEmpty()) { + QString fileName = qenPath.split('/').last(); + fileName.chop(4); // remove ".qen" + m_id = fileName; + } + // parse properties QJsonArray jsonProps = json.value("properties").toArray(); for (const auto /*QJsonValueRef*/ &prop : jsonProps) { @@ -118,8 +136,7 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c for (const QString &codeLine : std::as_const(shaderCodeLines)) { QString trimmedLine = codeLine.trimmed(); if (trimmedLine.startsWith("@requires")) { - // Get the required node, remove "@requires" - QString l = trimmedLine.sliced(9).trimmed(); + // Get the required node, remove "@requires " QString nodeName = trimmedLine.sliced(10); if (!nodeName.isEmpty() && !m_requiredNodes.contains(nodeName)) m_requiredNodes << nodeName; @@ -132,6 +149,36 @@ QList CompositionNode::uniforms() const return m_uniforms; } +int CompositionNode::incRefCount() +{ + ++m_refCount; + + if (m_refCount == 1) + emit isDepencyChanged(); + + return m_refCount; +} + +int CompositionNode::decRefCount() +{ + --m_refCount; + + if (m_refCount == 0) + emit isDepencyChanged(); + + return m_refCount; +} + +void CompositionNode::setRefCount(int count) +{ + bool notifyChange = (m_refCount > 0 && count == 0) || (m_refCount <= 0 && count > 0); + + m_refCount = count; + + if (notifyChange) + emit isDepencyChanged(); +} + QString CompositionNode::name() const { return m_name; diff --git a/src/plugins/effectmakernew/compositionnode.h b/src/plugins/effectmakernew/compositionnode.h index 4736f1d8afa..04f5dd5c02b 100644 --- a/src/plugins/effectmakernew/compositionnode.h +++ b/src/plugins/effectmakernew/compositionnode.h @@ -15,7 +15,8 @@ class CompositionNode : public QObject Q_OBJECT Q_PROPERTY(QString nodeName MEMBER m_name CONSTANT) - Q_PROPERTY(bool nodeEnabled READ isEnabled WRITE setIsEnabled NOTIFY isEnabledChanged) + 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) public: @@ -30,6 +31,7 @@ public: QString fragmentCode() const; QString vertexCode() const; QString description() const; + QString id() const; QObject *uniformsModel(); @@ -40,13 +42,20 @@ public: bool isEnabled() const; void setIsEnabled(bool newIsEnabled); + bool isDependency() const; + QString name() const; QList uniforms() const; + int incRefCount(); + int decRefCount(); + void setRefCount(int count); + signals: void uniformsModelChanged(); void isEnabledChanged(); + void isDepencyChanged(); private: void parse(const QString &effectName, const QString &qenPath, const QJsonObject &json); @@ -57,7 +66,9 @@ private: QString m_vertexCode; QString m_description; QStringList m_requiredNodes; + QString m_id; bool m_isEnabled = true; + int m_refCount = 0; QList m_uniforms; diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index e13e2e39a9a..fbb439ff17d 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -4,6 +4,8 @@ #include "effectmakermodel.h" #include "compositionnode.h" +#include "effectutils.h" +#include "propertyhandler.h" #include "syntaxhighlighterdata.h" #include "uniform.h" @@ -58,6 +60,7 @@ QHash EffectMakerModel::roleNames() const roles[NameRole] = "nodeName"; roles[EnabledRole] = "nodeEnabled"; roles[UniformsRole] = "nodeUniformsModel"; + roles[Dependency] = "isDependency"; return roles; } @@ -104,14 +107,29 @@ void EffectMakerModel::setIsEmpty(bool val) void EffectMakerModel::addNode(const QString &nodeQenPath) { - beginInsertRows({}, m_nodes.size(), m_nodes.size()); - auto *node = new CompositionNode("", nodeQenPath); + beginResetModel(); + auto *node = new CompositionNode({}, nodeQenPath); connect(qobject_cast(node->uniformsModel()), &EffectMakerUniformsModel::dataChanged, this, [this] { - setHasUnsavedChanges(true); - }); + setHasUnsavedChanges(true); + }); + + const QList requiredNodes = node->requiredNodes(); + if (requiredNodes.size() > 0) { + for (const QString &requiredId : requiredNodes) { + if (auto reqNode = findNodeById(requiredId)) { + reqNode->incRefCount(); + continue; + } + + const QString path = EffectUtils::nodesSourcesPath() + "/common/" + requiredId + ".qen"; + auto requiredNode = new CompositionNode({}, path); + requiredNode->setRefCount(1); + m_nodes.prepend(requiredNode); + } + } m_nodes.append(node); - endInsertRows(); + endResetModel(); setIsEmpty(false); @@ -121,6 +139,15 @@ void EffectMakerModel::addNode(const QString &nodeQenPath) emit nodesChanged(); } +CompositionNode *EffectMakerModel::findNodeById(const QString &id) const +{ + for (CompositionNode *node : std::as_const(m_nodes)) { + if (node->id() == id) + return node; + } + return {}; +} + void EffectMakerModel::moveNode(int fromIdx, int toIdx) { if (fromIdx == toIdx) @@ -137,10 +164,20 @@ void EffectMakerModel::moveNode(int fromIdx, int toIdx) void EffectMakerModel::removeNode(int idx) { - beginRemoveRows({}, idx, idx); + beginResetModel(); CompositionNode *node = m_nodes.takeAt(idx); + + const QStringList reqNodes = node->requiredNodes(); + for (const QString &reqId : reqNodes) { + CompositionNode *depNode = findNodeById(reqId); + if (depNode && depNode->decRefCount() <= 0) { + m_nodes.removeOne(depNode); + delete depNode; + } + } + delete node; - endRemoveRows(); + endResetModel(); if (m_nodes.isEmpty()) setIsEmpty(true); @@ -442,6 +479,8 @@ QJsonObject nodeToJson(const CompositionNode &node) nodeObject.insert("description", node.description()); nodeObject.insert("enabled", node.isEnabled()); nodeObject.insert("version", 1); + nodeObject.insert("id", node.id()); + // Add properties QJsonArray propertiesArray; const QList uniforms = node.uniforms(); @@ -549,7 +588,17 @@ QString EffectMakerModel::getQmlEffectString() s += '\n'; } - //TODO: Blue stuff goes here + if (m_shaderFeatures.enabled(ShaderFeatures::BlurSources)) { + s += " BlurHelper {\n"; + s += " id: blurHelper\n"; + s += " anchors.fill: parent\n"; + int blurMax = 32; + if (g_propertyData.contains("BLUR_HELPER_MAX_LEVEL")) + blurMax = g_propertyData["BLUR_HELPER_MAX_LEVEL"].toInt(); + s += QString(" property int blurMax: %1\n").arg(blurMax); + s += " property real blurMultiplier: rootItem.blurMultiplier\n"; + s += " }\n"; + } s += getQmlComponentString(true); s += "}\n"; @@ -643,18 +692,30 @@ void EffectMakerModel::openComposition(const QString &path) } if (json.contains("nodes") && json["nodes"].isArray()) { + beginResetModel(); + QHash refCounts; const QJsonArray nodesArray = json["nodes"].toArray(); + for (const auto &nodeElement : nodesArray) { - beginInsertRows({}, m_nodes.size(), m_nodes.size()); - auto *node = new CompositionNode(effectName, "", nodeElement.toObject()); + auto *node = new CompositionNode(effectName, {}, nodeElement.toObject()); connect(qobject_cast(node->uniformsModel()), &EffectMakerUniformsModel::dataChanged, this, [this] { setHasUnsavedChanges(true); }); m_nodes.append(node); - endInsertRows(); + const QStringList reqIds = node->requiredNodes(); + for (const QString &reqId : reqIds) + ++refCounts[reqId]; } + for (auto it = refCounts.cbegin(), end = refCounts.cend(); it != end; ++it) { + CompositionNode *depNode = findNodeById(it.key()); + if (depNode) + depNode->setRefCount(it.value()); + } + + endResetModel(); + setIsEmpty(m_nodes.isEmpty()); bakeShaders(); } @@ -748,6 +809,19 @@ void EffectMakerModel::saveResources(const QString &name) } } + if (m_shaderFeatures.enabled(ShaderFeatures::BlurSources)) { + QString blurHelperFilename("BlurHelper.qml"); + QString blurFsFilename("bluritems.frag.qsb"); + QString blurVsFilename("bluritems.vert.qsb"); + QString blurHelperPath(EffectUtils::nodesSourcesPath() + "/common/"); + sources.append(blurHelperPath + blurHelperFilename); + sources.append(blurHelperPath + blurFsFilename); + sources.append(blurHelperPath + blurVsFilename); + dests.append(blurHelperFilename); + dests.append(blurFsFilename); + dests.append(blurVsFilename); + } + for (int i = 0; i < sources.count(); ++i) { Utils::FilePath source = Utils::FilePath::fromString(sources[i]); Utils::FilePath target = Utils::FilePath::fromString(effectsResPath + dests[i]); @@ -1505,6 +1579,13 @@ QStringList EffectMakerModel::uniformNames() const return usedList; } +bool EffectMakerModel::isDependencyNode(int index) const +{ + if (m_nodes.size() > index) + return m_nodes[index]->isDependency(); + return false; +} + void EffectMakerModel::updateQmlComponent() { // Clear possible QML runtime errors diff --git a/src/plugins/effectmakernew/effectmakermodel.h b/src/plugins/effectmakernew/effectmakermodel.h index 7f73ed4cdca..a25a4e40913 100644 --- a/src/plugins/effectmakernew/effectmakermodel.h +++ b/src/plugins/effectmakernew/effectmakermodel.h @@ -7,10 +7,10 @@ #include +#include #include #include #include -#include #include namespace ProjectExplorer { @@ -62,6 +62,8 @@ public: void addNode(const QString &nodeQenPath); + CompositionNode *findNodeById(const QString &id) const; + Q_INVOKABLE void moveNode(int fromIdx, int toIdx); Q_INVOKABLE void removeNode(int idx); Q_INVOKABLE void clear(); @@ -96,6 +98,8 @@ public: QStringList uniformNames() const; + Q_INVOKABLE bool isDependencyNode(int index) const; + signals: void isEmptyChanged(); void selectedIndexChanged(int idx); @@ -112,7 +116,8 @@ private: enum Roles { NameRole = Qt::UserRole + 1, EnabledRole, - UniformsRole + UniformsRole, + Dependency }; enum ErrorTypes { diff --git a/src/plugins/effectmakernew/effectmakernodesmodel.cpp b/src/plugins/effectmakernew/effectmakernodesmodel.cpp index c6773faa090..7f35e935ba9 100644 --- a/src/plugins/effectmakernew/effectmakernodesmodel.cpp +++ b/src/plugins/effectmakernew/effectmakernodesmodel.cpp @@ -2,8 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "effectmakernodesmodel.h" - -#include +#include "effectutils.h" #include #include @@ -41,21 +40,12 @@ QVariant EffectMakerNodesModel::data(const QModelIndex &index, int role) const return m_categories.at(index.row())->property(roleNames().value(role)); } -QString EffectMakerNodesModel::nodesSourcesPath() const -{ -#ifdef SHARE_QML_PATH - if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) - return QLatin1String(SHARE_QML_PATH) + "/effectMakerNodes"; -#endif - return Core::ICore::resourcePath("qmldesigner/effectMakerNodes").toString(); -} - void EffectMakerNodesModel::loadModel() { if (m_modelLoaded) return; - auto nodesPath = Utils::FilePath::fromString(nodesSourcesPath()); + auto nodesPath = Utils::FilePath::fromString(EffectUtils::nodesSourcesPath()); if (!nodesPath.exists()) { qWarning() << __FUNCTION__ << "Effects not found."; diff --git a/src/plugins/effectmakernew/effectmakerwidget.cpp b/src/plugins/effectmakernew/effectmakerwidget.cpp index db549501f37..5151c0568ca 100644 --- a/src/plugins/effectmakernew/effectmakerwidget.cpp +++ b/src/plugins/effectmakernew/effectmakerwidget.cpp @@ -7,6 +7,7 @@ #include "effectmakermodel.h" #include "effectmakernodesmodel.h" #include "effectmakerview.h" +#include "effectutils.h" #include "propertyhandler.h" //#include "qmldesigner/designercore/imagecache/midsizeimagecacheprovider.h" @@ -61,6 +62,7 @@ EffectMakerWidget::EffectMakerWidget(EffectMakerView *view) m_quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView); QmlDesigner::Theme::setupTheme(m_quickWidget->engine()); m_quickWidget->engine()->addImportPath(propertyEditorResourcesPath() + "/imports"); + m_quickWidget->engine()->addImportPath(EffectUtils::nodesSourcesPath() + "/common"); m_quickWidget->setClearColor(QmlDesigner::Theme::getColor( QmlDesigner::Theme::Color::QmlDesigner_BackgroundColorDarkAlternate)); @@ -76,6 +78,10 @@ EffectMakerWidget::EffectMakerWidget(EffectMakerView *view) m_quickWidget->rootContext()->setContextProperty("g_propertyData", &g_propertyData); + QString blurPath = "file:" + EffectUtils::nodesSourcesPath() + "/common/"; + g_propertyData.insert(QString("blur_vs_path"), QString(blurPath + "bluritems.vert.qsb")); + g_propertyData.insert(QString("blur_fs_path"), QString(blurPath + "bluritems.frag.qsb")); + auto map = m_quickWidget->registerPropertyMap("EffectMakerBackend"); map->setProperties({{"effectMakerNodesModel", QVariant::fromValue(m_effectMakerNodesModel.data())}, {"effectMakerModel", QVariant::fromValue(m_effectMakerModel.data())}, diff --git a/src/plugins/effectmakernew/effectutils.cpp b/src/plugins/effectmakernew/effectutils.cpp index 8e2bb625431..a0159c520da 100644 --- a/src/plugins/effectmakernew/effectutils.cpp +++ b/src/plugins/effectmakernew/effectutils.cpp @@ -3,6 +3,8 @@ #include "effectutils.h" +#include + #include namespace EffectMaker { @@ -20,5 +22,14 @@ QString EffectUtils::codeFromJsonArray(const QJsonArray &codeArray) return codeString; } +QString EffectUtils::nodesSourcesPath() +{ +#ifdef SHARE_QML_PATH + if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE")) + return QLatin1String(SHARE_QML_PATH) + "/effectMakerNodes"; +#endif + return Core::ICore::resourcePath("qmldesigner/effectMakerNodes").toString(); +} + } // namespace EffectMaker diff --git a/src/plugins/effectmakernew/effectutils.h b/src/plugins/effectmakernew/effectutils.h index e3de9312dce..eede7952c5c 100644 --- a/src/plugins/effectmakernew/effectutils.h +++ b/src/plugins/effectmakernew/effectutils.h @@ -15,6 +15,8 @@ public: EffectUtils() = delete; static QString codeFromJsonArray(const QJsonArray &codeArray); + + static QString nodesSourcesPath(); }; } // namespace EffectMaker