diff --git a/doc/qtcreator/src/editors/creator-code-refactoring.qdoc b/doc/qtcreator/src/editors/creator-code-refactoring.qdoc index 37f45c5b259..285ab394799 100644 --- a/doc/qtcreator/src/editors/creator-code-refactoring.qdoc +++ b/doc/qtcreator/src/editors/creator-code-refactoring.qdoc @@ -3,7 +3,7 @@ /*! \page creator-editor-refactoring.html - \previouspage creator-editor-locator.html + \previouspage creator-jump-to-the-code.html \nextpage creator-editor-quick-fixes.html \title Refactoring diff --git a/doc/qtcreator/src/editors/creator-finding.qdoc b/doc/qtcreator/src/editors/creator-finding.qdoc index 71bdd340085..d2eda6bd227 100644 --- a/doc/qtcreator/src/editors/creator-finding.qdoc +++ b/doc/qtcreator/src/editors/creator-finding.qdoc @@ -37,6 +37,14 @@ through projects, files, classes, functions, documentation and file systems. + \li \l{Jump to the Code} + + Jump to the code for a specific component directly from + the \uicontrol {2D} view or \uicontrol {Navigator} view. + You can also jump to the code of a particular + \uicontrol {State} or \uicontrol {Connection} from their + corresponding views. + \endlist */ diff --git a/doc/qtcreator/src/editors/creator-jump-to-the-code.qdoc b/doc/qtcreator/src/editors/creator-jump-to-the-code.qdoc new file mode 100644 index 00000000000..d5a83080bfd --- /dev/null +++ b/doc/qtcreator/src/editors/creator-jump-to-the-code.qdoc @@ -0,0 +1,66 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \previouspage creator-editor-locator.html + \page creator-jump-to-the-code.html + \nextpage creator-editor-refactoring.html + + \title Jump to the Code + + Jump to the code is a feature that gives you instant access to a particular + part of the code. It takes you to the \uicontrol {Code} view location of a particular + component, \uicontrol {State}, or \uicontrol {Connection}. + + You can jump to the code from: + \list + \li \uicontrol {Navigator} view + \li \uicontrol {2D} view + \li \uicontrol {States} view + \li \uicontrol {Connections} view + \endlist + + \section1 Jump to the Code from the Navigator View + + \list 1 + \li Right-click on a component in the \uicontrol {Navigator} view. + \li Select \uicontrol {Jump to the Code}. + \endlist + + \image jump-to-the-code-from-navigator-view.webp + + \section1 Jump to the Code from the 2D View + + \list 1 + \li Right-click on a component in the \uicontrol {2D} view. + \li Select \uicontrol {Jump to the Code}. + \endlist + + \image jump-to-the-code-from-2D-view.webp + + \note Alternatively, you can select the component in the \uicontrol {Navigator} view + or in the \uicontrol {2D} view and press \key {F4}. That takes you to the code + location in the \uicontrol {Code} view. + + \section1 Jump to the Code from the States View + + \list 1 + \li Locate the state you want to check in the \uicontrol {States} view. + \li Select \inlineimage icons/browse-button.png + to open additional options. + \li Select \uicontrol {Jump to the Code}. + \endlist + + \image jump-to-the-code-from-state-view.webp + + \section1 Jump to the Code from the Connections View + + \list 1 + \li Select a connection in the \uicontrol {Connections} view. + \li Select \inlineimage icons/jump-to-code-16px.png + to jump to the code segment related to the connection. + \endlist + + \image jump-to-the-code-from-connections-view.webp + +*/ diff --git a/doc/qtcreator/src/editors/creator-locator.qdoc b/doc/qtcreator/src/editors/creator-locator.qdoc index e9a9ad59c98..53477670091 100644 --- a/doc/qtcreator/src/editors/creator-locator.qdoc +++ b/doc/qtcreator/src/editors/creator-locator.qdoc @@ -4,7 +4,7 @@ /*! \previouspage creator-editor-finding.html \page creator-editor-locator.html - \nextpage creator-editor-refactoring.html + \nextpage creator-jump-to-the-code.html \title Searching with the Locator diff --git a/doc/qtdesignstudio/examples/doc/FireParticles.qdoc b/doc/qtdesignstudio/examples/doc/FireParticles.qdoc index f3603f08441..d198fbdf965 100644 --- a/doc/qtdesignstudio/examples/doc/FireParticles.qdoc +++ b/doc/qtdesignstudio/examples/doc/FireParticles.qdoc @@ -31,7 +31,7 @@ \li \e fire-color-table.png \endlist - You can download the assets from + Download the assets \l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/fire-particles/FireParticles/content/images} {here}. @@ -48,14 +48,14 @@ \li In the \uicontrol Presets section, select \uicontrol General > \uicontrol {3D}. \li In the \uicontrol Details section, set the name to \e FireParticles - and select the folder where you want to save the project. + , and select the folder where you want to save the project. \li Select \uicontrol {Create}. \endlist - Next, remove unwanted default components from the project: + Next, remove any unwanted default components from the project: \list 1 - \li In \uicontrol {Navigator}, select \e Text and select the \key Delete + \li In the \uicontrol {Navigator} view, select \e Text and then select the \key Delete key. \li In the same way, delete \e {cubeModel}. \endlist @@ -63,11 +63,10 @@ For a better visual effect, set the background color to black: \list - \li In \uicontrol {Navigator}, select \e Rectangle and in + \li In the \uicontrol {Navigator} view, select \e Rectangle and in \uicontrol {Properties}, set \uicontrol {Fill Color} to #000000. \endlist - \section2 Adding a Particle System to Your Scene To add a particle system, you first need to import the QtQuick3D.Particles3D @@ -79,16 +78,19 @@ \li Find QtQuick3D.Particles3D, and select it to add it to your project. \endlist + \image fire-particles-components.png + In this project, you use an animated sprite to simulate a fire. For - this, use the Animated Sprite particle system template: + this, use the \uicontrol {Animated Sprite} particle system template: \list \li From \uicontrol Components > \uicontrol{Qt Quick 3D Particle System Templates} drag an - \uicontrol {Animated Sprite} component to the \uicontrol{3D} view. You can - also drag it to \e scene in \uicontrol {Navigator}. + \uicontrol {Animated Sprite} component [1] to \e scene in \uicontrol {Navigator}. \endlist + \image fire-particles-animated-sprite-comp.png + \image fire-particles-navigator.png You now have the particle system in place. To preview it, select @@ -97,26 +99,33 @@ \section2 Adding Sprites and Sprite Animations - First, import the sprite to use for the fire: + In this project, you use a spritesheet with 3 sprites. + A spritesheet is a single image file that contains multiple sprites arranged + in a grid. You use these sprites to create a looping animation to add variation + to the movement of the flames. + + First, import the spritesheet you downloaded in the beginning of this tutorial + (\e{fire-sprites.png}) to use for the fire: \list 1 - \li In \uicontrol {Assets}, select \inlineimage icons/plus.png + \li In the \uicontrol {Assets} view, select \inlineimage icons/plus.png . - \li Select \e {fire-sprites.png}. + \li In the \uicontrol {Add Assets} dialog, find and select \e {fire-sprites.png}. \endlist \image fire-particles-assets.png - Next, add the sprite to the particle system and create the animation: + Next, add the spritesheet to the particle system, and create the animation: \list 1 - \li From \uicontrol{Assets}, drag \e {fire-sprites.png} to - \e animatedTexture in \uicontrol {Navigator}. - \li In \uicontrol{Navigator}, select \e{animatedSequence} and in - \uicontrol {Properties}, set: + \li From the \uicontrol{Assets} view, drag \e {fire-sprites.png} to + \e animatedTexture in the \uicontrol {Navigator} view. + \image fire-particles-drag-sprites.png + \li In the \uicontrol{Navigator} view, select \e{animatedSequence} and in + the \uicontrol {Properties} view, set: \list \li \uicontrol{Frame Count} to 3. - There are 3 sprites in \e {fire-sprites.png} so you want to + There are three sprites in \e {fire-sprites.png} so you want to divide the image into 3 different sprites for this animation. \li \uicontrol Interpolate to true. This makes the animation between the sprites smooth. @@ -132,21 +141,25 @@ change the color of a single sprite during its life span. In this project, you use a gradient color table ranging from yellow to dark orange. This results in the sprites being yellow when they are emitted and dark - orange at the end of the life span. + orange at the end of their life span. To set the color table: + \list 1 - \li Import \e{fire-color-table.png} to your project. - \li From \uicontrol{Components}, drag a \uicontrol Texture to + \li Go to the \uicontrol {Asstes} view and import \e{fire-color-table.png} to your project. + \li From the \uicontrol{Components} view, drag a \uicontrol Texture [1] to \e animatedSpriteParticle in \uicontrol{Navigator}. + \image fire-particles-drag-texture.png \li Rename the texture to \e {fireColorTable}. - \li In \uicontrol {Navigator}, select \e {fireColorTable} and in - \uicontrol {Properties}, set \uicontrol Source to + \li In the \uicontrol {Navigator} view, select \e {fireColorTable} and in + the \uicontrol {Properties} view, set \uicontrol Source to \e{fire-color-table.png}. - \li In \uicontrol {Navigator}, select \e {animatedSpriteParticle} and: + \li In the \uicontrol {Navigator} view, select \e {animatedSpriteParticle} and in the + \uicontrol Properties view: \list - \li Ensure that \uicontrol Sprite is set to \e {animatedTexture}. - \li Set \uicontrol {Particle Scale} to 5. + \li Ensure that \uicontrol Sprite is set to \e {animatedTexture}. This sets which image + to emit from the particle emitter, which in this case is the spritesheet added earlier. + \li Set \uicontrol {Particle Scale} to 5 to adjust the size of the flames. \li Set \uicontrol {Color Table} to \e{fireColorTable}. \endlist \endlist @@ -158,48 +171,71 @@ The next step is to adjust the particle emitter properties: \list 1 - \li In \uicontrol{Navigator}, select \e animatedSpriteEmitter and in - \uicontrol {Properties}, set: + \li First, in the \uicontrol{Navigator} view, select \e animatedSpriteEmitter and then, in + the \uicontrol {Properties} view, set: \list - \li \uicontrol {Emit Rate} to 300. - \li \uicontrol {Life Span} to 2500. - \li \uicontrol {Life Span Variation} to 100. - \li \uicontrol {Particle End Scale} to 1,50. + \li \uicontrol {Emit Rate} to 300 to emit 300 particles per second. + \li \uicontrol {Life Span} to 2500 to set the life span of each particle to + 2500 milliseconds (2.5 seconds). + \li \uicontrol {Life Span Variation} to 100 to set variation to the particle + life spans. The life span of each particle is now between 2.4 and 2.6 seconds to make + the fire look more realistic. + \li \uicontrol {Particle End Scale} to 1.50. When a particle is emitted, its + scale is 1.00 by default. By the end of its life span, it will grow to a scale of 1.50. \endlist - This sets the emitter to emit 300 particles per second. The life span of - each particle is ranging from 2.4 to 2.6 seconds. The size of each - particle is increasing slightly throughout its life span. - \li In \uicontrol{Navigator}, select \e animatedSpriteParticle and in - \uicontrol {Properties}, set: + + \image fire-particles-particle-emitter.png + + \li First, in the \uicontrol{Navigator} view, select \e animatedSpriteParticle and then, in + the \uicontrol {Properties} view, set: \list - \li \uicontrol {Blend Mode} to Screen. - \li \uicontrol {Max Amount} to 1000. - \li \uicontrol {Color Variation} > \uicontrol W to 0,50. This adds + \li \uicontrol {Blend Mode} to Screen to blend the fire nicely with the background. + \li \uicontrol {Max Amount} to 1000 to define the maximum amount of particles visible at the + same time. Setting a higher number allocates more memory. + \li \uicontrol {Color Variation} > \uicontrol W to 0.50. This adds randomness to the opacity of the sprites. \endlist - \li In \uicontrol{Navigator}, select \e animatedSpriteDirection and in - \uicontrol {Properties}, set: + + \image fire-particle-sprite-particle.png + + \li The \e animatedSpriteDirection component defines the direction and the velocity of + the particles emitted from the particle emitter. In this tutorial, you want the particles to + go straight up with a small variation. + + In the \uicontrol{Navigator} view, select \e animatedSpriteDirection and in the + \uicontrol {Properties} view, set: \list - \li \uicontrol Direction > \uicontrol Y to 20. - \li \uicontrol {Direction Variation} > \uicontrol X to 3. - \li \uicontrol {Direction Variation} > \uicontrol Y to 10. + \li \uicontrol Direction > \uicontrol X to 0 and \uicontrol Direction > \uicontrol Y + to 20. This makes the particles go straight up (along the Y axis) at the velocity of 20. + \li \uicontrol {Direction Variation} > \uicontrol X to 3. This adds small variation along + the X axis, making the flames a little bit wider. + \li \uicontrol {Direction Variation} > \uicontrol Y to 10. This adds variation to the + velocity of the particles along the Y axis. Because this makes some particles slower, + the flames appears thicker in the lower part. \endlist - This makes the particles go straight up with a small amount of randomness - to the direction. + + \image fire-particles-direction.png + \endlist - \section1 Previewing + \section1 Running the Project - Now, the fire effect is done. Before you preview it, adjust the camera: + Now, the fire effect is ready. Before you run it, position the camera to show the effect + from a suitable perspective: \list 1 - \li In \uicontrol {Navigator}, select \e sceneCamera and in - \uicontrol {Properties}, set: + \li In the \uicontrol {Navigator} view, select \e sceneCamera and in the + \uicontrol {Properties} view, set: \list \li \uicontrol {Field of View} to 20. \li \uicontrol {Translation} > \uicontrol Y to 35. + \li \uicontrol {Translation} > \uicontrol Z to 350. \endlist \endlist - Now, preview the fire effect by selecting \key Alt + \key{P}. + \image fire-particles-camera.png + + Now, run the project by selecting \key Ctrl + \key{R} or the + \inlineimage icons/run_project.png + button in the top toolbar. */ diff --git a/doc/qtdesignstudio/examples/doc/images/fire-particle-sprite-particle.png b/doc/qtdesignstudio/examples/doc/images/fire-particle-sprite-particle.png new file mode 100644 index 00000000000..6ea732ed9f0 Binary files /dev/null and b/doc/qtdesignstudio/examples/doc/images/fire-particle-sprite-particle.png differ diff --git a/doc/qtdesignstudio/examples/doc/images/fire-particles-animated-sprite-comp.png b/doc/qtdesignstudio/examples/doc/images/fire-particles-animated-sprite-comp.png new file mode 100644 index 00000000000..e6e7b93baf9 Binary files /dev/null and b/doc/qtdesignstudio/examples/doc/images/fire-particles-animated-sprite-comp.png differ diff --git a/doc/qtdesignstudio/examples/doc/images/fire-particles-camera.png b/doc/qtdesignstudio/examples/doc/images/fire-particles-camera.png new file mode 100644 index 00000000000..c4bb401d7c9 Binary files /dev/null and b/doc/qtdesignstudio/examples/doc/images/fire-particles-camera.png differ diff --git a/doc/qtdesignstudio/examples/doc/images/fire-particles-components.png b/doc/qtdesignstudio/examples/doc/images/fire-particles-components.png new file mode 100644 index 00000000000..cad61db3e80 Binary files /dev/null and b/doc/qtdesignstudio/examples/doc/images/fire-particles-components.png differ diff --git a/doc/qtdesignstudio/examples/doc/images/fire-particles-direction.png b/doc/qtdesignstudio/examples/doc/images/fire-particles-direction.png new file mode 100644 index 00000000000..ca734933121 Binary files /dev/null and b/doc/qtdesignstudio/examples/doc/images/fire-particles-direction.png differ diff --git a/doc/qtdesignstudio/examples/doc/images/fire-particles-drag-sprites.png b/doc/qtdesignstudio/examples/doc/images/fire-particles-drag-sprites.png new file mode 100644 index 00000000000..6c8fd84b97c Binary files /dev/null and b/doc/qtdesignstudio/examples/doc/images/fire-particles-drag-sprites.png differ diff --git a/doc/qtdesignstudio/examples/doc/images/fire-particles-drag-texture.png b/doc/qtdesignstudio/examples/doc/images/fire-particles-drag-texture.png new file mode 100644 index 00000000000..c326e875579 Binary files /dev/null and b/doc/qtdesignstudio/examples/doc/images/fire-particles-drag-texture.png differ diff --git a/doc/qtdesignstudio/examples/doc/images/fire-particles-navigator.png b/doc/qtdesignstudio/examples/doc/images/fire-particles-navigator.png index 759cca99909..fe99fb2e188 100644 Binary files a/doc/qtdesignstudio/examples/doc/images/fire-particles-navigator.png and b/doc/qtdesignstudio/examples/doc/images/fire-particles-navigator.png differ diff --git a/doc/qtdesignstudio/examples/doc/images/fire-particles-particle-emitter.png b/doc/qtdesignstudio/examples/doc/images/fire-particles-particle-emitter.png new file mode 100644 index 00000000000..0b7c1399d4d Binary files /dev/null and b/doc/qtdesignstudio/examples/doc/images/fire-particles-particle-emitter.png differ diff --git a/doc/qtdesignstudio/images/icons/jump-to-code-16px.png b/doc/qtdesignstudio/images/icons/jump-to-code-16px.png new file mode 100644 index 00000000000..1e9bc31dba7 Binary files /dev/null and b/doc/qtdesignstudio/images/icons/jump-to-code-16px.png differ diff --git a/doc/qtdesignstudio/images/icons/run_project.png b/doc/qtdesignstudio/images/icons/run_project.png new file mode 100644 index 00000000000..ab744888d43 Binary files /dev/null and b/doc/qtdesignstudio/images/icons/run_project.png differ diff --git a/doc/qtdesignstudio/images/jump-to-the-code-from-2D-view.webp b/doc/qtdesignstudio/images/jump-to-the-code-from-2D-view.webp new file mode 100644 index 00000000000..61bf73acf5f Binary files /dev/null and b/doc/qtdesignstudio/images/jump-to-the-code-from-2D-view.webp differ diff --git a/doc/qtdesignstudio/images/jump-to-the-code-from-connections-view.webp b/doc/qtdesignstudio/images/jump-to-the-code-from-connections-view.webp new file mode 100644 index 00000000000..18657256793 Binary files /dev/null and b/doc/qtdesignstudio/images/jump-to-the-code-from-connections-view.webp differ diff --git a/doc/qtdesignstudio/images/jump-to-the-code-from-navigator-view.webp b/doc/qtdesignstudio/images/jump-to-the-code-from-navigator-view.webp new file mode 100644 index 00000000000..3591c4f11eb Binary files /dev/null and b/doc/qtdesignstudio/images/jump-to-the-code-from-navigator-view.webp differ diff --git a/doc/qtdesignstudio/images/jump-to-the-code-from-state-view.webp b/doc/qtdesignstudio/images/jump-to-the-code-from-state-view.webp new file mode 100644 index 00000000000..f396f8eeb15 Binary files /dev/null and b/doc/qtdesignstudio/images/jump-to-the-code-from-state-view.webp differ diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc index de4e993b7f6..c79a576c56f 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc @@ -214,6 +214,7 @@ \list \li \l{Finding and Replacing} \li \l{Searching with the Locator} + \li \l{Jump to the Code} \endlist \li \l{Refactoring} \li \l{Applying Refactoring Actions} diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/ImportDialog.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ImportDialog.qml index bf28695ec9b..e7bcefff776 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/ImportDialog.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/ImportDialog.qml @@ -120,7 +120,7 @@ StudioControls.Dialog { actionIndicator.visible: false translationIndicator.visible: false validator: RegularExpressionValidator { - regularExpression: /^\w+$/ + regularExpression: /^[\w ]+$/ } Keys.onEnterPressed: btnImport.onClicked() diff --git a/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml b/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml index 50ae55ab722..5cac7fd3fc0 100644 --- a/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml +++ b/share/qtcreator/qmldesigner/collectionEditorQmlSource/NewCollectionDialog.qml @@ -87,7 +87,7 @@ StudioControls.Dialog { actionIndicator.visible: false translationIndicator.visible: false validator: RegularExpressionValidator { - regularExpression: /^\w+$/ + regularExpression: /^[\w ]+$/ } Keys.onEnterPressed: btnCreate.onClicked() diff --git a/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml b/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml index e68a0bc8a25..0227d0f54af 100644 --- a/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml +++ b/share/qtcreator/qmldesigner/effectMakerQmlSources/BlurHelper.qml @@ -25,7 +25,6 @@ Item { 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 @@ -34,12 +33,12 @@ Item { BlurItem { id: blurredItemSource1 - property Item src: priv.useBlurItem1 ? source : null + property Item src: source // 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 + width: Math.ceil(rootItem.width / 16) * blurItemSize + height: Math.ceil(rootItem.height / 16) * blurItemSize } BlurItem { id: blurredItemSource2 diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextField.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextField.qml index 0180aa06ad5..58bd9c37d2e 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextField.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TextField.qml @@ -86,6 +86,9 @@ T.TextField { // was closed due to an menu item click. if (control.activeFocus && control.focusReason !== Qt.OtherFocusReason) control.preFocusText = control.text + + if (!control.activeFocus) + control.deselect() } onEditChanged: { diff --git a/src/libs/advanceddockingsystem/dockareawidget.cpp b/src/libs/advanceddockingsystem/dockareawidget.cpp index 5cf12d70509..89fbbcfb3b6 100644 --- a/src/libs/advanceddockingsystem/dockareawidget.cpp +++ b/src/libs/advanceddockingsystem/dockareawidget.cpp @@ -189,7 +189,8 @@ struct DockAreaWidgetPrivate { DockAreaWidget *q = nullptr; QBoxLayout *m_layout = nullptr; - DockAreaLayout *m_contentsLayout = nullptr; + // DockAreaLayout is not a QObject -> std::unique_ptr manages deletion + std::unique_ptr m_contentsLayout; DockAreaTitleBar *m_titleBar = nullptr; DockManager *m_dockManager = nullptr; AutoHideDockContainer *m_autoHideDockContainer = nullptr; @@ -328,7 +329,7 @@ DockAreaWidget::DockAreaWidget(DockManager *dockManager, DockContainerWidget *pa setLayout(d->m_layout); d->createTitleBar(); - d->m_contentsLayout = new DockAreaLayout(d->m_layout); + d->m_contentsLayout = std::make_unique(d->m_layout); if (d->m_dockManager) emit d->m_dockManager->dockAreaCreated(this); } @@ -336,8 +337,6 @@ DockAreaWidget::DockAreaWidget(DockManager *dockManager, DockContainerWidget *pa DockAreaWidget::~DockAreaWidget() { qCInfo(adsLog) << Q_FUNC_INFO; - delete d->m_contentsLayout; - delete d; } DockManager *DockAreaWidget::dockManager() const diff --git a/src/libs/advanceddockingsystem/dockareawidget.h b/src/libs/advanceddockingsystem/dockareawidget.h index 59f8b9ee207..dae4d942b8c 100644 --- a/src/libs/advanceddockingsystem/dockareawidget.h +++ b/src/libs/advanceddockingsystem/dockareawidget.h @@ -9,6 +9,8 @@ #include +#include + QT_BEGIN_NAMESPACE class QAbstractButton; class QXmlStreamWriter; @@ -33,7 +35,7 @@ class ADS_EXPORT DockAreaWidget : public QFrame { Q_OBJECT private: - DockAreaWidgetPrivate *d; ///< private data (pimpl) + std::unique_ptr d; ///< private data (pimpl) friend struct DockAreaWidgetPrivate; friend class DockContainerWidget; friend class DockContainerWidgetPrivate; diff --git a/src/plugins/effectmakernew/compositionnode.cpp b/src/plugins/effectmakernew/compositionnode.cpp index 9520e50d050..9412153ddee 100644 --- a/src/plugins/effectmakernew/compositionnode.cpp +++ b/src/plugins/effectmakernew/compositionnode.cpp @@ -137,9 +137,9 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c QString trimmedLine = codeLine.trimmed(); if (trimmedLine.startsWith("@requires")) { // Get the required node, remove "@requires " - QString nodeName = trimmedLine.sliced(10); - if (!nodeName.isEmpty() && !m_requiredNodes.contains(nodeName)) - m_requiredNodes << nodeName; + QString nodeId = trimmedLine.sliced(10).toLower(); + if (!nodeId.isEmpty() && !m_requiredNodes.contains(nodeId)) + m_requiredNodes << nodeId; } } } diff --git a/src/plugins/effectmakernew/effectmakermodel.cpp b/src/plugins/effectmakernew/effectmakermodel.cpp index fbb439ff17d..4fcb6686a76 100644 --- a/src/plugins/effectmakernew/effectmakermodel.cpp +++ b/src/plugins/effectmakernew/effectmakermodel.cpp @@ -124,6 +124,10 @@ void EffectMakerModel::addNode(const QString &nodeQenPath) const QString path = EffectUtils::nodesSourcesPath() + "/common/" + requiredId + ".qen"; auto requiredNode = new CompositionNode({}, path); + connect(qobject_cast(requiredNode->uniformsModel()), + &EffectMakerUniformsModel::dataChanged, this, [this] { + setHasUnsavedChanges(true); + }); requiredNode->setRefCount(1); m_nodes.prepend(requiredNode); } @@ -490,6 +494,9 @@ QJsonObject nodeToJson(const CompositionNode &node) QString type = Uniform::stringFromType(uniform->type()); uniformObject.insert("type", type); + if (!uniform->displayName().isEmpty()) + uniformObject.insert("displayName", QString(uniform->displayName())); + QString value = variantAsDataString(uniform->type(), uniform->value()); if (uniform->type() == Uniform::Type::Sampler) value = QFileInfo(value).fileName(); diff --git a/src/plugins/effectmakernew/uniform.cpp b/src/plugins/effectmakernew/uniform.cpp index be10cc7f421..e9084f27991 100644 --- a/src/plugins/effectmakernew/uniform.cpp +++ b/src/plugins/effectmakernew/uniform.cpp @@ -114,6 +114,11 @@ QString Uniform::description() const return m_description; } +QString Uniform::displayName() const +{ + return m_displayName; +} + QString Uniform::customValue() const { return m_customValue; diff --git a/src/plugins/effectmakernew/uniform.h b/src/plugins/effectmakernew/uniform.h index 7216c6d9d6b..2aa35d499d9 100644 --- a/src/plugins/effectmakernew/uniform.h +++ b/src/plugins/effectmakernew/uniform.h @@ -59,6 +59,7 @@ public: QString name() const; QString description() const; + QString displayName() const; QString customValue() const; void setCustomValue(const QString &newCustomValue); diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 5c6ebf07c5d..13178c6dd2e 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -115,9 +115,8 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFon m_assetsWidget->setClearColor(Theme::getColor(Theme::Color::QmlDesigner_BackgroundColorDarkAlternate)); m_assetsWidget->engine()->addImageProvider("qmldesigner_assets", m_assetsIconProvider); - connect(m_assetsModel, &AssetsLibraryModel::fileChanged, [](const QString &changeFilePath) { - QmlDesignerPlugin::instance()->emitAssetChanged(changeFilePath); - }); + connect(m_assetsModel, &AssetsLibraryModel::fileChanged, + QmlDesignerPlugin::instance(), &QmlDesignerPlugin::assetChanged); auto layout = new QVBoxLayout(this); layout->setContentsMargins({}); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp index 533c2d72b6c..2279b60d130 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectiondetailsmodel.cpp @@ -179,15 +179,16 @@ bool CollectionDetailsModel::setHeaderData(int section, return headerChanged; } -bool CollectionDetailsModel::insertRows(int row, int count, const QModelIndex &parent) +bool CollectionDetailsModel::insertRows(int row, int count, [[maybe_unused]] const QModelIndex &parent) { if (count < 1) return false; row = qBound(0, row, rowCount()); - beginInsertRows(parent, row, row + count); + + beginResetModel(); m_currentCollection.insertEmptyElements(row, count); - endInsertRows(); + endResetModel(); selectRow(row); return true; diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp index 4eeca52964d..f48b6547aea 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.cpp @@ -3,11 +3,9 @@ #include "collectioneditorutils.h" -#include "abstractview.h" -#include "bindingproperty.h" +#include "model.h" #include "nodemetainfo.h" #include "propertymetainfo.h" -#include "variantproperty.h" #include @@ -137,33 +135,6 @@ QString getSourceCollectionType(const ModelNode &node) return {}; } -void assignCollectionToNode(AbstractView *view, - const ModelNode &modelNode, - const ModelNode &collectionSourceNode, - const QString &collectionName) -{ - QTC_ASSERT(modelNode.isValid() && collectionSourceNode.isValid(), return); - - 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"); - - QString identifier = QString("%1.%2").arg(sourceId, QString::fromLatin1(sourceProperty.name())); - - view->executeInTransaction("CollectionEditor::assignCollectionToNode", - [&modelProperty, &identifier]() { - modelProperty.setExpression(identifier); - }); -} - Utils::FilePath dataStoreJsonFilePath() { return collectionPath("models.json"); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h index 835960f671e..036304a3819 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectioneditorutils.h @@ -24,11 +24,6 @@ QString getSourceCollectionType(const QmlDesigner::ModelNode &node); QString getSourceCollectionPath(const QmlDesigner::ModelNode &dataStoreNode); -void assignCollectionToNode(AbstractView *view, - const ModelNode &modelNode, - const ModelNode &collectionSourceNode, - const QString &collectionName); - Utils::FilePath dataStoreJsonFilePath(); Utils::FilePath dataStoreQmlFilePath(); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp index 4d7773ade33..5c4de3e4388 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.cpp @@ -394,27 +394,24 @@ void CollectionSourceModel::updateNodeSource(const ModelNode &node) updateCollectionList(index); } -void CollectionSourceModel::onSelectedCollectionChanged(int collectionIndex) +void CollectionSourceModel::onSelectedCollectionChanged(CollectionListModel *collectionList, + int collectionIndex) { - CollectionListModel *collectionList = qobject_cast(sender()); - if (collectionIndex > -1 && collectionList) { + if (collectionIndex > -1) { if (m_previousSelectedList && m_previousSelectedList != collectionList) m_previousSelectedList->selectCollectionIndex(-1); m_previousSelectedList = collectionList; - emit collectionSelected(collectionList->sourceNode(), - collectionList->collectionNameAt(collectionIndex)); + emit collectionSelected(collectionList->collectionNameAt(collectionIndex)); selectSourceIndex(sourceIndex(collectionList->sourceNode())); } } -void CollectionSourceModel::onCollectionNameChanged(const QString &oldName, const QString &newName) +void CollectionSourceModel::onCollectionNameChanged(CollectionListModel *collectionList, + const QString &oldName, const QString &newName) { - CollectionListModel *collectionList = qobject_cast(sender()); - QTC_ASSERT(collectionList, return); - auto emitRenameWarning = [this](const QString &msg) -> void { emit this->warning(tr("Rename Model"), msg); }; @@ -496,15 +493,14 @@ void CollectionSourceModel::onCollectionNameChanged(const QString &oldName, cons return; } + emit collectionRenamed(oldName, newName); updateCollectionList(nodeIndex); } } -void CollectionSourceModel::onCollectionsRemoved(const QStringList &removedCollections) +void CollectionSourceModel::onCollectionsRemoved(CollectionListModel *collectionList, + const QStringList &removedCollections) { - CollectionListModel *collectionList = qobject_cast(sender()); - QTC_ASSERT(collectionList, return); - auto emitDeleteWarning = [this](const QString &msg) -> void { emit warning(tr("Delete Model"), msg); }; @@ -551,10 +547,12 @@ void CollectionSourceModel::onCollectionsRemoved(const QStringList &removedColle if (document.isObject()) { QJsonObject rootObject = document.object(); + QStringList collectionsRemovedFromDocument; for (const QString &collectionName : removedCollections) { bool sourceContainsCollection = rootObject.contains(collectionName); if (sourceContainsCollection) { rootObject.remove(collectionName); + collectionsRemovedFromDocument << collectionName; } else { emitDeleteWarning(tr("The model group doesn't contain the model name (%1).") .arg(sourceContainsCollection)); @@ -576,6 +574,9 @@ void CollectionSourceModel::onCollectionsRemoved(const QStringList &removedColle return; } + for (const QString &collectionName : std::as_const(collectionsRemovedFromDocument)) + emit this->collectionRemoved(collectionName); + updateCollectionList(nodeIndex); } } @@ -606,7 +607,7 @@ void CollectionSourceModel::setSelectedIndex(int idx) } else if (m_previousSelectedList) { m_previousSelectedList->selectCollectionIndex(-1); m_previousSelectedList = {}; - emit this->collectionSelected(sourceNodeAt(idx), {}); + emit this->collectionSelected({}); } } } @@ -630,37 +631,38 @@ void CollectionSourceModel::updateCollectionList(QModelIndex index) return; ModelNode sourceNode = sourceNodeAt(index.row()); - QSharedPointer currentList = m_collectionList.at(index.row()); - QSharedPointer newList = loadCollection(sourceNode, currentList); - if (currentList != newList) { + QSharedPointer oldList = m_collectionList.at(index.row()); + QSharedPointer newList = loadCollection(sourceNode, oldList); + if (oldList != newList) { m_collectionList.replace(index.row(), newList); emit dataChanged(index, index, {CollectionsRole}); - emit collectionNamesChanged(sourceNode, newList->stringList()); + registerCollection(newList); } } void CollectionSourceModel::registerCollection(const QSharedPointer &collection) { - connect(collection.data(), - &CollectionListModel::selectedIndexChanged, - this, - &CollectionSourceModel::onSelectedCollectionChanged, - Qt::UniqueConnection); + CollectionListModel *collectionList = collection.data(); + if (collectionList == nullptr) + return; - connect(collection.data(), - &CollectionListModel::collectionNameChanged, - this, - &CollectionSourceModel::onCollectionNameChanged, - Qt::UniqueConnection); + connect(collectionList, &CollectionListModel::selectedIndexChanged, this, + [this, collectionList](int idx) { + onSelectedCollectionChanged(collectionList, idx); + }, Qt::UniqueConnection); - connect(collection.data(), - &CollectionListModel::collectionsRemoved, - this, - &CollectionSourceModel::onCollectionsRemoved, - Qt::UniqueConnection); + connect(collectionList, &CollectionListModel::collectionNameChanged, this, + [this, collectionList](const QString &oldName, const QString &newName) { + onCollectionNameChanged(collectionList, oldName, newName); + }, Qt::UniqueConnection); - if (collection.data() && collection->sourceNode()) - emit collectionNamesChanged(collection->sourceNode(), collection->stringList()); + connect(collectionList, &CollectionListModel::collectionsRemoved, this, + [this, collectionList](const QStringList &removedCollections) { + onCollectionsRemoved(collectionList, removedCollections); + }, Qt::UniqueConnection); + + if (collectionList->sourceNode().isValid()) + emit collectionNamesInitialized(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 36226138c30..487b616b97b 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionsourcemodel.h @@ -70,15 +70,20 @@ public: signals: void selectedIndexChanged(int idx); - void collectionSelected(const ModelNode &sourceNode, const QString &collectionName); - void collectionNamesChanged(const ModelNode &sourceNode, QStringList collections); + void collectionSelected(const QString &collectionName); + void collectionNamesInitialized(const QStringList &initialList); + void collectionRenamed(const QString &oldname, const QString &newName); + void collectionRemoved(const QString &collectionName); + void isEmptyChanged(bool); void warning(const QString &title, const QString &body); private slots: - void onSelectedCollectionChanged(int collectionIndex); - void onCollectionNameChanged(const QString &oldName, const QString &newName); - void onCollectionsRemoved(const QStringList &removedCollections); + void onSelectedCollectionChanged(CollectionListModel *collectionList, int collectionIndex); + void onCollectionNameChanged(CollectionListModel *collectionList, const QString &oldName, + const QString &newName); + void onCollectionsRemoved(CollectionListModel *collectionList, + const QStringList &removedCollections); private: void setSelectedIndex(int idx); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp index 9140f02ec53..f17abf5d9f5 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.cpp @@ -70,8 +70,8 @@ QmlDesigner::WidgetInfo CollectionView::widgetInfo() connect(sourceModel, &CollectionSourceModel::collectionSelected, this, - [this](const ModelNode &sourceNode, const QString &collection) { - m_widget->collectionDetailsModel()->loadCollection(sourceNode, collection); + [this](const QString &collection) { + m_widget->collectionDetailsModel()->loadCollection(dataStoreNode(), collection); }); connect(sourceModel, &CollectionSourceModel::isEmptyChanged, this, [this](bool isEmpty) { @@ -80,11 +80,24 @@ QmlDesigner::WidgetInfo CollectionView::widgetInfo() }); connect(sourceModel, - &CollectionSourceModel::collectionNamesChanged, + &CollectionSourceModel::collectionNamesInitialized, this, - [this](const ModelNode &sourceNode, const QStringList &collectionNames) { - if (sourceNode == m_dataStore->modelNode()) - m_dataStore->setCollectionNames(collectionNames); + [this](const QStringList &collectionNames) { + m_dataStore->setCollectionNames(collectionNames); + }); + + connect(sourceModel, + &CollectionSourceModel::collectionRenamed, + this, + [this](const QString &oldName, const QString &newName) { + m_dataStore->renameCollection(oldName, newName); + }); + + connect(sourceModel, + &CollectionSourceModel::collectionRemoved, + this, + [this](const QString &collectionName) { + m_dataStore->removeCollection(collectionName); }); } @@ -200,6 +213,12 @@ void CollectionView::addResource(const QUrl &url, const QString &name, const QSt }); } +void CollectionView::assignCollectionToSelectedNode(const QString &collectionName) +{ + QTC_ASSERT(dataStoreNode() && hasSingleSelectedModelNode(), return); + m_dataStore->assignCollectionToNode(this, singleSelectedModelNode(), collectionName); +} + void CollectionView::registerDeclarativeType() { CollectionDetails::registerDeclarativeType(); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h index dd946776ed1..c08368b0c35 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionview.h +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionview.h @@ -43,6 +43,8 @@ public: void addResource(const QUrl &url, const QString &name, const QString &type); + void assignCollectionToSelectedNode(const QString &collectionName); + static void registerDeclarativeType(); void resetDataStoreNode(); diff --git a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp index 30ae4418ed6..9b14c2cd036 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/collectionwidget.cpp @@ -337,17 +337,7 @@ bool CollectionWidget::addCollectionToDataStore(const QString &collectionName) void CollectionWidget::assignCollectionToSelectedNode(const QString collectionName) { - ModelNode dsNode = dataStoreNode(); - ModelNode targetNode = m_view->singleSelectedModelNode(); - - QTC_ASSERT(dsNode.isValid() && targetNode.isValid(), return); - - if (dsNode.id().isEmpty()) { - warn(tr("Assigning the model"), tr("The model must have a valid id to be assigned.")); - return; - } - - CollectionEditor::assignCollectionToNode(m_view, targetNode, dsNode, collectionName); + m_view->assignCollectionToSelectedNode(collectionName); } void CollectionWidget::ensureDataStoreExists() diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp index 446d7ef08fc..bebc60f1de1 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp +++ b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.cpp @@ -3,6 +3,7 @@ #include "datastoremodelnode.h" +#include "abstractview.h" #include "collectioneditorconstants.h" #include "collectioneditorutils.h" #include "model/qmltextgenerator.h" @@ -22,6 +23,9 @@ #include #include +#include +#include + namespace { QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node) @@ -42,6 +46,19 @@ QmlDesigner::PropertyNameList createNameList(const QmlDesigner::ModelNode &node) return defaultsNodeProps + dynamicPropertyNames; } +bool isValidCollectionPropertyName(const QString &collectionId) +{ + static const QmlDesigner::PropertyNameList reservedKeywords = { + QmlDesigner::CollectionEditor::SOURCEFILE_PROPERTY, + QmlDesigner::CollectionEditor::JSONBACKEND_TYPENAME, + "backend", + "models", + }; + + return QmlDesigner::ModelNode::isValidId(collectionId) + && !reservedKeywords.contains(collectionId.toLatin1()); +} + } // namespace namespace QmlDesigner { @@ -85,15 +102,13 @@ void DataStoreModelNode::reloadModel() m_dataRelativePath = dataStoreJsonPath.relativePathFrom(dataStoreQmlPath).toFSPathString(); - if (forceUpdate) { - updateDataStoreProperties(); - updateSingletonFile(); - } + if (forceUpdate) + update(); } QStringList DataStoreModelNode::collectionNames() const { - return m_collectionNames; + return m_collectionPropertyNames.keys(); } Model *DataStoreModelNode::model() const @@ -137,23 +152,60 @@ void DataStoreModelNode::updateDataStoreProperties() static TypeName childNodeTypename = "ChildListModel"; + QSet collectionNamesToBeAdded; + const QStringList allCollectionNames = m_collectionPropertyNames.keys(); + for (const QString &collectionName : allCollectionNames) + collectionNamesToBeAdded << collectionName; + const QList formerPropertyNames = rootNode.dynamicProperties(); - for (const AbstractProperty &property : formerPropertyNames) - rootNode.removeProperty(property.name()); + + // Remove invalid collection names from the properties + for (const AbstractProperty &property : formerPropertyNames) { + if (!property.isNodeProperty()) + continue; + + NodeProperty nodeProprty = property.toNodeProperty(); + if (!nodeProprty.hasDynamicTypeName(childNodeTypename)) + continue; + + ModelNode childNode = nodeProprty.modelNode(); + if (childNode.hasProperty(CollectionEditor::JSONCHILDMODELNAME_PROPERTY)) { + QString modelName = childNode.property(CollectionEditor::JSONCHILDMODELNAME_PROPERTY) + .toVariantProperty() + .value() + .toString(); + if (collectionNamesToBeAdded.contains(modelName)) { + m_collectionPropertyNames.insert(modelName, property.name()); + collectionNamesToBeAdded.remove(modelName); + } else { + rootNode.removeProperty(property.name()); + } + } else { + rootNode.removeProperty(property.name()); + } + } rootNode.setIdWithoutRefactoring("models"); - for (const QString &collectionName : std::as_const(m_collectionNames)) { - PropertyName newName = collectionName.toLatin1(); + QStringList collectionNamesLeft = collectionNamesToBeAdded.values(); + Utils::sort(collectionNamesLeft); + for (const QString &collectionName : std::as_const(collectionNamesLeft)) { + PropertyName newPropertyName = getUniquePropertyName(collectionName); + if (newPropertyName.isEmpty()) { + qWarning() << __FUNCTION__ << __LINE__ + << QString("The property name cannot be generated from \"%1\"").arg(collectionName); + continue; + } ModelNode collectionNode = model()->createModelNode(childNodeTypename); - VariantProperty modelNameProperty = collectionNode.variantProperty( CollectionEditor::JSONCHILDMODELNAME_PROPERTY); - modelNameProperty.setValue(newName); + modelNameProperty.setValue(collectionName); - NodeProperty nodeProp = rootNode.nodeProperty(newName); + NodeProperty nodeProp = rootNode.nodeProperty(newPropertyName); nodeProp.setDynamicTypeNameAndsetModelNode(childNodeTypename, collectionNode); + + m_collectionPropertyNames.insert(collectionName, newPropertyName); } // Backend Property @@ -186,13 +238,127 @@ void DataStoreModelNode::updateSingletonFile() file.finalize(); } +void DataStoreModelNode::update() +{ + updateDataStoreProperties(); + updateSingletonFile(); +} + +PropertyName DataStoreModelNode::getUniquePropertyName(const QString &collectionName) +{ + ModelNode dataStoreNode = modelNode(); + QTC_ASSERT(!collectionName.isEmpty() && dataStoreNode.isValid(), return {}); + + QString newProperty; + + // convert to camel case + QStringList nameWords = collectionName.split(' '); + nameWords[0] = nameWords[0].at(0).toLower() + nameWords[0].mid(1); + for (int i = 1; i < nameWords.size(); ++i) + nameWords[i] = nameWords[i].at(0).toUpper() + nameWords[i].mid(1); + newProperty = nameWords.join(""); + + // if id starts with a number prepend an underscore + if (newProperty.at(0).isDigit()) + newProperty.prepend('_'); + + // If the new id is not valid (e.g. qml keyword match), prepend an underscore + if (!isValidCollectionPropertyName(newProperty)) + newProperty.prepend('_'); + + static const QRegularExpression rgx("\\d+$"); // matches a number at the end of a string + while (dataStoreNode.hasProperty(newProperty.toLatin1())) { // id exists + QRegularExpressionMatch match = rgx.match(newProperty); + if (match.hasMatch()) { // ends with a number, increment it + QString numStr = match.captured(); + int num = numStr.toInt() + 1; + newProperty = newProperty.mid(0, match.capturedStart()) + QString::number(num); + } else { + newProperty.append('1'); + } + } + + return newProperty.toLatin1(); +} + void DataStoreModelNode::setCollectionNames(const QStringList &newCollectionNames) { - if (m_collectionNames != newCollectionNames) { - m_collectionNames = newCollectionNames; - updateDataStoreProperties(); - updateSingletonFile(); + m_collectionPropertyNames.clear(); + for (const QString &collectionName : newCollectionNames) + m_collectionPropertyNames.insert(collectionName, {}); + update(); +} + +void DataStoreModelNode::renameCollection(const QString &oldName, const QString &newName) +{ + ModelNode dataStoreNode = modelNode(); + QTC_ASSERT(dataStoreNode.isValid(), return); + + if (m_collectionPropertyNames.contains(oldName)) { + const PropertyName oldPropertyName = m_collectionPropertyNames.value(oldName); + if (!oldPropertyName.isEmpty() && dataStoreNode.hasProperty(oldPropertyName)) { + NodeProperty collectionNode = dataStoreNode.property(oldPropertyName).toNodeProperty(); + if (collectionNode.isValid()) { + VariantProperty modelNameProperty = collectionNode.modelNode().variantProperty( + CollectionEditor::JSONCHILDMODELNAME_PROPERTY); + modelNameProperty.setValue(newName); + m_collectionPropertyNames.remove(oldName); + m_collectionPropertyNames.insert(newName, collectionNode.name()); + update(); + return; + } + qWarning() << __FUNCTION__ << __LINE__ + << "There is no valid node for the old collection name"; + return; + } + qWarning() << __FUNCTION__ << __LINE__ << QString("Invalid old property name") + << oldPropertyName; + return; + } + qWarning() << __FUNCTION__ << __LINE__ + << QString("There is no old collection name registered with this name \"%1\"").arg(oldName); +} + +void DataStoreModelNode::removeCollection(const QString &collectionName) +{ + if (m_collectionPropertyNames.contains(collectionName)) { + m_collectionPropertyNames.remove(collectionName); + update(); } } +void DataStoreModelNode::assignCollectionToNode(AbstractView *view, + const ModelNode &targetNode, + const QString &collectionName) +{ + QTC_ASSERT(targetNode.isValid(), return); + + if (!CollectionEditor::canAcceptCollectionAsModel(targetNode)) + return; + + if (!m_collectionPropertyNames.contains(collectionName)) { + qWarning() << __FUNCTION__ << __LINE__ << "Collection doesn't exist in the DataStore" + << collectionName; + return; + } + + PropertyName propertyName = m_collectionPropertyNames.value(collectionName); + + const ModelNode dataStore = modelNode(); + VariantProperty sourceProperty = dataStore.variantProperty(propertyName); + if (!sourceProperty.exists()) { + qWarning() << __FUNCTION__ << __LINE__ + << "The source property doesn't exist in the DataStore."; + return; + } + + BindingProperty modelProperty = targetNode.bindingProperty("model"); + + QString identifier = QString("DataStore.%1").arg(QString::fromLatin1(sourceProperty.name())); + + view->executeInTransaction("assignCollectionToNode", [&modelProperty, &identifier]() { + modelProperty.setExpression(identifier); + }); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h index e76d7f50e4a..3048fc4fc9c 100644 --- a/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h +++ b/src/plugins/qmldesigner/components/collectioneditor/datastoremodelnode.h @@ -5,6 +5,8 @@ #include +#include + namespace QmlDesigner { class Model; @@ -21,6 +23,12 @@ public: ModelNode modelNode() const; void setCollectionNames(const QStringList &newCollectionNames); + void renameCollection(const QString &oldName, const QString &newName); + void removeCollection(const QString &collectionName); + + void assignCollectionToNode(AbstractView *view, + const ModelNode &targetNode, + const QString &collectionName); private: QString getModelQmlText(); @@ -28,9 +36,11 @@ private: void reset(); void updateDataStoreProperties(); void updateSingletonFile(); + void update(); + PropertyName getUniquePropertyName(const QString &collectionName); ModelPointer m_model; - QStringList m_collectionNames; + QMap m_collectionPropertyNames; QString m_dataRelativePath; }; diff --git a/src/plugins/qmldesigner/components/eventlist/eventlistdelegate.cpp b/src/plugins/qmldesigner/components/eventlist/eventlistdelegate.cpp index 939c36d338d..1db399b1539 100644 --- a/src/plugins/qmldesigner/components/eventlist/eventlistdelegate.cpp +++ b/src/plugins/qmldesigner/components/eventlist/eventlistdelegate.cpp @@ -27,8 +27,15 @@ QWidget *EventListDelegate::createEditor(QWidget *parent, { if (index.column() == EventListModel::shortcutColumn) { auto *editor = new ShortcutWidget(parent); - connect(editor, &ShortcutWidget::done, this, &EventListDelegate::commitAndClose); - connect(editor, &ShortcutWidget::cancel, this, &EventListDelegate::close); + connect(editor, &ShortcutWidget::done, this, [this, editor] { + auto that = const_cast(this); + emit that->commitData(editor); + emit that->closeEditor(editor); + }); + connect(editor, &ShortcutWidget::cancel, this, [this, editor] { + auto that = const_cast(this); + emit that->closeEditor(editor); + }); return editor; } else if (index.column() == EventListModel::connectColumn) { return nullptr; @@ -170,18 +177,4 @@ QSize EventListDelegate::sizeHint(const QStyleOptionViewItem &option, const QMod return QStyledItemDelegate::sizeHint(option, index); } -void EventListDelegate::commitAndClose() -{ - if (auto *editor = qobject_cast(sender())) { - emit commitData(editor); - emit closeEditor(editor); - } -} - -void EventListDelegate::close() -{ - if (auto *editor = qobject_cast(sender())) - emit closeEditor(editor); -} - } // namespace QmlDesigner. diff --git a/src/plugins/qmldesigner/components/eventlist/eventlistdelegate.h b/src/plugins/qmldesigner/components/eventlist/eventlistdelegate.h index 62ab74b617c..1589525df00 100644 --- a/src/plugins/qmldesigner/components/eventlist/eventlistdelegate.h +++ b/src/plugins/qmldesigner/components/eventlist/eventlistdelegate.h @@ -39,9 +39,6 @@ protected: QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override; private: - void close(); - void commitAndClose(); - static bool hasConnectionColumn(QObject *parent); static QRect connectButtonRect(const QStyleOptionViewItem &option); }; diff --git a/src/plugins/qmldesigner/components/eventlist/nodelistdelegate.cpp b/src/plugins/qmldesigner/components/eventlist/nodelistdelegate.cpp index b56f57ef0fb..b36f9577d69 100644 --- a/src/plugins/qmldesigner/components/eventlist/nodelistdelegate.cpp +++ b/src/plugins/qmldesigner/components/eventlist/nodelistdelegate.cpp @@ -51,18 +51,4 @@ bool NodeListDelegate::eventFilter(QObject *editor, QEvent *event) return QStyledItemDelegate::eventFilter(editor, event); } -void NodeListDelegate::commitAndClose() -{ - if (auto *editor = qobject_cast(sender())) { - emit commitData(editor); - emit closeEditor(editor); - } -} - -void NodeListDelegate::close() -{ - if (auto *editor = qobject_cast(sender())) - emit closeEditor(editor); -} - } // namespace QmlDesigner. diff --git a/src/plugins/qmldesigner/components/eventlist/nodelistdelegate.h b/src/plugins/qmldesigner/components/eventlist/nodelistdelegate.h index 6bfb7a6bf28..31fbe465ee3 100644 --- a/src/plugins/qmldesigner/components/eventlist/nodelistdelegate.h +++ b/src/plugins/qmldesigner/components/eventlist/nodelistdelegate.h @@ -16,10 +16,6 @@ public: protected: bool eventFilter(QObject *editor, QEvent *event) override; - -private: - void close(); - void commitAndClose(); }; } // namespace QmlDesigner. diff --git a/src/plugins/qmldesigner/components/timelineeditor/easingcurvedialog.cpp b/src/plugins/qmldesigner/components/timelineeditor/easingcurvedialog.cpp index b6b49d054d7..a2fb6339f31 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/easingcurvedialog.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/easingcurvedialog.cpp @@ -41,12 +41,12 @@ EasingCurveDialog::EasingCurveDialog(const QList &frames, QWidget *pa { setWindowFlag(Qt::Tool, true); - auto tw = new QTabWidget; - tw->setTabPosition(QTabWidget::East); - tw->addTab(m_splineEditor, "Curve"); - tw->addTab(m_text, "Text"); + m_tabWidget = new QTabWidget; + m_tabWidget->setTabPosition(QTabWidget::East); + m_tabWidget->addTab(m_splineEditor, "Curve"); + m_tabWidget->addTab(m_text, "Text"); - connect(tw, &QTabWidget::currentChanged, this, &EasingCurveDialog::tabClicked); + connect(m_tabWidget, &QTabWidget::currentChanged, this, &EasingCurveDialog::tabClicked); connect(m_text, &QPlainTextEdit::textChanged, this, &EasingCurveDialog::textChanged); auto labelFont = m_label->font(); @@ -105,7 +105,7 @@ EasingCurveDialog::EasingCurveDialog(const QList &frames, QWidget *pa grid->addLayout(vbox, 0, 0); grid->addWidget(presetBar, 0, 1, Qt::AlignBottom); - grid->addWidget(tw); + grid->addWidget(m_tabWidget); grid->addWidget(m_presets, 1, 1); grid->addLayout(m_durationLayout, 2, 0); grid->addLayout(buttonLayout, 2, 1); @@ -126,7 +126,6 @@ EasingCurveDialog::EasingCurveDialog(const QList &frames, QWidget *pa connect(durationEdit, &QSpinBox::valueChanged, m_splineEditor, &SplineEditor::setDuration); connect(animateButton, &QPushButton::clicked, m_splineEditor, &SplineEditor::animate); - resize(QSize(1421, 918)); } @@ -185,7 +184,7 @@ bool EasingCurveDialog::apply() } AbstractView *view = m_frames.first().view(); - return view->executeInTransaction("EasingCurveDialog::apply", [this](){ + return view->executeInTransaction("EasingCurveDialog::apply", [this] { auto expression = m_splineEditor->easingCurve().toString(); for (const auto &frame : std::as_const(m_frames)) frame.bindingProperty(m_easingCurveProperty).setExpression(expression); @@ -201,29 +200,22 @@ void EasingCurveDialog::textChanged() void EasingCurveDialog::tabClicked(int id) { - if (auto tw = qobject_cast(sender())) { - int seid = tw->indexOf(m_splineEditor); - if (seid == id) { - for (int i = 0; i < m_durationLayout->count(); ++i) { - auto *item = m_durationLayout->itemAt(i); - if (auto *widget = item->widget()) - widget->show(); - } - - auto curve = m_splineEditor->easingCurve(); - curve.fromString(m_text->toPlainText()); - m_splineEditor->setEasingCurve(curve); - - } else { - for (int i = 0; i < m_durationLayout->count(); ++i) { - auto *item = m_durationLayout->itemAt(i); - if (auto *widget = item->widget()) - widget->hide(); - } - - auto curve = m_splineEditor->easingCurve(); - m_text->setPlainText(curve.toString()); + const int seid = m_tabWidget->indexOf(m_splineEditor); + if (seid == id) { + for (int i = 0; i < m_durationLayout->count(); ++i) { + if (auto *widget = m_durationLayout->itemAt(i)->widget()) + widget->show(); } + auto curve = m_splineEditor->easingCurve(); + curve.fromString(m_text->toPlainText()); + m_splineEditor->setEasingCurve(curve); + } else { + for (int i = 0; i < m_durationLayout->count(); ++i) { + if (auto *widget = m_durationLayout->itemAt(i)->widget()) + widget->hide(); + } + auto curve = m_splineEditor->easingCurve(); + m_text->setPlainText(curve.toString()); } } diff --git a/src/plugins/qmldesigner/components/timelineeditor/easingcurvedialog.h b/src/plugins/qmldesigner/components/timelineeditor/easingcurvedialog.h index 06ce53c2305..039697db5a3 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/easingcurvedialog.h +++ b/src/plugins/qmldesigner/components/timelineeditor/easingcurvedialog.h @@ -9,9 +9,10 @@ #include QT_BEGIN_NAMESPACE +class QHBoxLayout; class QLabel; class QPlainTextEdit; -class QHBoxLayout; +class QTabWidget; QT_END_NAMESPACE namespace QmlDesigner { @@ -33,32 +34,21 @@ public: private: bool apply(); - void textChanged(); - void tabClicked(int id); - void presetTabClicked(int id); - void buttonsClicked(QDialogButtonBox::StandardButton button); - void updateEasingCurve(const EasingCurve &curve); private: + QTabWidget *m_tabWidget = nullptr; SplineEditor *m_splineEditor = nullptr; - QPlainTextEdit *m_text = nullptr; - PresetEditor *m_presets = nullptr; - QHBoxLayout *m_durationLayout = nullptr; - QDialogButtonBox *m_buttons = nullptr; - QLabel *m_label = nullptr; - QList m_frames; - PropertyName m_easingCurveProperty; }; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 32abfe73853..4e98ab92589 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -62,11 +62,12 @@ #include #include #include -#include #include #include +#include #include +#include #include #include #include @@ -82,9 +83,10 @@ #include #include -#include "nanotrace/nanotrace.h" #include +#include + static Q_LOGGING_CATEGORY(qmldesignerLog, "qtc.qmldesigner", QtWarningMsg) using namespace QmlDesigner::Internal; @@ -162,7 +164,7 @@ public: SettingsPage settingsPage{externalDependencies}; DesignModeWidget mainWidget; QtQuickDesignerFactory m_qtQuickDesignerFactory; - bool blockEditorChange = false; + Utils::Guard m_ignoreChanges; Utils::UniqueObjectPtr toolBar; Utils::UniqueObjectPtr statusBar; QHash m_traceIdentifierDataHash; @@ -497,7 +499,7 @@ void QmlDesignerPlugin::hideDesigner() void QmlDesignerPlugin::changeEditor() { - if (d->blockEditorChange) + if (d->m_ignoreChanges.isLocked()) return; clearDesigner(); @@ -666,18 +668,12 @@ void QmlDesignerPlugin::enforceDelayedInitialize() DesignDocument *QmlDesignerPlugin::currentDesignDocument() const { - if (d) - return d->documentManager.currentDesignDocument(); - - return nullptr; + return d ? d->documentManager.currentDesignDocument() : nullptr; } Internal::DesignModeWidget *QmlDesignerPlugin::mainWidget() const { - if (d) - return &d->mainWidget; - - return nullptr; + return d ? &d->mainWidget : nullptr; } QWidget *QmlDesignerPlugin::createProjectExplorerWidget(QWidget *parent) const @@ -687,21 +683,15 @@ QWidget *QmlDesignerPlugin::createProjectExplorerWidget(QWidget *parent) const void QmlDesignerPlugin::switchToTextModeDeferred() { - QTimer::singleShot(0, this, [] () { + QTimer::singleShot(0, this, [] { Core::ModeManager::activateMode(Core::Constants::MODE_EDIT); }); } void QmlDesignerPlugin::emitCurrentTextEditorChanged(Core::IEditor *editor) { - d->blockEditorChange = true; + const std::lock_guard locker(d->m_ignoreChanges); emit Core::EditorManager::instance()->currentEditorChanged(editor); - d->blockEditorChange = false; -} - -void QmlDesignerPlugin::emitAssetChanged(const QString &assetPath) -{ - emit assetChanged(assetPath); } double QmlDesignerPlugin::formEditorDevicePixelRatio() @@ -717,7 +707,7 @@ double QmlDesignerPlugin::formEditorDevicePixelRatio() void QmlDesignerPlugin::contextHelp(const Core::IContext::HelpCallback &callback, const QString &id) { - emitUsageStatisticsHelpRequested(id); + emitUsageStatistics(Constants::EVENT_HELP_REQUESTED + id); QmlDesignerPlugin::instance()->viewManager().qmlJSEditorContextHelp(callback); } @@ -733,7 +723,7 @@ void QmlDesignerPlugin::emitUsageStatistics(const QString &identifier) const int currentTime = privateInstance()->timer.elapsed(); const int currentDuration = (currentTime - activeData.time); if (currentDuration < activeData.maxDuration) - instance()->emitUsageStatisticsUsageDuration(activeData.newIdentifer, currentDuration); + emit instance()->usageStatisticsUsageDuration(activeData.newIdentifer, currentDuration); privateInstance()->m_activeTraceIdentifierDataHash.remove(identifier); } @@ -761,11 +751,6 @@ void QmlDesignerPlugin::emitUsageStatisticsContextAction(const QString &identifi emitUsageStatistics(Constants::EVENT_ACTION_EXECUTED + identifier); } -void QmlDesignerPlugin::emitUsageStatisticsHelpRequested(const QString &identifier) -{ - emitUsageStatistics(Constants::EVENT_HELP_REQUESTED + identifier); -} - AsynchronousImageCache &QmlDesignerPlugin::imageCache() { return m_instance->d->projectManager.asynchronousImageCache(); @@ -776,36 +761,22 @@ void QmlDesignerPlugin::registerPreviewImageProvider(QQmlEngine *engine) m_instance->d->projectManager.registerPreviewImageProvider(engine); } - -bool isParent(QWidget *parent, QWidget *widget) -{ - if (!widget) - return false; - - if (widget == parent) - return true; - - return isParent(parent, widget->parentWidget()); -} - void QmlDesignerPlugin::trackWidgetFocusTime(QWidget *widget, const QString &identifier) { - connect(qApp, - &QApplication::focusChanged, - widget, - [widget, identifier](QWidget *from, QWidget *to) { - static QElapsedTimer widgetUsageTimer; - static QString lastIdentifier; - if (isParent(widget, to)) { - if (!lastIdentifier.isEmpty()) - emitUsageStatisticsTime(lastIdentifier, widgetUsageTimer.elapsed()); - widgetUsageTimer.restart(); - lastIdentifier = identifier; - } else if (isParent(widget, from) && lastIdentifier == identifier) { - emitUsageStatisticsTime(identifier, widgetUsageTimer.elapsed()); - lastIdentifier.clear(); - } - }); + connect(qApp, &QApplication::focusChanged, + widget, [widget, identifier](QWidget *from, QWidget *to) { + static QElapsedTimer widgetUsageTimer; + static QString lastIdentifier; + if (widget->isAncestorOf(to)) { + if (!lastIdentifier.isEmpty()) + emitUsageStatisticsTime(lastIdentifier, widgetUsageTimer.elapsed()); + widgetUsageTimer.restart(); + lastIdentifier = identifier; + } else if (widget->isAncestorOf(from) && lastIdentifier == identifier) { + emitUsageStatisticsTime(identifier, widgetUsageTimer.elapsed()); + lastIdentifier.clear(); + } + }); } void QmlDesignerPlugin::registerCombinedTracedPoints(const QString &identifierFirst, @@ -880,14 +851,13 @@ void QmlDesignerPlugin::closeFeedbackPopup() void QmlDesignerPlugin::emitUsageStatisticsTime(const QString &identifier, int elapsed) { - QTC_ASSERT(instance(), return); emit instance()->usageStatisticsUsageTimer(normalizeIdentifier(identifier), elapsed); } void QmlDesignerPlugin::emitUsageStatisticsUsageDuration(const QString &identifier, int elapsed) { - QTC_ASSERT(instance(), return ); + QTC_ASSERT(instance(), return); emit instance()->usageStatisticsUsageDuration(identifier, elapsed); } diff --git a/src/plugins/qmldesigner/qmldesignerplugin.h b/src/plugins/qmldesigner/qmldesignerplugin.h index e9e8847fbe1..ebb2e2bda9c 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.h +++ b/src/plugins/qmldesigner/qmldesignerplugin.h @@ -66,15 +66,12 @@ public: void switchToTextModeDeferred(); void emitCurrentTextEditorChanged(Core::IEditor *editor); - void emitAssetChanged(const QString &assetPath); - static double formEditorDevicePixelRatio(); static void contextHelp(const Core::IContext::HelpCallback &callback, const QString &id); static void emitUsageStatistics(const QString &identifier); static void emitUsageStatisticsContextAction(const QString &identifier); - static void emitUsageStatisticsHelpRequested(const QString &identifier); static void emitUsageStatisticsTime(const QString &identifier, int elapsed); static void emitUsageStatisticsUsageDuration(const QString &identifier, int elapsed); diff --git a/src/plugins/qmldesigner/shortcutmanager.cpp b/src/plugins/qmldesigner/shortcutmanager.cpp index 87a873339df..e4eeb476225 100644 --- a/src/plugins/qmldesigner/shortcutmanager.cpp +++ b/src/plugins/qmldesigner/shortcutmanager.cpp @@ -45,6 +45,11 @@ namespace QmlDesigner { +static DesignDocument *currentDesignDocument() +{ + return QmlDesignerPlugin::instance()->currentDesignDocument(); +} + ShortCutManager::ShortCutManager() : QObject() , m_exportAsImageAction(tr("Export as &Image...")) @@ -58,9 +63,7 @@ ShortCutManager::ShortCutManager() , m_duplicateAction(tr("&Duplicate")) , m_selectAllAction(tr("Select &All")) , m_escapeAction(this) -{ - -} +{} void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContext, const Core::Context &qmlDesignerFormEditorContext, @@ -327,16 +330,24 @@ void ShortCutManager::selectAll() void ShortCutManager::connectUndoActions(DesignDocument *designDocument) { if (designDocument) { - connect(designDocument, &DesignDocument::undoAvailable, this, &ShortCutManager::undoAvailable); - connect(designDocument, &DesignDocument::redoAvailable, this, &ShortCutManager::redoAvailable); + connect(designDocument, &DesignDocument::undoAvailable, this, + [this, designDocument](bool isAvailable) { + if (currentDesignDocument() == designDocument) + m_undoAction.setEnabled(isAvailable); + }); + connect(designDocument, &DesignDocument::redoAvailable, this, + [this, designDocument](bool isAvailable) { + if (currentDesignDocument() == designDocument) + m_redoAction.setEnabled(isAvailable); + }); } } void ShortCutManager::disconnectUndoActions(DesignDocument *designDocument) { - if (currentDesignDocument()) { - disconnect(designDocument, &DesignDocument::undoAvailable, this, &ShortCutManager::undoAvailable); - disconnect(designDocument, &DesignDocument::redoAvailable, this, &ShortCutManager::redoAvailable); + if (designDocument) { + disconnect(designDocument, &DesignDocument::undoAvailable, this, nullptr); + disconnect(designDocument, &DesignDocument::redoAvailable, this, nullptr); } } @@ -351,29 +362,6 @@ void ShortCutManager::updateUndoActions(DesignDocument *designDocument) } } -DesignDocument *ShortCutManager::currentDesignDocument() const -{ - return QmlDesignerPlugin::instance()->currentDesignDocument(); -} - -void ShortCutManager::undoAvailable(bool isAvailable) -{ - auto documentController = qobject_cast(sender()); - if (currentDesignDocument() && - currentDesignDocument() == documentController) { - m_undoAction.setEnabled(isAvailable); - } -} - -void ShortCutManager::redoAvailable(bool isAvailable) -{ - auto documentController = qobject_cast(sender()); - if (currentDesignDocument() && - currentDesignDocument() == documentController) { - m_redoAction.setEnabled(isAvailable); - } -} - void ShortCutManager::goIntoComponent() { if (currentDesignDocument() diff --git a/src/plugins/qmldesigner/shortcutmanager.h b/src/plugins/qmldesigner/shortcutmanager.h index b97fd834ee7..70b019217ca 100644 --- a/src/plugins/qmldesigner/shortcutmanager.h +++ b/src/plugins/qmldesigner/shortcutmanager.h @@ -30,8 +30,6 @@ public: void connectUndoActions(DesignDocument *designDocument); void disconnectUndoActions(DesignDocument *designDocument); void updateUndoActions(DesignDocument *designDocument); - DesignDocument *currentDesignDocument() const; - void updateActions(Core::IEditor* editor); private: @@ -43,8 +41,6 @@ private: void duplicateSelected(); void paste(); void selectAll(); - void undoAvailable(bool isAvailable); - void redoAvailable(bool isAvailable); void goIntoComponent(); private: diff --git a/src/plugins/qmldesigner/utils/filedownloader.cpp b/src/plugins/qmldesigner/utils/filedownloader.cpp index 2b0dacea2da..e0842763624 100644 --- a/src/plugins/qmldesigner/utils/filedownloader.cpp +++ b/src/plugins/qmldesigner/utils/filedownloader.cpp @@ -74,7 +74,7 @@ void FileDownloader::start() QNetworkReply *reply = Utils::NetworkAccessManager::instance()->get(request); m_reply = reply; - QNetworkReply::connect(reply, &QNetworkReply::readyRead, this, [this, reply]() { + QNetworkReply::connect(reply, &QNetworkReply::readyRead, this, [this, reply] { bool isDownloadingFile = false; QString contentType; if (!reply->hasRawHeader("Content-Type")) { @@ -115,7 +115,7 @@ void FileDownloader::start() emit reply->redirectAllowed(); }); - QNetworkReply::connect(reply, &QNetworkReply::finished, this, [this, reply]() { + QNetworkReply::connect(reply, &QNetworkReply::finished, this, [this, reply] { if (reply->error()) { if (reply->error() != QNetworkReply::OperationCanceledError) { qWarning() << Q_FUNC_INFO << m_url << reply->errorString(); @@ -282,7 +282,7 @@ void FileDownloader::doProbeUrl() emit reply->redirectAllowed(); }); - QNetworkReply::connect(reply, &QNetworkReply::finished, this, [this, reply]() { + QNetworkReply::connect(reply, &QNetworkReply::finished, this, [this, reply] { if (reply->error()) return; @@ -295,22 +295,18 @@ void FileDownloader::doProbeUrl() reply->deleteLater(); }); - QNetworkReply::connect(reply, - &QNetworkReply::errorOccurred, - this, - [this](QNetworkReply::NetworkError code) { + QNetworkReply::connect(reply, &QNetworkReply::errorOccurred, + this, [this, reply](QNetworkReply::NetworkError code) { + if (QQmlData::wasDeleted(this)) { + qDebug() << Q_FUNC_INFO << "FileDownloader was deleted."; + return; + } - if (QQmlData::wasDeleted(this)) { - qDebug() << Q_FUNC_INFO << "FileDownloader was deleted."; - return; - } + qDebug() << Q_FUNC_INFO << "Network error:" << code << reply->errorString(); - qDebug() << Q_FUNC_INFO << "Network error:" << code - << qobject_cast(sender())->errorString(); - - m_available = false; - emit availableChanged(); - }); + m_available = false; + emit availableChanged(); + }); } void FileDownloader::setTargetFilePath(const QString &path) diff --git a/src/plugins/qmldesigner/utils/fileextractor.cpp b/src/plugins/qmldesigner/utils/fileextractor.cpp index 67dc68aca90..efc72b79944 100644 --- a/src/plugins/qmldesigner/utils/fileextractor.cpp +++ b/src/plugins/qmldesigner/utils/fileextractor.cpp @@ -216,14 +216,16 @@ void FileExtractor::extract() m_targetFolder = m_targetPath.toString() + "/" + m_archiveName; // If the target directory already exists, remove it and its content - QDir targetDir(m_targetFolder); - if (targetDir.exists() && m_clearTargetPathContents) - targetDir.removeRecursively(); - if (m_alwaysCreateDir) { - // Create a new directory to generate a proper creation date - targetDir.mkdir(m_targetFolder); - } + QTC_ASSERT(!m_targetPath.isEmpty(), return ); + + FilePath targetFilePath = FilePath::fromUserInput(m_targetFolder); + if (targetFilePath.exists() && m_clearTargetPathContents) + targetFilePath.removeRecursively(); + + // Create a new directory to generate a proper creation date + if (m_alwaysCreateDir) + targetFilePath.createDir(); const auto sourceAndCommand = Unarchiver::sourceAndCommand(m_sourceFile); QTC_ASSERT(sourceAndCommand, return); @@ -261,6 +263,8 @@ void FileExtractor::extract() void QmlDesigner::FileExtractor::removeTempTargetPath() { if (m_isTempTargetPath && m_targetPath.exists()) { + QTC_ASSERT(m_targetPath.toString().startsWith(QDir::tempPath()), qDebug() << m_targetPath; + return ); m_targetPath.removeRecursively(); m_isTempTargetPath = false; }