diff --git a/doc/qtdesignstudio/examples/doc/treadmilMcu.qdoc b/doc/qtdesignstudio/examples/doc/treadmilMcu.qdoc index ddb138ede1e..419ad37b0e2 100644 --- a/doc/qtdesignstudio/examples/doc/treadmilMcu.qdoc +++ b/doc/qtdesignstudio/examples/doc/treadmilMcu.qdoc @@ -22,7 +22,7 @@ \section1 Getting the MCU Treadmill design to Figma \list 1 - \li Get the optimized MCU Treadmill for Figma design from \l {https://git.qt.io/public-demos/qtdesign-studio/-/blob/treadmill-revision-revision/examples/TreadmillMcuDemo/figmadesign/McuDemo.fig} {here}. + \li Get the optimized MCU Treadmill for Figma design from \l {https://git.qt.io/public-demos/qtdesign-studio/-/blob/master/examples/TreadmillMcuDemo/figmadesign/McuDemo.fig} {here}. \li Go to \l {https://www.figma.com/}{Figma} and log in. \li Open the downloaded MCU Treadmill design in Figma. \endlist diff --git a/doc/qtdesignstudio/src/best practices/best-practices-glow.qdoc b/doc/qtdesignstudio/src/best practices/best-practices-glow.qdoc index 29847e73004..6caa58c1311 100644 --- a/doc/qtdesignstudio/src/best practices/best-practices-glow.qdoc +++ b/doc/qtdesignstudio/src/best practices/best-practices-glow.qdoc @@ -14,7 +14,7 @@ using image-based lighting) or add ambient light. Using the glow effect is one way to make your scene more realistic. - \image glow-example.webp + \image {glow-example.webp} {An example showing the difference between using a glow effect and not using a glow effect.} \section1 Creating a project with ExtendedSceneEnvironment @@ -29,7 +29,7 @@ \uicontrol {ExtendedSceneEnvironment} component from \uicontrol Components to the \uicontrol 2D or \uicontrol Navigator view. - \image ext-scene-env-navigator.webp + \image {ext-scene-env-navigator.webp} {The ExtendedSceneEnvironment in the Navigator view.} \section1 Enabling the Glow effect @@ -37,7 +37,7 @@ then, in the \uicontrol Properties view, select \uicontrol Enabled in the \uicontrol Glow section. - \image glow-properties.webp + \image {glow-properties.webp} {The Glow effect properties in the Properties view.} \note When setting up or experimenting with the glow effect, use the \l {Blend Modes}{Replace} blend mode to see the effect more clearly. @@ -52,7 +52,7 @@ properties is to change them directly in the \uicontrol Properties view in \QDS and see the changes live in the \uicontrol 2D view. - \image glow-example-project.webp + \image {glow-example-project.webp} {The Flashlight Example project running.} \section1 Basic properties @@ -96,13 +96,13 @@ \li Example \row \li Bloom disabled - \li \image bleed-scale-no.webp + \li \image {bleed-scale-no.webp} {A close-up of a light in the scene with Bloom disabled.} \row \li 8 - \li \image bleed-scale-8.webp + \li \image {bleed-scale-8.webp} {A close-up of a light in the scene with HDR Scale set to 8.} \row \li 1 - \li \image bleed-scale-1.webp + \li \image {bleed-scale-1.webp} {A close-up of a light in the scene with HDR Scale set to 1.} \endtable \section1 Blur Levels @@ -122,13 +122,13 @@ \li Example \row \li 1, 2, 3 - \li \image glow_low_blur_levels.webp + \li \image {glow_low_blur_levels.webp} {A close-up of a light in the scene with Blur level set to 1, 2, 3.} \row \li 5, 6, 7 - \li \image glow_high_blur_levels.webp + \li \image {glow_high_blur_levels.webp} {A close-up of a light in the scene with Blur level set to 5, 6, 7.} \row \li 1, 2, 3, 4, 5, 6, 7 - \li \image glow_all_blur_levels.webp + \li \image {glow_all_blur_levels.webp} {A close-up of a light in the scene with Blur level set to 1, 2, 3, 4, 5, 6, 7.} \endtable \section2 Blend modes @@ -143,21 +143,21 @@ \row \li Additive \li Often recommended for outdoor scenes with a visible sky or sun. - \li \image glow-additive-blend.webp + \li \image {glow-additive-blend.webp} {A close-up of a light in the scene with Blend mode set to Additive.} \row \li Screen \li Similar to \uicontrol {Additive}, but the result is less bright. - \li \image glow-screen-blend.webp + \li \image {glow-screen-blend.webp} {A close-up of a light in the scene with Blend mode set to Additive.} \row \li SoftLight \li Often recommended for in-door environments. - \li \image glow-softlight-blend.webp + \li \image {glow-softlight-blend.webp} {A close-up of a light in the scene with Blend mode set to SoftLight.} \row \li Replace \li Does not perform any blending, but displays only the contribution the glow effect would blend with the actual content. In practice, this is useful for experimenting and troubleshooting when setting up the glow effect. - \li \image glow-replace-blend.webp + \li \image {glow-replace-blend.webp} {A close-up of a light in the scene with Blend mode set to Replace.} \endtable \section1 Improvement properties @@ -187,13 +187,13 @@ \li Example \row \li No effect - \li \image glow-no-enhancment.webp + \li \image {glow-no-enhancment.webp} {A close-up of a light in the scene with no effect.} \row \li High Quality - \li \image glow-high-quality.webp + \li \image {glow-high-quality.webp} {A close-up of a light in the scene with the High Quality effect.} \row \li Bicubic Upsampling - \li \image glow-bicubic.webp + \li \image {glow-bicubic.webp} {A close-up of a light in the scene with the Bicubic Upsampling effect.} \endtable diff --git a/doc/qtdesignstudio/src/best practices/best-practices-shader-code.qdoc b/doc/qtdesignstudio/src/best practices/best-practices-shader-code.qdoc index 7ddd066e961..0e1148ca7b9 100644 --- a/doc/qtdesignstudio/src/best practices/best-practices-shader-code.qdoc +++ b/doc/qtdesignstudio/src/best practices/best-practices-shader-code.qdoc @@ -146,7 +146,7 @@ You can control these settings either from the \uicontrol Properties view or from code. - \image timeRunning_property.webp + \image {timeRunning_property.webp} {The Running setting turned on in the Properties view.} \code NorthernLights { diff --git a/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc b/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc index 1c8d5ef8dd6..f22dbdf0cf0 100644 --- a/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc @@ -13,7 +13,7 @@ new components that you can create instances of. You can then use the instances of the new components in other components. - \image qtquick-components-custom.png "Custom components in My Components" + \image {qtquick-components-custom.png} {Custom components in My Components.} Custom components are stored in \uicontrol Components > \uicontrol {My Components}. You can create instances of custom components @@ -86,7 +86,7 @@ in \uicontrol Navigator or the \uicontrol {2D} view, and select \uicontrol {Create Component} in the context menu. - \image qtcreator-move-component-into-separate-file.png + \image {qtcreator-move-component-into-separate-file.png} {The Move Component into Separate File dialog.} Give the new component a name, and select whether properties are set for the new component or for the original one. @@ -117,7 +117,7 @@ \uicontrol Navigator or \uicontrol {2D} view and select \uicontrol {Merge File with Template} in the context menu. - \image qmldesigner-merge-with-template.png "Merge with Template dialog" + \image {qmldesigner-merge-with-template.png} {The Merge with Template dialog.} In the \uicontrol Template field, select the file to use as a template. */ diff --git a/doc/qtdesignstudio/src/components/qtquick-controls.qdoc b/doc/qtdesignstudio/src/components/qtquick-controls.qdoc index aa650ae7d65..227e86cee5b 100644 --- a/doc/qtdesignstudio/src/components/qtquick-controls.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-controls.qdoc @@ -13,7 +13,7 @@ available in \uicontrol Components > \uicontrol {Qt Quick Controls} > \uicontrol Controls. - \image qtquick-designer-qtquickcontrols-types.png "Qt Quick Controls components" + \image {qtquick-designer-qtquickcontrols-types.png} {The Qt Quick Controls components in the Components view.} The following types of controls are available for user interaction: @@ -36,7 +36,7 @@ You can set control properties in the \l Properties view. - \image qtquick-designer-control-properties.png "Control section in Properties" + \image {qtquick-designer-control-properties.png} {The Control section in the Properties view.} The \uicontrol Enable check box indicates whether the control is enabled. @@ -64,7 +64,7 @@ most suitable for a use case and discuss the values you can set for button properties in the \uicontrol Properties view. - \image qtquick-designer-button-types.png "Button controls in the 2D view" + \image {qtquick-designer-button-types.png} {Different types of button controls in the 2D view.} Recommendations for buttons that contain text: @@ -387,20 +387,20 @@ \target progress-bar-control \section2 Progress Bar - \image qtquickcontrols2-progressbar.gif "Progress bar" + \image {qtquickcontrols2-progressbar.gif} {An animation of a Progress Bar running.} \uicontrol {Progress Bar} indicates the progress of an operation. You can specify the initial value in the \uicontrol Value field, but it should be updated regularly. Specify the range in the \uicontrol From and \uicontrol To fields, which can both contain any value. - \image qtquick-designer-progressbar-properties.png "Progress Bar properties" + \image {qtquick-designer-progressbar-properties.png} {The Progress Bar section in the Properties view.} Select the \uicontrol Indeterminate check box when unable to determine the size of the item being downloaded, or if the download progress might get interrupted due to a network failure. - \image qtquickcontrols2-progressbar-indeterminate.gif + \image {qtquickcontrols2-progressbar-indeterminate.gif} {A runnning Progress Bar with the Indeterminate property turned on.} The indeterminate mode is similar to a \l {Busy Indicator} in that both can be used to indicate background activity. Due to their visual differences, @@ -561,7 +561,7 @@ \section2 Tumbler - \image qtquickcontrols2-tumbler-wrap.gif + \image {qtquickcontrols2-tumbler-wrap.gif} {An animation of a Tumbler with multiple wheels spinning.} \uicontrol Tumbler allows users to select an option from a spinnable \e wheel of items. It is useful when there are too many options to use, for @@ -573,7 +573,7 @@ field. Select the index of the current option in the \uicontrol {Current index} field. - \image qtquick-designer-tumbler-properties.png "Tumbler properties" + \image {qtquick-designer-tumbler-properties.png} {The Tumbler section in the Properties view.} To enable wrapping, select the \uicontrol Wrap check box. @@ -600,18 +600,18 @@ If the total width of the buttons exceeds the available width of the tab bar, it automatically becomes \l{Flickable}{flickable}. - \image qtquickcontrols2-tabbar-flickable.png + \image {qtquickcontrols2-tabbar-flickable.png} {A Tab Bar exceeding the available width.} \section1 Tool Bar - \image qtquickcontrols2-toolbar.png + \image {qtquickcontrols2-toolbar.png} {A Tool Bar} \uicontrol {Tool Bar} contains application-wide and context-sensitive actions and controls, such as navigation buttons and search fields. A toolbar is commonly used as a header or footer of an \l ApplicationWindow. Select the toolbar position in the \uicontrol Position field. - \image qtquick-designer-toolbar-properties.png "Tool Bar properties" + \image {qtquick-designer-toolbar-properties.png} {The Tool Bar section in the Properties View.} \uicontrol {Tool Button} is nearly identical to \l Button, but it has a graphical appearance that makes it more suitable for insertion into a diff --git a/doc/qtdesignstudio/src/components/qtquick-images.qdoc b/doc/qtdesignstudio/src/components/qtquick-images.qdoc index 6528388f1ae..151ef30bfed 100644 --- a/doc/qtdesignstudio/src/components/qtquick-images.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-images.qdoc @@ -204,12 +204,12 @@ the ISO icon in the \l Navigator or \l {2D} view, and then select \uicontrol {Choose Icon} in the context menu. - \image studio-iso-icon.png + \image {studio-iso-icon.png} {An Iso Icon selected in the 2D view.} You can use the \l{Picking colors}{color picker} in \l Properties to set the value of \uicontrol {Icon color}. - \image iso-icon-browser.png + \image {iso-icon-browser.png} {The Iso Icon browser window.} \section1 Summary of the image components diff --git a/doc/qtdesignstudio/src/components/qtquick-shapes.qdoc b/doc/qtdesignstudio/src/components/qtquick-shapes.qdoc index 310615b0df9..ac386724832 100644 --- a/doc/qtdesignstudio/src/components/qtquick-shapes.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-shapes.qdoc @@ -199,7 +199,7 @@ fields in the \uicontrol Opacity section are used to hide and show either the front or back side of the item at a time. - \image studio-flipable.png + \image {studio-flipable.png} {A Flipable in the 2D, Navigator, and Properties view.} The \uicontrol {Flip angle} property is used to animate the angle of the component to produce the flipping effect. The value of the diff --git a/doc/qtdesignstudio/src/developers/studio-accessing-output-issues-and-warnings.qdoc b/doc/qtdesignstudio/src/developers/studio-accessing-output-issues-and-warnings.qdoc index 7bcb6588abb..7f26ce04664 100644 --- a/doc/qtdesignstudio/src/developers/studio-accessing-output-issues-and-warnings.qdoc +++ b/doc/qtdesignstudio/src/developers/studio-accessing-output-issues-and-warnings.qdoc @@ -8,7 +8,7 @@ \title Accessing output, issue, and warning messages - \image studio-output-view.webp Qt Design Studio Output view + \image {studio-output-view.webp} {The Qt Design Studio Output view.} \QDS projects generate output information that represent the executed processes. It also shows you the issues that stop a project from @@ -41,10 +41,10 @@ \li Message example \row \li Issue notification - \li \image studio-issue-message.webp + \li \image {studio-issue-message.webp} {Example issue notification in the Output view.} \row \li Warning notification - \li \image studio-warning-message.webp + \li \image {studio-warning-message.webp} {Example warning notification in the Output view.} \endtable diff --git a/doc/qtdesignstudio/src/developers/studio-jump-to-the-code.qdoc b/doc/qtdesignstudio/src/developers/studio-jump-to-the-code.qdoc index 7284eee1a1c..d5518ffeed5 100644 --- a/doc/qtdesignstudio/src/developers/studio-jump-to-the-code.qdoc +++ b/doc/qtdesignstudio/src/developers/studio-jump-to-the-code.qdoc @@ -26,7 +26,7 @@ \li Select \uicontrol {Jump to the Code}. \endlist - \image jump-to-the-code-from-navigator-view.webp + \image {jump-to-the-code-from-navigator-view.webp} {Selecting Jump to the Code from the context menu in the Navigator view.} \section1 Jump to the Code from the 2D view @@ -35,7 +35,7 @@ \li Select \uicontrol {Jump to the Code}. \endlist - \image jump-to-the-code-from-2D-view.webp + \image {jump-to-the-code-from-2D-view.webp} {Selecting Jump to the Code from the context menu in the 2D view.} \note Alternatively, you can select the component in the \uicontrol {Navigator} view or in the \uicontrol {2D} view and select \key {F4}. That takes you to the code @@ -50,7 +50,7 @@ \li Select \uicontrol {Jump to the Code}. \endlist - \image jump-to-the-code-from-state-view.webp + \image {jump-to-the-code-from-state-view.webp} {Selecting Jump to the Code from the context menu in the States view.} \section1 Jump to the Code from the Connections view @@ -60,6 +60,6 @@ to jump to the code segment related to the connection. \endlist - \image jump-to-the-code-from-connections-view.webp + \image {jump-to-the-code-from-connections-view.webp} {Selecting Jump to the Code from the context menu in the Connections view.} */ diff --git a/doc/qtdesignstudio/src/effects-concept.qdoc b/doc/qtdesignstudio/src/effects-concept.qdoc index a79198edf25..849b5484d32 100644 --- a/doc/qtdesignstudio/src/effects-concept.qdoc +++ b/doc/qtdesignstudio/src/effects-concept.qdoc @@ -19,7 +19,7 @@ designed for both experienced developers and beginners, simplifying the process of developing visual effects without requiring extensive knowledge of shader coding. -\image northern-lights-effect.webp +\image {northern-lights-effect.webp} {A northern lights effect in Effect Composer.} Key features of the \QDS Effect Composer: diff --git a/doc/qtdesignstudio/src/mcus/qtdesignstudio-creating-projects-for-mcus.qdoc b/doc/qtdesignstudio/src/mcus/qtdesignstudio-creating-projects-for-mcus.qdoc index ea8912f12dd..247a456f27b 100644 --- a/doc/qtdesignstudio/src/mcus/qtdesignstudio-creating-projects-for-mcus.qdoc +++ b/doc/qtdesignstudio/src/mcus/qtdesignstudio-creating-projects-for-mcus.qdoc @@ -12,7 +12,7 @@ project. When you create a project with the wizard, all the necessary files are created, you can adjust the project settings, and save custom presets. - \image studio-preset-for-mcus.png + \image studio-preset-for-mcus.png {The Qt for MCU preset on the Qt Design Studio Welcome page.} Using the \uicontrol {\QMCU} preset creates an application that uses a subset of the default components that you can deploy, run, and debug on MCU boards. diff --git a/doc/qtdesignstudio/src/mcus/qtdesignstudio-developing-applications-for-mcus.qdoc b/doc/qtdesignstudio/src/mcus/qtdesignstudio-developing-applications-for-mcus.qdoc index 00f8b6f9ae2..9d8291f34af 100644 --- a/doc/qtdesignstudio/src/mcus/qtdesignstudio-developing-applications-for-mcus.qdoc +++ b/doc/qtdesignstudio/src/mcus/qtdesignstudio-developing-applications-for-mcus.qdoc @@ -18,7 +18,7 @@ mode to modify UI files (.ui.qml). For more information, see \l {Implementing applications}. - \image qds-mcu-target-deployment.png + \image {qds-mcu-target-deployment.png} {The workflow of using Qt Design Studio and Qt for MCUs to create an application for an MCU target device.} With Qt Creator, you can test, preview, and fine-tune your designs directly on the desktop or on an actual MCU target device. As a developer you can use diff --git a/doc/qtdesignstudio/src/overviews/qt-design-viewer-navigation.qdoc b/doc/qtdesignstudio/src/overviews/qt-design-viewer-navigation.qdoc index 61a4c378e4a..2f945b58dae 100644 --- a/doc/qtdesignstudio/src/overviews/qt-design-viewer-navigation.qdoc +++ b/doc/qtdesignstudio/src/overviews/qt-design-viewer-navigation.qdoc @@ -68,7 +68,7 @@ \endlist - \image web-navigation-components.png + \image {web-navigation-components.png} {The structure of the web application in the Navigator view.} \section1 Creating the pages @@ -88,7 +88,7 @@ \li Set \uicontrol {Root Item} to \e Rectangle. \endlist - \image web-navigation-new-file.png + \image {web-navigation-new-file.png} {The New File dialog.} When you have created the new page, select \e rectangle in \uicontrol Navigator, and in the \uicontrol Properties view: @@ -114,7 +114,7 @@ \li Top, 100 \li Left, 50 \endlist - \image web-navigation-page-margins.png + \image {web-navigation-page-margins.png} {The Anchor and Margin properties for the web application header.} \endlist Now, with the first page done, create two more pages in the same way. For these @@ -124,13 +124,13 @@ You can change the file that you are working on from the drop-down menu in the toolbar. Now, select \e Screen01.ui.qml from this menu to go back to your main page. -\image web-navigation-change-file.png +\image {web-navigation-change-file.png} {Changing the file in top toolbar.} You can see the pages you created under \uicontrol {My Components} in the \uicontrol Components view. To edit a component, right-click it in \uicontrol Components and select \uicontrol {Edit Component} -\image web-navigation-page-components.png +\image {web-navigation-page-components.png} {The web app pages in the Components view.} \section1 Organizing the pages @@ -139,7 +139,7 @@ To organize the pages vertically: \list 1 \li From \uicontrol Components, drag each of the pages to \e columnLayout in \uicontrol Navigator. - \image web-navigation-components-2.png + \image {web-navigation-components-2.png} {} \li Select \e columnLayout in Navigator and in \uicontrol Properties: \list \li Next to \uicontrol Size > \uicontrol W and \uicontrol Size > @@ -189,7 +189,7 @@ main rectangle so that it adapts to the window size: \imageactioniconbinding next to \uicontrol Width and select \uicontrol {Set Binding}. \li Enter \c {Window.width} - \image web-navigation-size-binding.png + \image {web-navigation-size-binding.png} {Window.width set in Binding Editor.} \li Repeat step 2 and 3 for \uicontrol Height and set the value to \c {Window.height}. \endlist @@ -226,7 +226,7 @@ vertically to the correct place: \li Select \imageactioniconbinding next to \uicontrol Width and select \uicontrol {Set Binding}. \li Enter \c {parent.width}. - \image web-navigation-size-binding-2.png + \image {web-navigation-size-binding-2.png} {parent.width set in Binding Editor.} \li In \uicontrol Navigator: \list 1 \li Select \e Button and on the \uicontrol Button tab in \uicontrol Properties, diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-overview.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-overview.qdoc index f93808d2619..b0dcc5f8e37 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-overview.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-overview.qdoc @@ -13,7 +13,7 @@ You can use \QBF to export designs from Figma to a \e {.qtbridge} archive that you can \l{Importing 2D Assets}{import} to projects in \QDS. - \image studio-figma-export.png + \image {studio-figma-export.png} {Qt Bridge for Figma open in Figma.} The following topics describe setting up and using \QBF: diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc index edcdeed411a..b58151a5e0e 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-figma-using.qdoc @@ -226,7 +226,7 @@ \section2 Settings - \image qt-figma-bridge-settings.png + \image {qt-figma-bridge-settings.png} {The Qt Bridge for Figma settings window in Figma.} You can export assets in the selected format (JPG, PNG, or SVG). diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-overview.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-overview.qdoc index 80c41467290..fe198b067f3 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-overview.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-overview.qdoc @@ -13,7 +13,7 @@ You can use \QBPS to export designs from Adobe Photoshop to \e {.metadata} format that you can \l{Importing 2D Assets}{import} to projects in \QDS. - \image studio-ps-export.png + \image {studio-ps-export.png} {Qt Bridge for Photoshop open in Adobe Photoshop.} The following topics describe setting up and using \QBPS: diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc index 489dbabeeff..0e7a4443f85 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc @@ -81,7 +81,7 @@ enter a password in the \uicontrol Password field. \li To test that the connection is working properly, start \QBPS and select the settings icon in the top right corner. - \image qt-bridge-settings.png + \image {qt-bridge-settings.png} {The Qt Bridge for Photoshop settings window in Adobe Photoshop.} \li In the \uicontrol Password field, enter the password you entered in Adobe Photoshop and select \uicontrol {Connect}. \li In the \uicontrol {Export Path} group, select the folder button diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-using.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-using.qdoc index f6d78347464..7c68cea1377 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-using.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-using.qdoc @@ -133,7 +133,7 @@ \l{Property Aliases}{property aliases} to fetch the values from other properties. - \image qt-bridge.png + \image {qt-bridge.png} {The Qt Bridge for Photoshop default home screen.} \section2 Specifying settings for exporting assets @@ -238,7 +238,7 @@ In the \uicontrol {ID Suffix} field, specify an ID suffix that will be appended to all auto generated IDs. - \image qt-bridge-qml-id-settings.png + \image {qt-bridge-qml-id-settings.png} {The ID Prefix field highlighted in the settings.} \section1 Cloning documents @@ -246,7 +246,7 @@ allows the user to filter out certain kind of layers and groups. In the \QBPS \uicontrol Settings dialog, select \uicontrol {Clone} to start cloning the document. - \image qt-bridge-clone.png + \image {qt-bridge-clone.png} {The Clone button highlighted in the Clone document settings.} \section2 Clone options The following exclusion options can be selected to exclude certain kind of layers and @@ -273,7 +273,7 @@ \note The sanitization is done in memory and the document must be saved to keep the sanitized state. - \image qt-bridge-sanitize.png + \image {qt-bridge-sanitize.png} {The Sanitize button highlighted in the settings.} \section1 Extending \QBPS You can change the default behavior of \QBPS with the help of a JSX script. One can write @@ -297,11 +297,11 @@ PSD layer instance. \endlist - \note Please refer to \l {https://www.adobe.com/devnet/photoshop/scripting.html} + \note See the \l {https://www.adobe.com/devnet/photoshop/scripting.html} {Adobe Photoshop CC Javascript} scripting guide to understand the object model and \e Document and \e Layer instances. - \image qt-bridge-override.png + \image {qt-bridge-override.png} {The Script Path field highlighted in the settings.} In the \QBPS \uicontrol Settings dialog, select \uicontrol {Override JSX Script} to set the override JSX script. @@ -317,14 +317,14 @@ Select the \uicontrol Import button to launch the \uicontrol Import panel. Alternatively, \QB import can be launched from \uicontrol Window > \uicontrol Extensions. - \image qt-bridge-import.png + \image {qt-bridge-import.png} {The Qt Bridge import dialog.} Create a new PSD document and launch the \uicontrol Import dialog. Open the metadata file to import and select \uicontrol Import. \note The import process removes all the existing layers in the selected PSD document. - \image qt-bridge-import-warning.png + \image {qt-bridge-import-warning.png} {An import warning in the Qt Bridge import dialog.} The following guidelines are followed to generate the Photoshop document: \list diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-overview.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-overview.qdoc index 12156d6733b..118bc1f5042 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-overview.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-overview.qdoc @@ -13,7 +13,7 @@ You can use \QBSK to export designs from Sketch to \e {.metadata} format that you can \l{Importing 2D Assets}{import} to projects in \QDS. - \image studio-sketch-export.png + \image {studio-sketch-export.png} {Qt Bridge for Sketch open in Sketch.} The following topics describe setting up and using \QBSK: diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-using.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-using.qdoc index d052bf3138c..69e815f8f64 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-using.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-sketch-using.qdoc @@ -160,7 +160,7 @@ component in \QDS. Or you could export a button as a Qt Quick Controls \l Button component. - \image qt-sketch-bridge.png + \image {qt-sketch-bridge.png} {Qt Bridge for Sketch open with default settings.} \section2 Specifying settings for exporting assets @@ -253,7 +253,7 @@ You can export assets into JPG, PNG, or SVG format. To specify export path and asset format, select \uicontrol Settings. - \image qt-sketch-bridge-settings.png + \image {qt-sketch-bridge-settings.png} {Qt Bridge for Sketch export settings with export path and asset format specified.} \QBSK exports assets to a .qtbridge archive named after your Sketch file. By default, the directory is located inside the parent directory @@ -303,5 +303,5 @@ To export a library, select \uicontrol Export. \QBSK asks you whether you want to export the complete library or to unlink the symbols. - \image qt-sketch-bridge-library.png + \image {qt-sketch-bridge-library.png} {Qt Bridge for Sketch Export Library dialog.} */ diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-overview.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-overview.qdoc index 13442251676..edf28dca206 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-overview.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-overview.qdoc @@ -16,7 +16,7 @@ You can use \QBXD to export designs from Adobe XD to \e {.qtbridge} format that you can \l{Importing 2D Assets}{import} to projects in \QDS. - \image qt-bridge-xd.png + \image {qt-bridge-xd.png} {The Qt Bridge for Adobe XD open in Adobe XD.} The following topics describe setting up and using \QBXD: diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-setup.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-setup.qdoc index a20bfddd969..e9087911f3b 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-setup.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-setup.qdoc @@ -29,7 +29,7 @@ \note Since the plugin is not distributed through Adobe's marketplace, during the installation Adobe XD might warn about the third-party developer. - \image qt-bridge-xd-warn.png + \image {qt-bridge-xd-warn.png} {The Install Qt Bridge plugin warning dialog.} You can launch the plugin from \uicontrol Plugins > \uicontrol {\QB}. */ diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-using.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-using.qdoc index 0bc76b1eca5..647beea35b0 100644 --- a/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-using.qdoc +++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-xd-using.qdoc @@ -68,7 +68,7 @@ exported. The \uicontrol {Home} panel displays and allows layer annotation for export. - \image qt-bridge-xd-home.png + \image {qt-bridge-xd-home.png} {The Qt Bridge for Adobe XD home panel.} \list 1 \li In the \uicontrol ID field, enter a unique and descriptive name. @@ -180,8 +180,8 @@ \list 1 \li Select \uicontrol Settings. - \image qt-bridge-xd-menu.png - \image qt-bridge-xd-settings.png + \image {qt-bridge-xd-menu.png} {Settings selected in the file menu.} + \image {qt-bridge-xd-settings.png} {The Qt Bridge for Adobe XD Settings panel.} \li You can now edit the following settings: \list diff --git a/doc/qtdesignstudio/src/qtdesignstudio-exporting-and-importing.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-exporting-and-importing.qdoc index bc5ccdc12ab..55d4708fc72 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-exporting-and-importing.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-exporting-and-importing.qdoc @@ -19,7 +19,7 @@ The following image describes the workflow in a basic way using \QBPS and \QDS: - \image studio-workflow.png + \image {studio-workflow.png} {The complete designer-developer workflow from design tool to a finished application.} The workflow consists of the following steps: diff --git a/doc/qtdesignstudio/src/qtdesignstudio-qt-runtime-version.qdocinc b/doc/qtdesignstudio/src/qtdesignstudio-qt-runtime-version.qdocinc index fb74f9180db..c92a1545bd4 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-qt-runtime-version.qdocinc +++ b/doc/qtdesignstudio/src/qtdesignstudio-qt-runtime-version.qdocinc @@ -5,6 +5,6 @@ \QDS runs projects using a specific version of Qt. In \QDS, find the Qt runtime version in the bottom toolbar. - \image studio-qt-development-kit.webp + \image {studio-qt-development-kit.webp} {The kit selector dropdown menu in the bottom toolbar.} //! [qt-runtime-version] */ diff --git a/doc/qtdesignstudio/src/qtdesignstudio-using-effect-maker-effects.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-using-effect-maker-effects.qdoc index 42588f7d2b4..0a97a5e4dc4 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-using-effect-maker-effects.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-using-effect-maker-effects.qdoc @@ -23,11 +23,11 @@ \li Right-click in the \uicontrol Assets view and select \uicontrol {New Effect}. \QDS creates an effect file and opens it in \QQEM. - \image qt-quick-effect-maker.webp + \image {qt-quick-effect-maker.webp} {The Qt Effect Maker default view.} \li Edit the effect. \li In \QQEM, go to \uicontrol File > \uicontrol Save. \li With the default settings, select \uicontrol OK. - \image effect-maker-export.png + \image {effect-maker-export.png} {Qt Effect Maker export effect dialog.} \endlist Now, you can close \QQEM and return to \QDS and apply the @@ -39,6 +39,6 @@ from the \uicontrol Assets view to the component in the \uicontrol 2D or \uicontrol Navigator view. - \image apply-effect-maker-effect.webp + \image {apply-effect-maker-effect.webp} {Qt Design Studio with a Qt Effect Maker effect applied.} */ diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-camera.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-camera.qdoc index f40b0633e04..bd598bc4399 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-camera.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-camera.qdoc @@ -137,7 +137,7 @@ \li In \uicontrol Navigator, select the camera. \li In \uicontrol Properties > \uicontrol {Look-at-Node}, select the object that the camera should look at. - \image camera-look-at-node.webp + \image {camera-look-at-node.webp} {Selecting the Look-at-Node object in the Camera sections in the Properties view.} \endlist When you set a camera to look at an object, the camera automatically rotates to diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc index 9b365110a77..b26d9c962c4 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc @@ -186,7 +186,7 @@ In the 3D view, you can show a small window displaying the camera view. - \image 3d-view-camera-view.webp + \image {3d-view-camera-view.webp} {The Camera view in the 3D view.} To toggle this view, select \imagevisibilityon diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc index cafa97421a5..b98be425d0b 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc @@ -23,7 +23,7 @@ For more information about exporting 3D graphics, see \l{Exporting 3D assets}. - \image studio-import-3d.webp + \image {studio-import-3d.webp} {The Asset Import dialog.} \section1 Importing a 3D asset diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc index 8b4f76e90f1..56191e5b602 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc @@ -249,7 +249,7 @@ \li Select \uicontrol Bake. \endlist - \image bake-lights-dialog.png + \image {bake-lights-dialog.png} {The Lights Baking Setup dialog.} \section2 Manually baking lightmaps for a 3D model @@ -261,7 +261,7 @@ \list 1 \li From \uicontrol Components, drag a \uicontrol {Baked Lightmap} component to the 3D model in the \uicontrol Navigator view. - \image baked-lightmaps-navigator.png + \image {baked-lightmaps-navigator.png} {The Baked Lightmap component in the Navigator view.} \li In the \uicontrol Navigator view, select \e bakedLightmap, and in the \uicontrol Properties view: \list @@ -289,15 +289,15 @@ \list 1 \li In the \uicontrol Navigator view, right-click the subcomponent and select \uicontrol {Edit Component}. - \image baked-lightmaps-edit-component.png + \image {baked-lightmaps-edit-component.png} {Selecting Edit Component from the context menu in the Navigator view.} \li In the \uicontrol Navigator view, select the root component. \li In the \uicontrol Properties view, select \imageplus in the \uicontrol {Local Custom Properties} section. \li Add a new property, set \uicontrol Type to alias. - \image baked-lightmaps-add-property.png + \image {baked-lightmaps-add-property.png} {The Add New Property dialog.} \li For the property, set the value to the ID of the 3D model that you want to bake lightmaps for. - \image baked-lightmaps-property-value.png + \image {baked-lightmaps-property-value.png} {The custom property set to sphere in the Local Custom Tab in the Properties view.} \li In the \uicontrol Navigator view, select the 3D model and in the \uicontrol Properties view: \list @@ -306,10 +306,10 @@ \endlist \li Save your changes (\key {Ctrl+S}) and return to the main project file. To do this, select the bread crumb in the top toolbar. - \image baked-lightmaps-exit-component.png + \image {baked-lightmaps-exit-component.png} {Selecting the main project file bread crumb in the top toolbar.} \li From the \uicontrol Components view, drag a \uicontrol {Baked Lightmap} component to the subcomponent in the \uicontrol Navigator view. - \image baked-lightmaps-navigator-blm.png + \image {baked-lightmaps-navigator-blm.png} {The Baked Lightmap component in the Navigator view.} \li In the \uicontrol Navigator view, select the subcomponent and go to the \uicontrol Code view. \li In the \uicontrol Code view, you need to set the properties for the model inside the sub diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-loader-3d.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-loader-3d.qdoc index f9034f4a227..7d33d87540e 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-loader-3d.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-loader-3d.qdoc @@ -67,10 +67,10 @@ \li From \uicontrol {Components}, drag a \uicontrol Loader3D component to \e scene in the \uicontrol Navigator or \uicontrol{3D} view. \li In \uicontrol {Navigator}, select \e{loader3D}. - \image loader3d-navigator.png + \image {loader3d-navigator.png} {The loader3D component in the Navigator view.} \li In \uicontrol {Properties}, select \uicontrol{Source} and select a QML file. - \image loader3d-select-source.png + \image {loader3d-select-source.png} {Setting the Loader3D Source setting in the Properties view.} \endlist \section1 Setting Loader3D to load a Component3D component @@ -85,12 +85,12 @@ \li In \uicontrol {Navigator}, select the filter icon and clear \uicontrol {Show Only Visible Components}. This makes the \uicontrol Component3D component visible in \uicontrol Navigator. - \image navigator-show-all-loader.png + \image {navigator-show-all-loader.png} {Toggling component visibility in the Navigator view.} \li In \uicontrol {Navigator}, select \e{loader3D}. \li In \uicontrol {Properties}, select \uicontrol{Source Component} and select \e {component3D}. - \image loader3d-select-source-component.png + \image {loader3d-select-source-component.png} {Selecting Source Component in the Properties view.} \endlist \section1 Setting the Visibility of loading components @@ -101,7 +101,7 @@ \list 1 \li In \uicontrol Properties > \uicontrol Loader3D, select the \uicontrol Asynchronous check box. - \image loader3d-visibility.png + \image {loader3d-visibility.png} {The Asynchronous setting turned on in the Properties view.} \li In \uicontrol {Visibility}, select \imageactionicon to open the actions menu, and then select \uicontrol {Set Binding}. diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc index 14cc442158e..6834b5005b2 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-particles.qdoc @@ -311,7 +311,7 @@ \uicontrol Navigator. You can also drag it to the \uicontrol{3D} view. \endlist - \image studio-3d-particles-sprite-template.png + \image {studio-3d-particles-sprite-template.png} {The particle system template components in the Component view.} \section1 Performance considerations @@ -536,7 +536,7 @@ Specify properties for line particles in \uicontrol Properties > \uicontrol {Line Particle}. - \image studio-3d-properties-line-particle.png + \image {studio-3d-properties-line-particle.png} {The Line Particle properties in the Properties view.} \uicontrol {Segments} defines the number of segments in each line. @@ -845,7 +845,7 @@ Specify properties for emit bursts in \uicontrol Properties > \uicontrol {Dynamic Burst}. - \image studio-3d-properties-particle-dynamic-burst.png + \image {studio-3d-properties-particle-dynamic-burst.png} {The Dynamic Burst properties in the Properties view.} \uicontrol {Trigger Mode} defines when the burst is triggered: @@ -1022,7 +1022,7 @@ Specify settings for \uicontrol Repeller component instances in \uicontrol Properties > \uicontrol {Particle Repeller}. - \image studio-3d-properties-particle-repeller.png + \image {studio-3d-properties-particle-repeller.png} {The Repeller properties in the Properties view.} \uicontrol {Outer Radius} defines the outer radius of the repeller. The particle is not affected until it enters this radius and the repel @@ -1038,7 +1038,7 @@ \uicontrol {Scale Affector} scales particles based on their lifetime and other parameters. - \image studio-3d-properties-particle-scale-affector.png + \image {studio-3d-properties-particle-scale-affector.png} {The Particle Scale Affector properties in the Properties view.} \uicontrol {Minimum Size} defines the minimum size that the affector can scale particles to. diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-repeater-3d.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-repeater-3d.qdoc index ec3ed257926..87632a6e703 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-repeater-3d.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-repeater-3d.qdoc @@ -74,7 +74,7 @@ \e scene in \uicontrol Navigator. \li Select \e repeater3D in \uicontrol Navigator and in \uicontrol Properties, set \uicontrol Model to 4. - \image repeater3d-model-property.png + \image {repeater3d-model-property.png} {The Repeater Model property set to 4 in the Properties view.} \endlist Now, you have set up the \uicontrol Repeater3D component to use a numeric model that draws four instances of the same item. Next, you need to add the @@ -90,11 +90,11 @@ \li Select \uicontrol {Set binding} to open \uicontrol {Binding Editor}. \li In the binding editor, enter \c{index * 150}. This sets the X location to increase by 150 for each of the cube instances. - \image repeater3d-index-binding.png + \image {repeater3d-index-binding.png} {index * 150 set in Bindings Editor.} \li Select \uicontrol OK and go to the \uicontrol{3D} view to see the result. \endlist - \image repeater3d-numeric-model.webp + \image {repeater3d-numeric-model.webp} {Four cubes rendered with the Repeater component in the 3D view.} \section1 Adding a Repeater3D component with a List Model @@ -172,7 +172,7 @@ \list 1 \li From \uicontrol Components, drag a \uicontrol Sphere to \e _3DRepeater in \uicontrol Navigator. - \image repeater3d-listmodel-navigator.png + \image {repeater3d-listmodel-navigator.png} {The Sphere component in the Navigator view.} \li Select \e sphere in \uicontrol Navigator and in the \uicontrol Properties view, select \imageactionicon next to \uicontrol Scale > \uicontrol X. @@ -180,7 +180,7 @@ \li In the binding editor, enter \c{radius}. This sets the X scale to the radius value defined in the list model for each of the sphere instances. - \image repeater3d-radius-binding.png + \image {repeater3d-radius-binding.png} {radius set in Binding Editor.} \li Select \uicontrol OK. \li Repeat steps 2 to 5 for \uicontrol Scale > \uicontrol Y and \uicontrol Scale > \uicontrol Z. @@ -196,7 +196,7 @@ \li Select \uicontrol {Set binding} to open \uicontrol {Binding Editor}. \li In the binding editor, enter \c{index * 1000}. This sets the X location to increase by 1000 for each of the sphere instances. - \image repeater3d-location-binding.png + \image {repeater3d-location-binding.png} {index * 1000 set in Binding Editor.} \li Select \uicontrol OK and go to the \uicontrol{3D} view to see the result. You need to zoom out to see all the spheres. \endlist diff --git a/doc/qtdesignstudio/src/qtquickdesigner-components/qtdesignstudio-logic-helpers.qdoc b/doc/qtdesignstudio/src/qtquickdesigner-components/qtdesignstudio-logic-helpers.qdoc index e0b24f21772..077b953a67f 100644 --- a/doc/qtdesignstudio/src/qtquickdesigner-components/qtdesignstudio-logic-helpers.qdoc +++ b/doc/qtdesignstudio/src/qtquickdesigner-components/qtdesignstudio-logic-helpers.qdoc @@ -246,7 +246,7 @@ is under or over the going value. We then use \uicontrol {And Operator} components to determine whether the value is below minimum or above maximum. - \image studio-logic-helper-combining-example.gif + \image {studio-logic-helper-combining-example.gif} {An animated example of an app combining several logic helpers.} We use one \uicontrol {String Mapper} component to map the slider value to a \uicontrol Text component that displays the price, as @@ -295,7 +295,7 @@ and sell hints. For this purpose, we create the states and set \c when conditions for them. - \image studio-logic-helper-combining-example.png + \image {studio-logic-helper-combining-example.png} {The different stats of the app in the States view.} First, we create a \e tooLow state and set a \c when condition to apply it when the value of the \uicontrol {Below min} field of diff --git a/doc/qtdesignstudio/src/reference/qtdesignstudio-keyboard-shortcuts.qdoc b/doc/qtdesignstudio/src/reference/qtdesignstudio-keyboard-shortcuts.qdoc index 3d1b1d00821..646876a3bfa 100644 --- a/doc/qtdesignstudio/src/reference/qtdesignstudio-keyboard-shortcuts.qdoc +++ b/doc/qtdesignstudio/src/reference/qtdesignstudio-keyboard-shortcuts.qdoc @@ -14,7 +14,7 @@ To view all \QDS functions in and their keyboard shortcuts, select \preferences > \uicontrol Environment > \uicontrol Keyboard. - \image qtcreator-keyboard-shortcuts.png + \image {qtcreator-keyboard-shortcuts.png} {Keyboard shortcut settings.} The shortcuts that are displayed in red color are associated with several functions. \QDS executes the function that is available in the current diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc index cc7f1e2cdb5..e91adb949fd 100644 --- a/doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc @@ -25,7 +25,7 @@ You can create bindings between components in \uicontrol Bindings. - \image qmldesigner-bindings.webp + \image {qmldesigner-bindings.webp} {The Bindings tab in the Connections view.} \section1 Creating bindings between component properties @@ -35,7 +35,7 @@ \li Place two components in the \uicontrol {2D} view. - \image qmldesigner-components-before-binding.webp + \image {qmldesigner-components-before-binding.webp} {Two components next to each other in the 2D view.} \li Name the first component as \e {viewBox}. \li Name the second component as \e {connectBox}. @@ -46,7 +46,7 @@ (\uicontrol Add) button to add a binding to the currently selected component. - \image qmldesigner-updated-bindings-editor.webp + \image qmldesigner-updated-bindings-editor.webp {The Add Binding dialog.} \li From the pop-up \uicontrol {Bindings editor}, in the \uicontrol From section, select \e {viewBox} as the parent component, then select its \uicontrol {border.color} @@ -58,7 +58,7 @@ instantly getting applied to the \uicontrol {color} of the \e {connectBox} component. - \image qmldesigner-components-after-binding.webp + \image qmldesigner-components-after-binding.webp {Two components next to each other in the 2D view with the property binding applied.} \endlist diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc index fd5e13e23f6..8cf4e901f8f 100644 --- a/doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc @@ -40,9 +40,9 @@ \li Select the \imageplus (\uicontrol Add) button to add a custom property for the currently selected component. - \image add-local-custom-property.png + \image {add-local-custom-property.png} {Selecting the Add button in the Properties view.} \li Set the \uicontrol Name and \uicontrol Type for the property. - \image add-new-property-dialog.png + \image {add-new-property-dialog.png} {Selecting the Type for the property in the Add New Property dialog.} \endlist \section1 Binding a property value @@ -69,14 +69,14 @@ \uicontrol {2D} view or in the \uicontrol {Navigator} view. \li Select \uicontrol {Properties} from the \uicontrol {Connections} view. - \image add-updated-local-custom-property.webp + \image {add-updated-local-custom-property.webp} {The Properties tab in the Connections view.} \li Select the \imageplus (\uicontrol Add) button to add a Custom property. \li From the pop-up \uicontrol {Custom property editor}, select the \uicontrol {Type} of the property you want to include. - \image add-updated-local-custom-property-editor.webp + \image {add-updated-local-custom-property-editor.webp} {The Custom Property Editor dialog.} \li Next, set the \uicontrol{Name} of the property. \li Set a value to the Custom property in the \uicontrol {Value} field. diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc index 683a01e2921..f231a9fcf74 100644 --- a/doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc @@ -45,7 +45,7 @@ put \b {logical conditions} on this \uicontrol Actions to control them according to your needs. - \image qmldesigner-connections-advanced.webp + \image {qmldesigner-connections-advanced.webp} {The Connections tab in the Connections view.} Initiate a new connection for a component: @@ -57,7 +57,7 @@ (\uicontrol Add) button to add a connection. \endlist - \image qmldesigner-connections-editor.webp + \image {qmldesigner-connections-editor.webp} {The Add Connection dialog.} Connect component \uicontrol Signal to \uicontrol Action: @@ -108,7 +108,7 @@ \li Follow the steps described above in Connect component \uicontrol Signal to \uicontrol Action. For a list of \uicontrol Actions and their properties, see \l {Action Properties}. - \image qmldesigner-connections-ConditionalAction-Autometic.webp + \image {qmldesigner-connections-ConditionalAction-Autometic.webp} {The Add Connection dialog with a JavaScript expression.} \li Open the \uicontrol {Manual Code Edit} window from the \uicontrol {Connections} view and write JavaScript expressions with components and logical expressions manually. @@ -118,7 +118,7 @@ level \e {if-else} expression. For nested level \e {if-else} expressions, use the \uicontrol {Manual Code Edit}. - \image qmldesigner-connections-ConditionalAction-Manual.webp + \image {qmldesigner-connections-ConditionalAction-Manual.webp} {A JavaScript code snippet in the Manual Code Edit dialog.} \endlist \section2 Action properties diff --git a/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc b/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc index 8238dc1b467..d5b90450eec 100644 --- a/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc @@ -162,7 +162,7 @@ (\uicontrol Export) button in \uicontrol Navigator to export a component as a property alias with a valid alias reference. - \image qmldesigner-export-item.png + \image {qmldesigner-export-item.png} {Selecting the Export button in the Navigator view.} You can then use the property alias in other components to \l{Working with connections}{create connections} to this component. diff --git a/doc/qtdesignstudio/src/views/qtquick-properties-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-properties-view.qdoc index 84faad338d9..24d1d7a80b3 100644 --- a/doc/qtdesignstudio/src/views/qtquick-properties-view.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-properties-view.qdoc @@ -44,7 +44,7 @@ \li A property that has been added inside a component. \endtable - \image custom-properties.png + \image {custom-properties.png} {Local Custom Properties and Exposed Custom Properties settings in the Settings view.} \section1 Viewing changes in properties @@ -81,21 +81,21 @@ \table \row - \li \image qmldesigner-boolean-true.png + \li \image {qmldesigner-boolean-true.png} {The Visibility property selected but not highlighted.} \li TRUE \li The component is visible by default. The visibility might be overridden by the visibility set in the base state. \row - \li \image qmldesigner-boolean-true-blue.png + \li \image {qmldesigner-boolean-true-blue.png} {The Visibility property selected and highlighted.} \li TRUE (highlighted) \li The component is explicitly set to visible. \row - \li \image qmldesigner-boolean-false.png + \li \image {qmldesigner-boolean-false.png} {The Visibility property not selected and not highlighted.} \li FALSE \li The component is hidden by default. The visibility might be overridden by the visibility set in the base state. \row - \li \image qmldesigner-boolean-false-blue.png + \li \image {qmldesigner-boolean-false-blue.png} {The Visibility property not selected but highlighted.} \li FALSE (hightlighted) \li The component is explicitly set to hidden. \endtable diff --git a/doc/qtdesignstudio/src/views/qtquick-properties.qdoc b/doc/qtdesignstudio/src/views/qtquick-properties.qdoc index f4ff275ec14..c31ca5d33f3 100644 --- a/doc/qtdesignstudio/src/views/qtquick-properties.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-properties.qdoc @@ -208,7 +208,7 @@ or \uicontrol Vertical in the \uicontrol {Gradient Controls} section of the color picker. - \image qtquick-designer-gradient-stops.gif + \image {qtquick-designer-gradient-stops.gif} {An Animation showing how to add and remove gradient stops.} Calculating gradients can be computationally expensive compared to the use of solid color fills or images. Consider using gradients only for @@ -462,5 +462,5 @@ you can also right-click components to open the inline editors from the context menu. - \image qmldesigner-inline-editing.png + \image qmldesigner-inline-editing.png {Selecting Edit Color from the context menu in the 2D view.} */ diff --git a/doc/qtdesignstudio/src/views/qtquick-states.qdoc b/doc/qtdesignstudio/src/views/qtquick-states.qdoc index a3daed09935..b87789f790a 100644 --- a/doc/qtdesignstudio/src/views/qtquick-states.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-states.qdoc @@ -183,10 +183,10 @@ Here, extended states are not used: - \image no-extended-state.webp + \image {no-extended-state.webp} {Three states in the States view with no extended state.} Here, \e State2 is extended from \e State1: - \image extended-state.webp + \image {extended-state.webp} {Three states in the States view with State2 extended from State1.} */ diff --git a/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc b/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc index 715a822fc51..82843990428 100644 --- a/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc @@ -37,7 +37,7 @@ of the timeline. Negative values are allowed. \li In the \uicontrol {End frame} field, set the last frame of the timeline. - \image timeline-settings-dialog.png + \image {timeline-settings-dialog.png} {The Timeline Settings dialog.} \endlist \li On the \uicontrol {Animation Settings} tab: \list @@ -87,13 +87,13 @@ . This creates another timeline. \li In the table below the \uicontrol {Animation Settings} tab, set the Timeline for the state where you want to use it. - \image timeline-settings-dialog-second.png + \image {timeline-settings-dialog-second.png} {Two timelines in the Timeline Settings dialog.} \endlist To set the keyframe values for the timeline you created, first select the state in \uicontrol {States} and the timeline is available in \uicontrol{Timelines}. - \image timeline-states.webp + \image {timeline-states.webp} {The Timeline and States views.} \section2 Setting keyframe values @@ -114,11 +114,11 @@ \li In the \l Properties view, select \imageactionicon (\uicontrol Actions) > \uicontrol {Insert Keyframe} for the property that you want to animate. - \image timeline-insert-keyframe.png + \image {timeline-insert-keyframe.png} {Selecting Insert Keyframe from the Action drop-down menu in the Properties view.} \li In the \l Timeline view, select the \uicontrol {Per Property Recording} button to start recording property changes. - \image timeline-per-property-recording.webp + \image {timeline-per-property-recording.webp} {Selecting the Per Property Recording button in the Timeline view.} \li Ensure that the playhead is in frame 0 and enter the value of the property in the field next to the property name on the timeline. Select \key Enter to save the value. @@ -155,7 +155,7 @@ next to the \uicontrol {Animation Settings} tab to delete the animation. If you have several animations, delete all. \li In \uicontrol {Expression binding}, enter \c {slider.value}. - \image timeline-settings-property-binding.png + \image {timeline-settings-property-binding.png} {Expression binding set to slider.value in the Timeline Settings dialog.} \endlist \section2 Binding animations to states @@ -172,7 +172,7 @@ the timeline with the animation you want to bind to the state. \li Double-click the value in the \uicontrol Animation field and select the animation you want to bind to the state. - \image timeline-bind-animation-state.png + \image {timeline-bind-animation-state.png} {Selecting an Animation in the Timeline Settings dialog window to bind it to a state.} \endlist \endlist To bind a state to a certain keyframe in an animation without running the diff --git a/doc/qtdesignstudio/src/views/studio-content-library.qdoc b/doc/qtdesignstudio/src/views/studio-content-library.qdoc index 2bbb3d6e691..9d71b3d0677 100644 --- a/doc/qtdesignstudio/src/views/studio-content-library.qdoc +++ b/doc/qtdesignstudio/src/views/studio-content-library.qdoc @@ -26,7 +26,7 @@ Assets added to \uicontrol {User Assets} are always available in \uicontrol {Content Library} regardless of what project you are working on. - \image content-library.webp + \image {content-library.webp} {The Materials tab in the Content Library view.} \section1 Adding a material to your project @@ -86,7 +86,7 @@ \section1 User Assets - \image user-assets.webp + \image {user-assets.webp} {The User Assets tab in the Content Library view.} Add assets to \uicontrol {User Assets} to access them in any project. diff --git a/doc/qtdesignstudio/src/views/studio-qtinsight.qdoc b/doc/qtdesignstudio/src/views/studio-qtinsight.qdoc index ef77d6e3641..65dbbf3f8d2 100644 --- a/doc/qtdesignstudio/src/views/studio-qtinsight.qdoc +++ b/doc/qtdesignstudio/src/views/studio-qtinsight.qdoc @@ -21,7 +21,7 @@ \l{https://www.qt.io/product/insight/onboarding-instructions}{Getting Started with Qt Insight} documentation. - \image qt-insight-view.png + \image {qt-insight-view.png} {The Qt Insight view.} In \QDS, you can do the following with Qt Insight: \list diff --git a/doc/qtdesignstudio/src/views/studio-translations.qdoc b/doc/qtdesignstudio/src/views/studio-translations.qdoc index f4f9310478d..c31faaa56a0 100644 --- a/doc/qtdesignstudio/src/views/studio-translations.qdoc +++ b/doc/qtdesignstudio/src/views/studio-translations.qdoc @@ -106,13 +106,13 @@ \li \uicontrol{Exceeds boundaries} highlights translations where the text is too long to fit in the text object. \endlist - \image translation-tester.png + \image {translation-tester.png} {The Translation Tester dialog with all highlights selected.} \li Select \uicontrol{Run Tests}. \endlist When the test has completed, you can see the test result highlights in the \uicontrol {2D} view. - \image qml-translation-test-result.png + \image {qml-translation-test-result.png} {The Test Results dialog.} If the test finds an error, it is highlighted for all languages. For example, if a translation is missing for Swedish, it is also highlighted diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTextureContextMenu.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTextureContextMenu.qml index 3dba67243fe..f64306743f7 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTextureContextMenu.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTextureContextMenu.qml @@ -13,12 +13,14 @@ StudioControls.Menu { property var targetTexture: null property bool hasSceneEnv: false property bool showRemoveAction: false // true: adds an option to remove targetTexture + property bool showInGraphicalShellVisible: false property bool canUse3D: targetTexture && ContentLibraryBackend.rootView.hasQuick3DImport && ContentLibraryBackend.rootView.hasMaterialLibrary - function popupMenu(targetTexture = null) + function popupMenu(targetTexture = null, showInGraphicalShellItemVisible = false) { this.targetTexture = targetTexture + root.showInGraphicalShellVisible = showInGraphicalShellItemVisible ContentLibraryBackend.rootView.updateSceneEnvState(); popup() } @@ -49,4 +51,20 @@ StudioControls.Menu { height: visible ? implicitHeight : 0 onTriggered: ContentLibraryBackend.userModel.removeTexture(root.targetTexture) } + + StudioControls.MenuSeparator { + visible: root.showInGraphicalShellVisible + height: visible ? StudioTheme.Values.border : 0 + } + + StudioControls.MenuItem { + text: ContentLibraryBackend.rootView.showInGraphicalShellMsg + + visible: root.showInGraphicalShellVisible + height: visible ? implicitHeight : 0 + + onTriggered: { + ContentLibraryBackend.rootView.showInGraphicalShell(root.targetTexture.textureParentPath) + } + } } diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryUserView.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryUserView.qml index 4ee3af47f83..15e36666d96 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryUserView.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryUserView.qml @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick +import QtQuick.Layouts import Qt.labs.qmlmodels import HelperWidgets as HelperWidgets import StudioControls as StudioControls @@ -79,171 +80,222 @@ Item { } } - HelperWidgets.ScrollView { - id: scrollView + ColumnLayout { + id: col + anchors.fill: parent + spacing: 0 - clip: true - interactive: !ctxMenuItem.opened && !ctxMenuTexture.opened - && !ContentLibraryBackend.rootView.isDragging && !HelperWidgets.Controller.contextMenuOpened - hideHorizontalScrollBar: true + Rectangle { + id: toolbar - Column { - Repeater { - id: categoryRepeater + width: parent.width + height: StudioTheme.Values.toolbarHeight + color: StudioTheme.Values.themeToolbarBackground - model: ContentLibraryBackend.userModel + HelperWidgets.AbstractButton { + style: StudioTheme.Values.viewBarButtonStyle + buttonIcon: StudioTheme.Constants.add_medium + enabled: (this.hasMaterial ?? false) + && hasModelSelection + && hasQuick3DImport + && hasMaterialLibrary + tooltip: qsTr("Add a custom bundle folder.") + onClicked: ContentLibraryBackend.rootView.browseBundleFolder() + x: 5 // left margin + } + } - delegate: HelperWidgets.Section { - id: section + HelperWidgets.ScrollView { + id: scrollView - width: root.width - leftPadding: StudioTheme.Values.sectionPadding - rightPadding: StudioTheme.Values.sectionPadding - topPadding: StudioTheme.Values.sectionPadding - bottomPadding: StudioTheme.Values.sectionPadding + Layout.fillWidth: true + Layout.fillHeight: true - caption: categoryTitle - dropEnabled: true - category: "ContentLib_User" + clip: true + interactive: !ctxMenuItem.opened && !ctxMenuTexture.opened + && !ContentLibraryBackend.rootView.isDragging && !HelperWidgets.Controller.contextMenuOpened + hideHorizontalScrollBar: true - function expandSection() { - section.expanded = true - } + Column { + Repeater { + id: categoryRepeater - property alias count: repeater.count + model: ContentLibraryBackend.userModel - onCountChanged: root.assignMaxCount() + delegate: HelperWidgets.Section { + id: section - onDropEnter: (drag) => { - let has3DNode = ContentLibraryBackend.rootView - .has3DNode(drag.getDataAsArrayBuffer(drag.formats[0])) - - let hasTexture = ContentLibraryBackend.rootView - .hasTexture(drag.formats[0], drag.urls) - - drag.accepted = (categoryTitle === "Textures" && hasTexture) - || (categoryTitle === "Materials" && drag.formats[0] === "application/vnd.qtdesignstudio.material") - || (categoryTitle === "3D" && has3DNode) - - section.highlight = drag.accepted - } - - onDropExit: { - section.highlight = false - } - - onDrop: (drag) => { - section.highlight = false - drag.accept() - section.expandSection() - - if (categoryTitle === "Textures") { - if (drag.formats[0] === "application/vnd.qtdesignstudio.assets") - ContentLibraryBackend.rootView.acceptTexturesDrop(drag.urls) - else if (drag.formats[0] === "application/vnd.qtdesignstudio.texture") - ContentLibraryBackend.rootView.acceptTextureDrop(drag.getDataAsString(drag.formats[0])) - } else if (categoryTitle === "Materials") { - ContentLibraryBackend.rootView.acceptMaterialDrop(drag.getDataAsString(drag.formats[0])) - } else if (categoryTitle === "3D") { - ContentLibraryBackend.rootView.accept3DDrop(drag.getDataAsArrayBuffer(drag.formats[0])) - } - } - - Grid { - width: section.width - section.leftPadding - section.rightPadding - spacing: StudioTheme.Values.sectionGridSpacing - columns: root.numColumns - - Repeater { - id: repeater - model: categoryItems - - delegate: DelegateChooser { - role: "bundleId" - - DelegateChoice { - roleValue: "UserMaterials" - ContentLibraryItem { - width: root.cellWidth - height: root.cellHeight - visible: modelData.bundleItemVisible && !infoText.visible - - onShowContextMenu: ctxMenuItem.popupMenu(modelData) - onAddToProject: ContentLibraryBackend.userModel.addToProject(modelData) - } - } - DelegateChoice { - roleValue: "UserTextures" - delegate: ContentLibraryTexture { - width: root.cellWidth - height: root.cellWidth // for textures use a square size since there is no name row - - onShowContextMenu: ctxMenuTexture.popupMenu(modelData) - } - } - DelegateChoice { - roleValue: "User3D" - delegate: ContentLibraryItem { - width: root.cellWidth - height: root.cellHeight - visible: modelData.bundleItemVisible && !infoText.visible - - onShowContextMenu: ctxMenuItem.popupMenu(modelData) - onAddToProject: ContentLibraryBackend.userModel.addToProject(modelData) - } - } - } - - onCountChanged: root.assignMaxCount() - } - } - - Text { - text: qsTr("No match found."); - color: StudioTheme.Values.themeTextColor - font.pixelSize: StudioTheme.Values.baseFontSize - leftPadding: 10 - visible: infoText.text === "" && !searchBox.isEmpty() && categoryNoMatch - } - - Text { - id: infoText - - text: { - let categoryName = (categoryTitle === "3D") ? categoryTitle + " assets" - : categoryTitle.toLowerCase() - if (!ContentLibraryBackend.rootView.isQt6Project) { - qsTr("Content Library is not supported in Qt5 projects.") - } else if (!ContentLibraryBackend.rootView.hasQuick3DImport && categoryTitle !== "Textures") { - qsTr('To use %1, add the QtQuick3D module and the View3D - component in the Components view, or click - - here.') - .arg(categoryName) - .arg(StudioTheme.Values.themeInteraction) - } else if (!ContentLibraryBackend.rootView.hasMaterialLibrary && categoryTitle !== "Textures") { - qsTr("Content Library is disabled inside a non-visual component.") - } else if (categoryEmpty) { - qsTr("There are no "+ categoryName + " in the User Assets.") - } else { - "" - } - } - textFormat: Text.RichText - color: StudioTheme.Values.themeTextColor - font.pixelSize: StudioTheme.Values.mediumFontSize - padding: 10 - visible: infoText.text !== "" - horizontalAlignment: Text.AlignHCenter - wrapMode: Text.WordWrap width: root.width + leftPadding: StudioTheme.Values.sectionPadding + rightPadding: StudioTheme.Values.sectionPadding + topPadding: StudioTheme.Values.sectionPadding + bottomPadding: StudioTheme.Values.sectionPadding - onLinkActivated: ContentLibraryBackend.rootView.addQtQuick3D() + caption: categoryTitle + captionTooltip: section.isCustomCat ? categoryBundlePath : "" + dropEnabled: true + category: "ContentLib_User" + showCloseButton: section.isCustomCat + closeButtonToolTip: qsTr("Remove folder") + closeButtonIcon: StudioTheme.Constants.deletepermanently_small - HoverHandler { - enabled: infoText.hoveredLink - cursorShape: Qt.PointingHandCursor + onCloseButtonClicked: { + ContentLibraryBackend.userModel.removeBundleDir(index) + } + + function expandSection() { + section.expanded = true + } + + property alias count: repeater.count + property bool isCustomCat: !["Textures", "Materials", "3D"].includes(section.caption); + + onCountChanged: root.assignMaxCount() + + onDropEnter: (drag) => { + let has3DNode = ContentLibraryBackend.rootView + .has3DNode(drag.getDataAsArrayBuffer(drag.formats[0])) + + let hasTexture = ContentLibraryBackend.rootView + .hasTexture(drag.formats[0], drag.urls) + + drag.accepted = (categoryTitle === "Textures" && hasTexture) + || (categoryTitle === "Materials" && drag.formats[0] === "application/vnd.qtdesignstudio.material") + || (categoryTitle === "3D" && has3DNode) + || (section.isCustomCat && hasTexture) + + section.highlight = drag.accepted + } + + onDropExit: { + section.highlight = false + } + + onDrop: (drag) => { + section.highlight = false + drag.accept() + section.expandSection() + + if (categoryTitle === "Textures") { + if (drag.formats[0] === "application/vnd.qtdesignstudio.assets") + ContentLibraryBackend.rootView.acceptTexturesDrop(drag.urls) + else if (drag.formats[0] === "application/vnd.qtdesignstudio.texture") + ContentLibraryBackend.rootView.acceptTextureDrop(drag.getDataAsString(drag.formats[0])) + } else if (categoryTitle === "Materials") { + ContentLibraryBackend.rootView.acceptMaterialDrop(drag.getDataAsString(drag.formats[0])) + } else if (categoryTitle === "3D") { + ContentLibraryBackend.rootView.accept3DDrop(drag.getDataAsArrayBuffer(drag.formats[0])) + } else { // custom bundle folder + if (drag.formats[0] === "application/vnd.qtdesignstudio.assets") + ContentLibraryBackend.rootView.acceptTexturesDrop(drag.urls, categoryBundlePath) + else if (drag.formats[0] === "application/vnd.qtdesignstudio.texture") + ContentLibraryBackend.rootView.acceptTextureDrop(drag.getDataAsString(drag.formats[0]), categoryBundlePath) + } + } + + Grid { + id: grid + + width: section.width - section.leftPadding - section.rightPadding + spacing: StudioTheme.Values.sectionGridSpacing + columns: root.numColumns + + property int catIdx: index + + Repeater { + id: repeater + + model: categoryItems + + delegate: DelegateChooser { + role: "bundleId" + + DelegateChoice { + roleValue: "UserMaterials" + ContentLibraryItem { + width: root.cellWidth + height: root.cellHeight + visible: modelData.bundleItemVisible && !infoText.visible + + onShowContextMenu: ctxMenuItem.popupMenu(modelData) + onAddToProject: ContentLibraryBackend.userModel.addToProject(modelData) + } + } + DelegateChoice { + roleValue: "UserTextures" + delegate: ContentLibraryTexture { + width: root.cellWidth + height: root.cellWidth // for textures use a square size since there is no name row + + onShowContextMenu: ctxMenuTexture.popupMenu(modelData, grid.catIdx > 2) + } + } + DelegateChoice { + roleValue: "User3D" + delegate: ContentLibraryItem { + width: root.cellWidth + height: root.cellHeight + visible: modelData.bundleItemVisible && !infoText.visible + + onShowContextMenu: ctxMenuItem.popupMenu(modelData) + onAddToProject: ContentLibraryBackend.userModel.addToProject(modelData) + } + } + } + + onCountChanged: root.assignMaxCount() + } + } + + Text { + text: qsTr("No match found."); + color: StudioTheme.Values.themeTextColor + font.pixelSize: StudioTheme.Values.baseFontSize + leftPadding: 10 + visible: infoText.text === "" && !searchBox.isEmpty() && categoryNoMatch + } + + Text { + id: infoText + + text: { + let categoryName = (categoryTitle === "3D") ? categoryTitle + " assets" + : categoryTitle.toLowerCase() + if (!ContentLibraryBackend.rootView.isQt6Project) { + qsTr("Content Library is not supported in Qt5 projects.") + } else if (!ContentLibraryBackend.rootView.hasQuick3DImport + && categoryTitle !== "Textures" && !section.isCustomCat) { + qsTr('To use %1, add the QtQuick3D module and the View3D + component in the Components view, or click + + here.') + .arg(categoryName) + .arg(StudioTheme.Values.themeInteraction) + } else if (!ContentLibraryBackend.rootView.hasMaterialLibrary + && categoryTitle !== "Textures" && !section.isCustomCat) { + qsTr("Content Library is disabled inside a non-visual component.") + } else if (categoryEmpty) { + qsTr("There are no items in this category.") + } else { + "" + } + } + textFormat: Text.RichText + color: StudioTheme.Values.themeTextColor + font.pixelSize: StudioTheme.Values.mediumFontSize + padding: 10 + visible: infoText.text !== "" + horizontalAlignment: Text.AlignHCenter + wrapMode: Text.WordWrap + width: root.width + + onLinkActivated: ContentLibraryBackend.rootView.addQtQuick3D() + + HoverHandler { + enabled: infoText.hoveredLink + cursorShape: Qt.PointingHandCursor + } } } } diff --git a/share/qtcreator/qmldesigner/designsystem/Main.qml b/share/qtcreator/qmldesigner/designsystem/Main.qml index 9578c6f8ef1..7b2344ecc67 100644 --- a/share/qtcreator/qmldesigner/designsystem/Main.qml +++ b/share/qtcreator/qmldesigner/designsystem/Main.qml @@ -23,12 +23,11 @@ Rectangle { readonly property int cellWidth: 200 readonly property int cellHeight: 40 - readonly property color textColor: "#ffffff" - readonly property color iconColor: "#959595" - readonly property color backgroundColor: "#2c2c2c" - readonly property color borderColor: "#444444" + readonly property color backgroundColor: StudioTheme.Values.themePanelBackground + // TODO This is not a proper color value, but will be fixed with new design + readonly property color borderColor: StudioTheme.Values.themeControlBackground_topToolbarHover - readonly property int borderWidth: 1 + readonly property int borderWidth: StudioTheme.Values.border readonly property int textSize: 18 readonly property int iconSize: 16 @@ -127,7 +126,7 @@ Rectangle { overlayInvalid.show() } - function showHeaderData(section: int, orientation: var) { + function showHeaderData(section: int, orientation: var, message: string) { if (orientation === Qt.Horizontal) { overlayInvalid.parent = horizontalHeaderView.contentItem overlayInvalid.cellItem = horizontalHeaderView.itemAtCell(Qt.point(overlay.section, 0)) @@ -136,7 +135,7 @@ Rectangle { overlayInvalid.cellItem = verticalHeaderView.itemAtCell(Qt.point(0, overlay.section)) } - notification.message = qsTr("This name is already in use, please use a different name.") + notification.message = message overlayInvalid.show() } @@ -1095,8 +1094,14 @@ Rectangle { // Revoke active focus from text field by forcing active focus on another item tableView.forceActiveFocus() - if (!result && overlayTextField.previousText !== overlayTextField.text) - overlayInvalid.showHeaderData(overlay.section, overlay.orientation) + if (overlayTextField.text === "") + overlayInvalid.showHeaderData(overlay.section, + overlay.orientation, + qsTr("No name found, please enter a valid name.")) + else if (!result && overlayTextField.previousText !== overlayTextField.text) + overlayInvalid.showHeaderData(overlay.section, + overlay.orientation, + qsTr("This name is already in use, please use a different name.")) } Text { diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/BlurHelper.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/BlurHelper.qml index da68339603a..733f0a15a0b 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/BlurHelper.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/BlurHelper.qml @@ -4,6 +4,7 @@ // This file should match the BlurHelper.qml in qtquickdesigner repository, except for shader paths import QtQuick +import EffectComposerPropertyData Item { id: rootItem @@ -20,8 +21,8 @@ Item { visible: false layer.enabled: true layer.smooth: true - vertexShader: g_propertyData.blur_vs_path - fragmentShader: g_propertyData.blur_fs_path + vertexShader: GlobalPropertyData?.blur_vs_path ?? "" + fragmentShader: GlobalPropertyData?.blur_fs_path ?? "" } QtObject { diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerPreview.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerPreview.qml index d8c36e34c22..7c7f167e07b 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerPreview.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerPreview.qml @@ -7,6 +7,7 @@ import HelperWidgets as HelperWidgets import StudioControls as StudioControls import StudioTheme as StudioTheme import EffectComposerBackend +import EffectComposerPropertyData Column { id: root @@ -298,8 +299,8 @@ Column { BlurHelper { id: blurHelper source: source - 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 + property int blurMax: GlobalPropertyData?.blur_helper_max_level ?? 64 + property real blurMultiplier: GlobalPropertyData?.blurMultiplier ?? 0 } Item { diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNode.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNode.qml index 243cd1ea317..33c8fe9d3fe 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNode.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNode.qml @@ -80,9 +80,10 @@ HelperWidgets.Section { function showNodeExistsWarning(enable) { infoText.text = qsTr("An effect with this name already exists.\nSuffix was added to make the name unique.") - infoTimer.restart() - infoText.visible = enable infoText.color = StudioTheme.Values.themeWarning + infoText.visible = enable + if (infoText.visible) + infoTimer.restart() } function showNodeAddedToLibraryInfo(message) @@ -95,15 +96,17 @@ HelperWidgets.Section { infoText.text = message infoText.color = StudioTheme.Values.themeInteraction } - infoTimer.restart() infoText.visible = message !== "" + if (infoText.visible) + infoTimer.restart() } function showNeedRenameInfo() { + infoTimer.stop() infoText.text = qsTr("A built-in effect with this name already exists in the library.\nPlease rename the effect before adding it to the library.") - infoText.visible = true infoText.color = StudioTheme.Values.themeWarning + infoText.visible = true } onVisibleChanged: { @@ -120,7 +123,7 @@ HelperWidgets.Section { onTriggered: { infoText.visible = false - infoTimer.running = false + infoTimer.stop() } } } diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/areaseries-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/areaseries-icon.png new file mode 100644 index 00000000000..590aaaa2847 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/areaseries-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/areaseries-polar-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/areaseries-polar-icon.png new file mode 100644 index 00000000000..af72238d692 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/areaseries-polar-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/bars3d-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/bars3d-icon.png new file mode 100644 index 00000000000..342c587117e Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/bars3d-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/bars3d-icon16.png b/share/qtcreator/qmldesigner/itemLibrary/images/bars3d-icon16.png new file mode 100644 index 00000000000..ce5d75ad4f3 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/bars3d-icon16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/barseries-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/barseries-icon.png new file mode 100644 index 00000000000..1bf023f385c Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/barseries-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/boxplotseries-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/boxplotseries-icon.png new file mode 100644 index 00000000000..25e9fe692ec Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/boxplotseries-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/boxshape.png b/share/qtcreator/qmldesigner/itemLibrary/images/boxshape.png new file mode 100644 index 00000000000..23775571c50 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/boxshape.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/boxshape16.png b/share/qtcreator/qmldesigner/itemLibrary/images/boxshape16.png new file mode 100644 index 00000000000..18707ce2434 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/boxshape16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/boxshape@2x.png b/share/qtcreator/qmldesigner/itemLibrary/images/boxshape@2x.png new file mode 100644 index 00000000000..596be65ae0f Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/boxshape@2x.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/capsuleshape.png b/share/qtcreator/qmldesigner/itemLibrary/images/capsuleshape.png new file mode 100644 index 00000000000..f3d29fd57ff Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/capsuleshape.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/capsuleshape16.png b/share/qtcreator/qmldesigner/itemLibrary/images/capsuleshape16.png new file mode 100644 index 00000000000..74e2ea9efd5 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/capsuleshape16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/capsuleshape@2x.png b/share/qtcreator/qmldesigner/itemLibrary/images/capsuleshape@2x.png new file mode 100644 index 00000000000..048883c8571 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/capsuleshape@2x.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/charactercontroller.png b/share/qtcreator/qmldesigner/itemLibrary/images/charactercontroller.png new file mode 100644 index 00000000000..ce18058d3aa Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/charactercontroller.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/charactercontroller16.png b/share/qtcreator/qmldesigner/itemLibrary/images/charactercontroller16.png new file mode 100644 index 00000000000..5998fd41a03 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/charactercontroller16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/charactercontroller@2x.png b/share/qtcreator/qmldesigner/itemLibrary/images/charactercontroller@2x.png new file mode 100644 index 00000000000..faa94098d7a Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/charactercontroller@2x.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/chartview-icon16.png b/share/qtcreator/qmldesigner/itemLibrary/images/chartview-icon16.png new file mode 100644 index 00000000000..b135c25908c Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/chartview-icon16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/convexmeshshape.png b/share/qtcreator/qmldesigner/itemLibrary/images/convexmeshshape.png new file mode 100644 index 00000000000..0837829fb5a Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/convexmeshshape.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/convexmeshshape16.png b/share/qtcreator/qmldesigner/itemLibrary/images/convexmeshshape16.png new file mode 100644 index 00000000000..9a411ed9fa7 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/convexmeshshape16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/convexmeshshape@2x.png b/share/qtcreator/qmldesigner/itemLibrary/images/convexmeshshape@2x.png new file mode 100644 index 00000000000..384d6969c4a Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/convexmeshshape@2x.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/dynamicrigidbody.png b/share/qtcreator/qmldesigner/itemLibrary/images/dynamicrigidbody.png new file mode 100644 index 00000000000..4cde7a3a27c Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/dynamicrigidbody.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/dynamicrigidbody16.png b/share/qtcreator/qmldesigner/itemLibrary/images/dynamicrigidbody16.png new file mode 100644 index 00000000000..ac26b26b4f4 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/dynamicrigidbody16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/dynamicrigidbody@2x.png b/share/qtcreator/qmldesigner/itemLibrary/images/dynamicrigidbody@2x.png new file mode 100644 index 00000000000..2a8579e4b04 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/dynamicrigidbody@2x.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/heightfieldshape.png b/share/qtcreator/qmldesigner/itemLibrary/images/heightfieldshape.png new file mode 100644 index 00000000000..5d8873750f0 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/heightfieldshape.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/heightfieldshape16.png b/share/qtcreator/qmldesigner/itemLibrary/images/heightfieldshape16.png new file mode 100644 index 00000000000..3cc0eeacb1f Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/heightfieldshape16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/heightfieldshape@2x.png b/share/qtcreator/qmldesigner/itemLibrary/images/heightfieldshape@2x.png new file mode 100644 index 00000000000..8c169613bdb Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/heightfieldshape@2x.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/horizontalbarseries-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/horizontalbarseries-icon.png new file mode 100644 index 00000000000..7d3ec403451 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/horizontalbarseries-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/horizontalpercentbarseries-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/horizontalpercentbarseries-icon.png new file mode 100644 index 00000000000..16783f7daf4 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/horizontalpercentbarseries-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/horizontalstackedbarseries-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/horizontalstackedbarseries-icon.png new file mode 100644 index 00000000000..b6fae651112 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/horizontalstackedbarseries-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/lineseries-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/lineseries-icon.png new file mode 100644 index 00000000000..de42f50d7fd Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/lineseries-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/lineseries-polar-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/lineseries-polar-icon.png new file mode 100644 index 00000000000..611b09f9fe7 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/lineseries-polar-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/percentbarseries-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/percentbarseries-icon.png new file mode 100644 index 00000000000..ef6221f6ef1 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/percentbarseries-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/physicsmaterial.png b/share/qtcreator/qmldesigner/itemLibrary/images/physicsmaterial.png new file mode 100644 index 00000000000..9675b1dfde7 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/physicsmaterial.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/physicsmaterial16.png b/share/qtcreator/qmldesigner/itemLibrary/images/physicsmaterial16.png new file mode 100644 index 00000000000..951221e57a4 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/physicsmaterial16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/physicsmaterial@2x.png b/share/qtcreator/qmldesigner/itemLibrary/images/physicsmaterial@2x.png new file mode 100644 index 00000000000..e50ca8edaaa Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/physicsmaterial@2x.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/physicsworld.png b/share/qtcreator/qmldesigner/itemLibrary/images/physicsworld.png new file mode 100644 index 00000000000..5d0c15e4354 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/physicsworld.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/physicsworld16.png b/share/qtcreator/qmldesigner/itemLibrary/images/physicsworld16.png new file mode 100644 index 00000000000..6ac979abf7b Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/physicsworld16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/physicsworld@2x.png b/share/qtcreator/qmldesigner/itemLibrary/images/physicsworld@2x.png new file mode 100644 index 00000000000..77652a5358d Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/physicsworld@2x.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/pieseries-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/pieseries-icon.png new file mode 100644 index 00000000000..51a61551e74 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/pieseries-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/planeshape.png b/share/qtcreator/qmldesigner/itemLibrary/images/planeshape.png new file mode 100644 index 00000000000..4d8f3b4136d Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/planeshape.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/planeshape16.png b/share/qtcreator/qmldesigner/itemLibrary/images/planeshape16.png new file mode 100644 index 00000000000..9388bfc37d5 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/planeshape16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/planeshape@2x.png b/share/qtcreator/qmldesigner/itemLibrary/images/planeshape@2x.png new file mode 100644 index 00000000000..f5fb2615927 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/planeshape@2x.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/scatter3d-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/scatter3d-icon.png new file mode 100644 index 00000000000..cef13081606 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/scatter3d-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/scatter3d-icon16.png b/share/qtcreator/qmldesigner/itemLibrary/images/scatter3d-icon16.png new file mode 100644 index 00000000000..2c456788ca0 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/scatter3d-icon16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/scatterseries-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/scatterseries-icon.png new file mode 100644 index 00000000000..8be289d6dea Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/scatterseries-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/scatterseries-polar-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/scatterseries-polar-icon.png new file mode 100644 index 00000000000..44cd8d72a66 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/scatterseries-polar-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/sphereshape.png b/share/qtcreator/qmldesigner/itemLibrary/images/sphereshape.png new file mode 100644 index 00000000000..d6f847ccbe2 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/sphereshape.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/sphereshape16.png b/share/qtcreator/qmldesigner/itemLibrary/images/sphereshape16.png new file mode 100644 index 00000000000..94c9430ca71 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/sphereshape16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/sphereshape@2x.png b/share/qtcreator/qmldesigner/itemLibrary/images/sphereshape@2x.png new file mode 100644 index 00000000000..0a1c289827b Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/sphereshape@2x.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/splineseries-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/splineseries-icon.png new file mode 100644 index 00000000000..e1df42068a1 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/splineseries-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/splineseries-polar-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/splineseries-polar-icon.png new file mode 100644 index 00000000000..293266df140 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/splineseries-polar-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/stackedbarseries-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/stackedbarseries-icon.png new file mode 100644 index 00000000000..03516997e9e Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/stackedbarseries-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/staticrigidbody.png b/share/qtcreator/qmldesigner/itemLibrary/images/staticrigidbody.png new file mode 100644 index 00000000000..f64beb8ec5c Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/staticrigidbody.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/staticrigidbody16.png b/share/qtcreator/qmldesigner/itemLibrary/images/staticrigidbody16.png new file mode 100644 index 00000000000..a89997cbc26 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/staticrigidbody16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/staticrigidbody@2x.png b/share/qtcreator/qmldesigner/itemLibrary/images/staticrigidbody@2x.png new file mode 100644 index 00000000000..fac847f153b Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/staticrigidbody@2x.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/surface3d-icon.png b/share/qtcreator/qmldesigner/itemLibrary/images/surface3d-icon.png new file mode 100644 index 00000000000..a2cdba06317 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/surface3d-icon.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/surface3d-icon16.png b/share/qtcreator/qmldesigner/itemLibrary/images/surface3d-icon16.png new file mode 100644 index 00000000000..f8f8a3ee787 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/surface3d-icon16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/trianglemeshshape.png b/share/qtcreator/qmldesigner/itemLibrary/images/trianglemeshshape.png new file mode 100644 index 00000000000..2fb4a7bc69f Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/trianglemeshshape.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/trianglemeshshape16.png b/share/qtcreator/qmldesigner/itemLibrary/images/trianglemeshshape16.png new file mode 100644 index 00000000000..d60b67f0f2e Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/trianglemeshshape16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/trianglemeshshape@2x.png b/share/qtcreator/qmldesigner/itemLibrary/images/trianglemeshshape@2x.png new file mode 100644 index 00000000000..64b0bc2c840 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/trianglemeshshape@2x.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/triggerbody.png b/share/qtcreator/qmldesigner/itemLibrary/images/triggerbody.png new file mode 100644 index 00000000000..e1abdeac434 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/triggerbody.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/triggerbody16.png b/share/qtcreator/qmldesigner/itemLibrary/images/triggerbody16.png new file mode 100644 index 00000000000..29a47afdc3b Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/triggerbody16.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/images/triggerbody@2x.png b/share/qtcreator/qmldesigner/itemLibrary/images/triggerbody@2x.png new file mode 100644 index 00000000000..7b942d959b3 Binary files /dev/null and b/share/qtcreator/qmldesigner/itemLibrary/images/triggerbody@2x.png differ diff --git a/share/qtcreator/qmldesigner/itemLibrary/qtcharts.metainfo b/share/qtcreator/qmldesigner/itemLibrary/qtcharts.metainfo new file mode 100644 index 00000000000..42eea67b4e5 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/qtcharts.metainfo @@ -0,0 +1,166 @@ +MetaInfo { + Type { + name: "QtCharts.ChartView" + icon: "images/chartview-icon16.png" + + ItemLibraryEntry { + name: "Area" + category: "Qt Charts - ChartView" + libraryIcon: "images/areaseries-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/AreaSeries.qml" } + } + + ItemLibraryEntry { + name: "Bar" + category: "Qt Charts - ChartView" + libraryIcon: "images/barseries-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/BarSeries.qml" } + } + + ItemLibraryEntry { + name: "BoxPlot" + category: "Qt Charts - ChartView" + libraryIcon: "images/boxplotseries-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/BoxPlotSeries.qml" } + } + + ItemLibraryEntry { + name: "H.Bar" + category: "Qt Charts - ChartView" + libraryIcon: "images/horizontalbarseries-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/HorizontalBarSeries.qml" } + } + + ItemLibraryEntry { + name: "H.PercentBar" + category: "Qt Charts - ChartView" + libraryIcon: "images/horizontalpercentbarseries-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/HorizontalPercentBarSeries.qml" } + } + + ItemLibraryEntry { + name: "H.StackedBar" + category: "Qt Charts - ChartView" + libraryIcon: "images/horizontalstackedbarseries-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/HorizontalStackedBarSeries.qml" } + } + + ItemLibraryEntry { + name: "Line" + category: "Qt Charts - ChartView" + libraryIcon: "images/lineseries-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/LineSeries.qml" } + } + + ItemLibraryEntry { + name: "Percent" + category: "Qt Charts - ChartView" + libraryIcon: "images/percentbarseries-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/PercentBarSeries.qml" } + } + + ItemLibraryEntry { + name: "Pie" + category: "Qt Charts - ChartView" + libraryIcon: "images/pieseries-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/PieSeries.qml" } + } + + ItemLibraryEntry { + name: "Scatter" + category: "Qt Charts - ChartView" + libraryIcon: "images/scatterseries-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/ScatterSeries.qml" } + } + + ItemLibraryEntry { + name: "Spline" + category: "Qt Charts - ChartView" + libraryIcon: "images/splineseries-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/SplineSeries.qml" } + } + + ItemLibraryEntry { + name: "StackedBar" + category: "Qt Charts - ChartView" + libraryIcon: "images/stackedbarseries-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/StackedBarSeries.qml" } + } + + ItemLibraryEntry { + name: "Area" + category: "Qt Charts - PolarChartView" + libraryIcon: "images/areaseries-polar-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/PolarAreaSeries.qml" } + } + + ItemLibraryEntry { + name: "Line" + category: "Qt Charts - PolarChartView" + libraryIcon: "images/lineseries-polar-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/PolarLineSeries.qml" } + } + + ItemLibraryEntry { + name: "Scatter" + category: "Qt Charts - PolarChartView" + libraryIcon: "images/scatterseries-polar-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/PolarScatterSeries.qml" } + } + + ItemLibraryEntry { + name: "Spline" + category: "Qt Charts - PolarChartView" + libraryIcon: "images/splineseries-polar-icon.png" + version: "2.0" + requiredImport: "QtCharts" + + QmlSource { source: "source/PolarSplineSeries.qml" } + } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/qtgraphs.metainfo b/share/qtcreator/qmldesigner/itemLibrary/qtgraphs.metainfo new file mode 100644 index 00000000000..6eb8754d9ee --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/qtgraphs.metainfo @@ -0,0 +1,111 @@ +MetaInfo { + Type { + name: "QtGraphs.Bars3D" + icon: "images/bars3d-icon16.png" + + ItemLibraryEntry { + name: "Bars3D" + category: "3D Graphs" + libraryIcon: "images/bars3d-icon.png" + version: "1.0" + requiredImport: "QtGraphs" + + QmlSource { source: "source/Bars3D.qml" } + } + } + + Type { + name: "QtGraphs.Scatter3D" + icon: "images/scatter3d-icon16.png" + + ItemLibraryEntry { + name: "Scatter3D" + category: "3D Graphs" + libraryIcon: "images/scatter3d-icon.png" + version: "1.0" + requiredImport: "QtGraphs" + + QmlSource { source: "source/Scatter3D.qml" } + } + } + + Type { + name: "QtGraphs.Surface3D" + icon: "images/surface3d-icon16.png" + + ItemLibraryEntry { + name: "Surface3D" + category: "3D Graphs" + libraryIcon: "images/surface3d-icon.png" + version: "1.0" + requiredImport: "QtGraphs" + + QmlSource { source: "source/Surface3D.qml" } + } + } + + Type { + name: "QtGraphs.GraphsView" + icon: "images/chartview-icon16.png" + + ItemLibraryEntry { + name: "Area" + category: "2D Graphs" + libraryIcon: "images/areaseries-icon.png" + version: "1.0" + requiredImport: "QtGraphs" + + QmlSource { source: "source/Graphs2DAreaSeries.qml" } + } + + ItemLibraryEntry { + name: "Bar" + category: "2D Graphs" + libraryIcon: "images/barseries-icon.png" + version: "1.0" + requiredImport: "QtGraphs" + + QmlSource { source: "source/Graphs2DBarSeries.qml" } + } + + ItemLibraryEntry { + name: "Line" + category: "2D Graphs" + libraryIcon: "images/lineseries-icon.png" + version: "1.0" + requiredImport: "QtGraphs" + + QmlSource { source: "source/Graphs2DLineSeries.qml" } + } + + ItemLibraryEntry { + name: "Pie" + category: "2D Graphs" + libraryIcon: "images/pieseries-icon.png" + version: "1.0" + requiredImport: "QtGraphs" + + QmlSource { source: "source/Graphs2DPieSeries.qml" } + } + + ItemLibraryEntry { + name: "Scatter" + category: "2D Graphs" + libraryIcon: "images/scatterseries-icon.png" + version: "1.0" + requiredImport: "QtGraphs" + + QmlSource { source: "source/Graphs2DScatterSeries.qml" } + } + + ItemLibraryEntry { + name: "Spline" + category: "2D Graphs" + libraryIcon: "images/splineseries-icon.png" + version: "1.0" + requiredImport: "QtGraphs" + + QmlSource { source: "source/Graphs2DSplineSeries.qml" } + } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/qtsaferenderer.metainfo b/share/qtcreator/qmldesigner/itemLibrary/qtsaferenderer.metainfo new file mode 100644 index 00000000000..6fae3638a54 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/qtsaferenderer.metainfo @@ -0,0 +1,47 @@ +MetaInfo { + Type { + name: "Qt.SafeRenderer.SafePicture" + icon: "images/picture-icon16.png" + + ItemLibraryEntry { + name: "SafePicture" + category: "Qt Safe Renderer" + libraryIcon: "images/picture-icon.png" + version: "2.0" + requiredImport: "Qt.SafeRenderer" + + Property { name: "width"; type: "int"; value: 64; } + Property { name: "height"; type: "int"; value: 64; } + } + } + Type { + name: "Qt.SafeRenderer.SafeText" + icon: "images/text-16px.png" + + ItemLibraryEntry { + name: "SafeText" + category: "Qt Safe Renderer" + libraryIcon: "images/text-24px.png" + version: "2.0" + requiredImport: "Qt.SafeRenderer" + + Property { name: "width"; type: "int"; value: 128; } + Property { name: "height"; type: "int"; value: 64; } + } + } + Type { + name: "Qt.SafeRenderer.SafeImage" + icon: "images/image-icon16.png" + + ItemLibraryEntry { + name: "SafeImage" + category: "Qt Safe Renderer" + libraryIcon: "images/image-icon.png" + version: "2.0" + requiredImport: "Qt.SafeRenderer" + + Property { name: "width"; type: "int"; value: 64; } + Property { name: "height"; type: "int"; value: 64; } + } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/qtvirtualkeyboard.metainfo b/share/qtcreator/qmldesigner/itemLibrary/qtvirtualkeyboard.metainfo new file mode 100644 index 00000000000..0aea30b869e --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/qtvirtualkeyboard.metainfo @@ -0,0 +1,35 @@ +MetaInfo { +Type { + name: "QtQuick.VirtualKeyboard.InputPanel" + icon: "images/text-input-icon16.png" + + ItemLibraryEntry { + name: "Input Panel" + category: "Virtual Keyboard" + libraryIcon: "images/text-input-icon.png" + version: "6.0" + requiredImport: "QtQuick.VirtualKeyboard" + + Property { name: "width"; type: "int"; value: 200; } + Property { name: "height"; type: "int"; value: 200; } + toolTip: qsTr("Provides the virtual keyboard UI.") + } +} + +Type { + name: "QtQuick.VirtualKeyboard.HandwritingInputPanel" + icon: "images/text-input-icon16.png" + + ItemLibraryEntry { + name: "Handwriting Input Panel" + category: "Virtual Keyboard" + libraryIcon: "images/text-input-icon.png" + version: "6.0" + requiredImport: "QtQuick.VirtualKeyboard" + + Property { name: "width"; type: "int"; value: 200; } + Property { name: "height"; type: "int"; value: 200; } + toolTip: qsTr("Provides a handwriting panel add-on for the virtual keyboard UI.") + } +} +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/quick3d_physics.metainfo b/share/qtcreator/qmldesigner/itemLibrary/quick3d_physics.metainfo new file mode 100644 index 00000000000..874e209dc52 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/quick3d_physics.metainfo @@ -0,0 +1,261 @@ +MetaInfo { + Type { + name: "QtQuick3D.Physics.PhysicsWorld" + icon: "images/physicsworld16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: false + } + + ItemLibraryEntry { + name: "Physics World" + category: "Components" + libraryIcon: "images/physicsworld.png" + version: "6.5" + requiredImport: "QtQuick3D.Physics" + } + } + + Type { + name: "QtQuick3D.Physics.TriggerBody" + icon: "images/triggerbody16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: true + } + + ItemLibraryEntry { + name: "Trigger Body" + category: "Collision Bodies" + libraryIcon: "images/triggerbody.png" + version: "6.5" + requiredImport: "QtQuick3D.Physics" + } + } + + Type { + name: "QtQuick3D.Physics.StaticRigidBody" + icon: "images/staticrigidbody16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: true + } + + ItemLibraryEntry { + name: "Static Rigid Body" + category: "Collision Bodies" + libraryIcon: "images/staticrigidbody.png" + version: "6.5" + requiredImport: "QtQuick3D.Physics" + } + } + + Type { + name: "QtQuick3D.Physics.DynamicRigidBody" + icon: "images/dynamicrigidbody16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: true + } + + ItemLibraryEntry { + name: "Dynamic Rigid Body" + category: "Collision Bodies" + libraryIcon: "images/dynamicrigidbody.png" + version: "6.5" + requiredImport: "QtQuick3D.Physics" + } + } + + Type { + name: "QtQuick3D.Physics.PhysicsMaterial" + icon: "images/physicsmaterial16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: false + } + + ItemLibraryEntry { + name: "Physics Material" + category: "Components" + libraryIcon: "images/physicsmaterial.png" + version: "6.5" + requiredImport: "QtQuick3D.Physics" + } + } + + Type { + name: "QtQuick3D.Physics.BoxShape" + icon: "images/boxshape16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: true + } + + ItemLibraryEntry { + name: "Box Shape" + category: "Collision Shapes" + libraryIcon: "images/boxshape.png" + version: "6.5" + requiredImport: "QtQuick3D.Physics" + } + } + + Type { + name: "QtQuick3D.Physics.CapsuleShape" + icon: "images/capsuleshape16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: true + } + + ItemLibraryEntry { + name: "Capsule Shape" + category: "Collision Shapes" + libraryIcon: "images/capsuleshape.png" + version: "6.5" + requiredImport: "QtQuick3D.Physics" + } + } + + Type { + name: "QtQuick3D.Physics.ConvexMeshShape" + icon: "images/convexmeshshape16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: true + } + + ItemLibraryEntry { + name: "Convex Mesh Shape" + category: "Collision Shapes" + libraryIcon: "images/convexmeshshape.png" + version: "6.5" + requiredImport: "QtQuick3D.Physics" + } + } + + Type { + name: "QtQuick3D.Physics.HeightFieldShape" + icon: "images/heightfieldshape16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: true + } + + ItemLibraryEntry { + name: "Height Field Shape" + category: "Collision Shapes" + libraryIcon: "images/heightfieldshape.png" + version: "6.5" + requiredImport: "QtQuick3D.Physics" + } + } + + Type { + name: "QtQuick3D.Physics.PlaneShape" + icon: "images/planeshape16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: true + } + + ItemLibraryEntry { + name: "Plane Shape" + category: "Collision Shapes" + libraryIcon: "images/planeshape.png" + version: "6.5" + requiredImport: "QtQuick3D.Physics" + } + } + + Type { + name: "QtQuick3D.Physics.SphereShape" + icon: "images/sphereshape16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: true + } + + ItemLibraryEntry { + name: "Sphere Shape" + category: "Collision Shapes" + libraryIcon: "images/sphereshape.png" + version: "6.5" + requiredImport: "QtQuick3D.Physics" + } + } + + Type { + name: "QtQuick3D.Physics.TriangleMeshShape" + icon: "images/trianglemeshshape16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: true + } + + ItemLibraryEntry { + name: "Triangle Mesh Shape" + category: "Collision Shapes" + libraryIcon: "images/trianglemeshshape.png" + version: "6.5" + requiredImport: "QtQuick3D.Physics" + } + } + + Type { + name: "QtQuick3D.Physics.CharacterController" + icon: "images/charactercontroller16.png" + + Hints { + visibleInNavigator: true + canBeDroppedInNavigator: true + canBeDroppedInFormEditor: false + canBeDroppedInView3D: true + } + + ItemLibraryEntry { + name: "Character Controller" + category: "Collision Bodies" + libraryIcon: "images/charactercontroller.png" + version: "6.5" + requiredImport: "QtQuick3D.Physics" + } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/AreaSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/AreaSeries.qml new file mode 100644 index 00000000000..6aa9fae78ac --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/AreaSeries.qml @@ -0,0 +1,20 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +ChartView { + width: 300 + height: 300 + + AreaSeries { + name: "AreaSeries" + upperSeries: LineSeries { + XYPoint { x: 0; y: 1.5 } + XYPoint { x: 1; y: 3 } + XYPoint { x: 3; y: 4.3 } + XYPoint { x: 6; y: 1.1 } + } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/BarSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/BarSeries.qml new file mode 100644 index 00000000000..07e5838ef9d --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/BarSeries.qml @@ -0,0 +1,17 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +ChartView { + width: 300 + height: 300 + + BarSeries { + name: "BarSeries" + BarSet { label: "Set1"; values: [2, 2, 3] } + BarSet { label: "Set2"; values: [5, 1, 2] } + BarSet { label: "Set3"; values: [3, 5, 8] } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/Bars3D.qml b/share/qtcreator/qmldesigner/itemLibrary/source/Bars3D.qml new file mode 100644 index 00000000000..e823c16ae7f --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/Bars3D.qml @@ -0,0 +1,28 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick3D +import QtGraphs + +Bars3D { + id: bars3d + width: 300 + height: 300 + Bar3DSeries { + id: bars3dSeries + ItemModelBarDataProxy { + id: barsDataProxy + itemModel: ListModel { + ListElement{ row: "row 1"; column: "column 1"; value: "1"; } + ListElement{ row: "row 1"; column: "column 2"; value: "2"; } + ListElement{ row: "row 1"; column: "column 3"; value: "3"; } + } + + rowRole: "row" + columnRole: "column" + valueRole: "value" + } + } +} + diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/BoxPlotSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/BoxPlotSeries.qml new file mode 100644 index 00000000000..44d7041b358 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/BoxPlotSeries.qml @@ -0,0 +1,17 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +ChartView { + width: 300 + height: 300 + + BoxPlotSeries { + name: "BoxPlotSeries" + BoxSet { label: "Set1"; values: [3, 4, 5.1, 6.2, 8.5] } + BoxSet { label: "Set2"; values: [5, 6, 7.5, 8.6, 11.8] } + BoxSet { label: "Set3"; values: [3.2, 5, 5.7, 8, 9.2] } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DAreaSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DAreaSeries.qml new file mode 100644 index 00000000000..22c5835104b --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DAreaSeries.qml @@ -0,0 +1,52 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtGraphs + +GraphsView { + width: 300 + height: 300 + + axisX: valueAxisX + axisY: valueAxisY + + ValueAxis { + id: valueAxisX + min: 0 + max: 10 + } + ValueAxis { + id: valueAxisY + min: 0 + max: 10 + } + + AreaSeries { + name: "AreaSeries" + upperSeries: lineSeries + + LineSeries { + id: lineSeries + XYPoint { + x: 0 + y: 1.5 + } + + XYPoint { + x: 1 + y: 3 + } + + XYPoint { + x: 6 + y: 6.3 + } + + XYPoint { + x: 10 + y: 3.1 + } + } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DBarSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DBarSeries.qml new file mode 100644 index 00000000000..ece1718ab83 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DBarSeries.qml @@ -0,0 +1,31 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtGraphs + +GraphsView { + width: 300 + height: 300 + + axisX: barCategoryAxis + axisY: valueAxis + + BarCategoryAxis { + id: barCategoryAxis + categories: ["2023", "2024", "2025"] + } + + ValueAxis { + id: valueAxis + min: 0 + max: 10 + } + + BarSeries { + id: barSeries + BarSet { id: set1; label: "Set1"; values: [2, 2, 3] } + BarSet { id: set2; label: "Set2"; values: [5, 1, 2] } + BarSet { id: set3; label: "Set3"; values: [3, 5, 8] } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DLineSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DLineSeries.qml new file mode 100644 index 00000000000..1f7d9595e47 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DLineSeries.qml @@ -0,0 +1,47 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtGraphs + +GraphsView { + width: 300 + height: 300 + + axisX: valueAxisX + axisY: valueAxisY + + ValueAxis { + id: valueAxisX + min: 0 + max: 10 + } + ValueAxis { + id: valueAxisY + min: 0 + max: 10 + } + + LineSeries { + id: lineSeries + XYPoint { + x: 0 + y: 2 + } + + XYPoint { + x: 3 + y: 1.2 + } + + XYPoint { + x: 7 + y: 3.3 + } + + XYPoint { + x: 10 + y: 2.1 + } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DPieSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DPieSeries.qml new file mode 100644 index 00000000000..a8b8bcd806b --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DPieSeries.qml @@ -0,0 +1,17 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtGraphs + +GraphsView { + width: 300 + height: 300 + + PieSeries { + id: pieSeries + PieSlice { label: "Slice1"; value: 13.5 } + PieSlice { label: "Slice2"; value: 10.9 } + PieSlice { label: "Slice3"; value: 8.6 } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DScatterSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DScatterSeries.qml new file mode 100644 index 00000000000..4d86d504117 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DScatterSeries.qml @@ -0,0 +1,47 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtGraphs + +GraphsView { + width: 300 + height: 300 + + axisX: valueAxisX + axisY: valueAxisY + + ValueAxis { + id: valueAxisX + min: 0 + max: 10 + } + ValueAxis { + id: valueAxisY + min: 0 + max: 10 + } + + ScatterSeries { + id: lineSeries + XYPoint { + x: 0 + y: 2 + } + + XYPoint { + x: 3 + y: 1.2 + } + + XYPoint { + x: 7 + y: 3.3 + } + + XYPoint { + x: 10 + y: 2.1 + } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DSplineSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DSplineSeries.qml new file mode 100644 index 00000000000..baab8f14e72 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/Graphs2DSplineSeries.qml @@ -0,0 +1,47 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtGraphs + +GraphsView { + width: 300 + height: 300 + + axisX: valueAxisX + axisY: valueAxisY + + ValueAxis { + id: valueAxisX + min: 0 + max: 10 + } + ValueAxis { + id: valueAxisY + min: 0 + max: 10 + } + + SplineSeries { + id: lineSeries + XYPoint { + x: 0 + y: 2 + } + + XYPoint { + x: 3 + y: 1.2 + } + + XYPoint { + x: 7 + y: 3.3 + } + + XYPoint { + x: 10 + y: 2.1 + } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/HorizontalBarSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/HorizontalBarSeries.qml new file mode 100644 index 00000000000..559cf2b7898 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/HorizontalBarSeries.qml @@ -0,0 +1,17 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +ChartView { + width: 300 + height: 300 + + HorizontalBarSeries { + name: "HorizontalBarSeries" + BarSet { label: "Set1"; values: [2, 2, 3] } + BarSet { label: "Set2"; values: [5, 1, 2] } + BarSet { label: "Set3"; values: [3, 5, 8] } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/HorizontalPercentBarSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/HorizontalPercentBarSeries.qml new file mode 100644 index 00000000000..68f7a0f532b --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/HorizontalPercentBarSeries.qml @@ -0,0 +1,17 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +ChartView { + width: 300 + height: 300 + + HorizontalPercentBarSeries { + name: "HorizontalPercentBarSeries" + BarSet { label: "Set1"; values: [2, 2, 3] } + BarSet { label: "Set2"; values: [5, 1, 2] } + BarSet { label: "Set3"; values: [3, 5, 8] } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/HorizontalStackedBarSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/HorizontalStackedBarSeries.qml new file mode 100644 index 00000000000..c80cd3cba8d --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/HorizontalStackedBarSeries.qml @@ -0,0 +1,17 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +ChartView { + width: 300 + height: 300 + + HorizontalStackedBarSeries { + name: "HorizontalStackedBarSeries" + BarSet { label: "Set1"; values: [2, 2, 3] } + BarSet { label: "Set2"; values: [5, 1, 2] } + BarSet { label: "Set3"; values: [3, 5, 8] } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/LineSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/LineSeries.qml new file mode 100644 index 00000000000..c0ce034505b --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/LineSeries.qml @@ -0,0 +1,18 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +ChartView { + width: 300 + height: 300 + + LineSeries { + name: "LineSeries" + XYPoint { x: 0; y: 2 } + XYPoint { x: 1; y: 1.2 } + XYPoint { x: 2; y: 3.3 } + XYPoint { x: 5; y: 2.1 } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/PercentBarSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/PercentBarSeries.qml new file mode 100644 index 00000000000..71e039f2d95 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/PercentBarSeries.qml @@ -0,0 +1,17 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +ChartView { + width: 300 + height: 300 + + PercentBarSeries { + name: "PercentBarSeries" + BarSet { label: "Set1"; values: [2, 2, 3] } + BarSet { label: "Set2"; values: [5, 1, 2] } + BarSet { label: "Set3"; values: [3, 5, 8] } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/PieSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/PieSeries.qml new file mode 100644 index 00000000000..eb803e68c64 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/PieSeries.qml @@ -0,0 +1,17 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +ChartView { + width: 300 + height: 300 + + PieSeries { + name: "PieSeries" + PieSlice { label: "Slice1"; value: 13.5 } + PieSlice { label: "Slice2"; value: 10.9 } + PieSlice { label: "Slice3"; value: 8.6 } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/PolarAreaSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/PolarAreaSeries.qml new file mode 100644 index 00000000000..581b7b20aa6 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/PolarAreaSeries.qml @@ -0,0 +1,48 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +PolarChartView { + width: 300 + height: 300 + legend.visible: false + + ValueAxis { + id: axis1 + tickCount: 9 + } + ValueAxis { + id: axis2 + } + LineSeries { + id: lowerLine + axisAngular: axis1 + axisRadial: axis2 + + XYPoint { x: 1; y: 5 } + XYPoint { x: 2; y: 10 } + XYPoint { x: 3; y: 12 } + XYPoint { x: 4; y: 17 } + XYPoint { x: 5; y: 20 } + } + LineSeries { + id: upperLine + axisAngular: axis1 + axisRadial: axis2 + + XYPoint { x: 1; y: 5 } + XYPoint { x: 2; y: 14 } + XYPoint { x: 3; y: 20 } + XYPoint { x: 4; y: 32 } + XYPoint { x: 5; y: 35 } + } + AreaSeries { + name: "AreaSeries" + axisAngular: axis1 + axisRadial: axis2 + lowerSeries: lowerLine + upperSeries: upperLine + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/PolarLineSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/PolarLineSeries.qml new file mode 100644 index 00000000000..a1d43c4554e --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/PolarLineSeries.qml @@ -0,0 +1,27 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +PolarChartView { + width: 300 + height: 300 + + LineSeries { + name: "LineSeries" + axisRadial: CategoryAxis { + min: 0 + max: 20 + } + axisAngular: ValueAxis { + tickCount: 9 + } + XYPoint { x: 0; y: 4.3 } + XYPoint { x: 2; y: 4.7 } + XYPoint { x: 4; y: 5.2 } + XYPoint { x: 6; y: 6.1 } + XYPoint { x: 8; y: 12.9 } + XYPoint { x: 9; y: 19.2 } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/PolarScatterSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/PolarScatterSeries.qml new file mode 100644 index 00000000000..26dd577b5ea --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/PolarScatterSeries.qml @@ -0,0 +1,26 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +PolarChartView { + width: 300 + height: 300 + + ScatterSeries { + name: "ScatterSeries" + axisRadial: CategoryAxis { + min: 0 + max: 20 + } + axisAngular: ValueAxis { + tickCount: 9 + } + XYPoint { x: 0; y: 4.3 } + XYPoint { x: 2; y: 4.7 } + XYPoint { x: 4; y: 5.2 } + XYPoint { x: 8; y: 12.9 } + XYPoint { x: 9; y: 19.2 } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/PolarSplineSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/PolarSplineSeries.qml new file mode 100644 index 00000000000..5f05ca9c622 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/PolarSplineSeries.qml @@ -0,0 +1,27 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +PolarChartView { + width: 300 + height: 300 + + SplineSeries { + name: "SplineSeries" + axisRadial: CategoryAxis { + min: 0 + max: 20 + } + axisAngular: ValueAxis { + tickCount: 9 + } + XYPoint { x: 0; y: 4.3 } + XYPoint { x: 2; y: 4.7 } + XYPoint { x: 4; y: 5.2 } + XYPoint { x: 6; y: 6.1 } + XYPoint { x: 8; y: 12.9 } + XYPoint { x: 9; y: 19.2 } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/Scatter3D.qml b/share/qtcreator/qmldesigner/itemLibrary/source/Scatter3D.qml new file mode 100644 index 00000000000..24c199ab406 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/Scatter3D.qml @@ -0,0 +1,28 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick3D +import QtGraphs + +Scatter3D { + id: scatter3d + width: 300 + height: 300 + Scatter3DSeries { + id: scatter3dSeries + ItemModelScatterDataProxy { + id: scatterDataProxy + itemModel: ListModel { + ListElement{ x: "1"; y: "2"; z: "3"; } + ListElement{ x: "2"; y: "3"; z: "4"; } + ListElement{ x: "3"; y: "4"; z: "1"; } + } + + xPosRole: "x" + yPosRole: "y" + zPosRole: "z" + } + } +} + diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/ScatterSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/ScatterSeries.qml new file mode 100644 index 00000000000..3b73402e41b --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/ScatterSeries.qml @@ -0,0 +1,18 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +ChartView { + width: 300 + height: 300 + + ScatterSeries { + name: "ScatterSeries" + XYPoint { x: 1; y: 1 } + XYPoint { x: 2; y: 4 } + XYPoint { x: 4; y: 2 } + XYPoint { x: 5; y: 5 } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/SplineSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/SplineSeries.qml new file mode 100644 index 00000000000..b400a99e535 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/SplineSeries.qml @@ -0,0 +1,18 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +ChartView { + width: 300 + height: 300 + + SplineSeries { + name: "SplineSeries" + XYPoint { x: 0; y: 1 } + XYPoint { x: 3; y: 4.3 } + XYPoint { x: 5; y: 3.1 } + XYPoint { x: 8; y: 5.8 } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/StackedBarSeries.qml b/share/qtcreator/qmldesigner/itemLibrary/source/StackedBarSeries.qml new file mode 100644 index 00000000000..45431cd8580 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/StackedBarSeries.qml @@ -0,0 +1,17 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtCharts + +ChartView { + width: 300 + height: 300 + + StackedBarSeries { + name: "StackedBarSeries" + BarSet { label: "Set1"; values: [2, 2, 3] } + BarSet { label: "Set2"; values: [5, 1, 2] } + BarSet { label: "Set3"; values: [3, 5, 8] } + } +} diff --git a/share/qtcreator/qmldesigner/itemLibrary/source/Surface3D.qml b/share/qtcreator/qmldesigner/itemLibrary/source/Surface3D.qml new file mode 100644 index 00000000000..d5c0a56fff6 --- /dev/null +++ b/share/qtcreator/qmldesigner/itemLibrary/source/Surface3D.qml @@ -0,0 +1,28 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import QtQuick3D +import QtGraphs + +Surface3D { + id: surface3d + width: 300 + height: 300 + Surface3DSeries { + id: surface3dSeries + ItemModelSurfaceDataProxy { + id: surfaceDataProxy + itemModel: ListModel { + ListElement{ row: "1"; column: "1"; y: "1"; } + ListElement{ row: "1"; column: "2"; y: "2"; } + ListElement{ row: "2"; column: "1"; y: "3"; } + ListElement{ row: "2"; column: "2"; y: "4"; } + } + + rowRole: "row" + columnRole: "column" + yPosRole: "y" + } + } +} diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml index 6e1467dd2f7..87c9f623536 100644 --- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml @@ -132,7 +132,7 @@ Item { delegate: ItemDelegate { id: delegateId - readonly property string styleName: model.display + readonly property string styleName: model?.display ?? "" width: stylesList.width height: DialogValues.styleListItemHeight hoverEnabled: true @@ -180,7 +180,7 @@ Item { width: DialogValues.styleImageWidth height: DialogValues.styleImageHeight asynchronous: false - source: "image://newprojectdialog_library/" + model.iconName + source: model?.iconName ? "image://newprojectdialog_library/" + model.iconName : "" } } // Rectangle diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/Qt/SafeRenderer/SafeImagePane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/Qt/SafeRenderer/SafeImagePane.qml new file mode 100644 index 00000000000..5f06bd79d89 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/Qt/SafeRenderer/SafeImagePane.qml @@ -0,0 +1,156 @@ +// Copyright (C) 2025 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.Layouts +import QtQuickDesignerTheme +import HelperWidgets +import StudioTheme as StudioTheme + +Rectangle { + id: itemPane + width: 320 + height: 400 + color: Theme.qmlDesignerBackgroundColorDarkAlternate() + + Component.onCompleted: Controller.mainScrollView = mainScrollView + + MouseArea { + anchors.fill: parent + onClicked: forceActiveFocus() + } + + ScrollView { + id: mainScrollView + clip: true + anchors.fill: parent + + Column { + id: mainColumn + y: -1 + width: itemPane.width + + onWidthChanged: StudioTheme.Values.responsiveResize(itemPane.width) + Component.onCompleted: StudioTheme.Values.responsiveResize(itemPane.width) + + ComponentSection {} + + Section { + caption: qsTr("Safe Image") + anchors.left: parent.left + anchors.right: parent.right + + SectionLayout { + PropertyLabel { text: qsTr("Position") } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.x + maximumValue: 0xffff + minimumValue: -0xffff + decimals: 0 + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { text: "X" } + + Spacer { implicitWidth: StudioTheme.Values.controlGap } + + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.y + maximumValue: 0xffff + minimumValue: -0xffff + decimals: 0 + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { text: "Y" } + + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Size") } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.width + maximumValue: 0xffff + minimumValue: 1 + decimals: 0 + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + //: The width of the object + text: qsTr("W", "width") + } + + Spacer { implicitWidth: StudioTheme.Values.controlGap } + + SpinBox { + id: heightSpinBox + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.height + maximumValue: 0xffff + minimumValue: 1 + decimals: 0 + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + //: The height of the object + text: qsTr("H", "height") + } + + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Source") } + + SecondColumnLayout { + UrlChooser { + backendValue: backendValues.source + } + + ExpandingSpacer {} + } + PropertyLabel { text: qsTr("fillColor") } + + ColorEditor { + backendValue: backendValues.fillColor + supportGradient: false + } + + PropertyLabel { text: qsTr("Opacity") } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + sliderIndicatorVisible: true + backendValue: backendValues.opacity + decimals: 2 + minimumValue: 0 + maximumValue: 1 + hasSlider: true + stepSize: 0.1 + } + + ExpandingSpacer {} + } + } + } + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/Qt/SafeRenderer/SafePicturePane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/Qt/SafeRenderer/SafePicturePane.qml new file mode 100644 index 00000000000..89aaccba29c --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/Qt/SafeRenderer/SafePicturePane.qml @@ -0,0 +1,163 @@ +// Copyright (C) 2025 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.Layouts +import QtQuickDesignerTheme +import HelperWidgets +import StudioTheme as StudioTheme + +Rectangle { + id: itemPane + width: 320 + height: 400 + color: Theme.qmlDesignerBackgroundColorDarkAlternate() + + Component.onCompleted: Controller.mainScrollView = mainScrollView + + MouseArea { + anchors.fill: parent + onClicked: forceActiveFocus() + } + + ScrollView { + id: mainScrollView + clip: true + anchors.fill: parent + + Column { + id: mainColumn + y: -1 + width: itemPane.width + + onWidthChanged: StudioTheme.Values.responsiveResize(itemPane.width) + Component.onCompleted: StudioTheme.Values.responsiveResize(itemPane.width) + + ComponentSection {} + + Section { + caption: qsTr("Safe Picture") + anchors.left: parent.left + anchors.right: parent.right + + SectionLayout { + PropertyLabel { text: qsTr("Position") } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.x + maximumValue: 0xffff + minimumValue: -0xffff + decimals: 0 + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { text: "X" } + + Spacer { implicitWidth: StudioTheme.Values.controlGap } + + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.y + maximumValue: 0xffff + minimumValue: -0xffff + decimals: 0 + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { text: "Y" } + + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Size") } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.width + maximumValue: 0xffff + minimumValue: 1 + decimals: 0 + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + //: The width of the object + text: qsTr("W", "width") + } + + Spacer { implicitWidth: StudioTheme.Values.controlGap } + + SpinBox { + id: heightSpinBox + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.height + maximumValue: 0xffff + minimumValue: 1 + decimals: 0 + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + //: The height of the object + text: qsTr("H", "height") + } + + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Source") } + + SecondColumnLayout { + UrlChooser { + backendValue: backendValues.source + } + + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Color") } + + ColorEditor { + backendValue: backendValues.color + supportGradient: false + } + + PropertyLabel { text: qsTr("fillColor") } + + ColorEditor { + backendValue: backendValues.fillColor + supportGradient: false + } + PropertyLabel { text: qsTr("Opacity") } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + sliderIndicatorVisible: true + backendValue: backendValues.opacity + decimals: 2 + minimumValue: 0 + maximumValue: 1 + hasSlider: true + stepSize: 0.1 + } + + ExpandingSpacer {} + } + } + } + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/Qt/SafeRenderer/SafeTextPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/Qt/SafeRenderer/SafeTextPane.qml new file mode 100644 index 00000000000..be097ee2738 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/Qt/SafeRenderer/SafeTextPane.qml @@ -0,0 +1,269 @@ +// Copyright (C) 2025 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.Layouts +import QtQuickDesignerTheme +import HelperWidgets +import StudioTheme as StudioTheme + +Rectangle { + id: itemPane + width: 320 + height: 400 + color: Theme.qmlDesignerBackgroundColorDarkAlternate() + + Component.onCompleted: Controller.mainScrollView = mainScrollView + + MouseArea { + anchors.fill: parent + onClicked: forceActiveFocus() + } + + ScrollView { + id: mainScrollView + clip: true + anchors.fill: parent + + Column { + id: mainColumn + y: -1 + width: itemPane.width + + onWidthChanged: StudioTheme.Values.responsiveResize(itemPane.width) + Component.onCompleted: StudioTheme.Values.responsiveResize(itemPane.width) + + ComponentSection {} + + Section { + caption: qsTr("Safe Text") + anchors.left: parent.left + anchors.right: parent.right + + SectionLayout { + PropertyLabel { text: qsTr("Position") } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.x + maximumValue: 0xffff + minimumValue: -0xffff + decimals: 0 + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { text: "X" } + + Spacer { implicitWidth: StudioTheme.Values.controlGap } + + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.y + maximumValue: 0xffff + minimumValue: -0xffff + decimals: 0 + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { text: "Y" } + + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Size") } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.width + maximumValue: 0xffff + minimumValue: 1 + decimals: 0 + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + //: The width of the object + text: qsTr("W", "width") + } + + Spacer { implicitWidth: StudioTheme.Values.controlGap } + + SpinBox { + id: heightSpinBox + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.height + maximumValue: 0xffff + minimumValue: 1 + decimals: 0 + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + //: The height of the object + text: qsTr("H", "height") + } + + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Text") } + + SecondColumnLayout { + LineEdit { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + width: implicitWidth + backendValue: backendValues.text + } + + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Color") } + + ColorEditor { + backendValue: backendValues.color + supportGradient: false + } + PropertyLabel { text: qsTr("fillColor") } + + ColorEditor { + backendValue: backendValues.fillColor + supportGradient: false + } + PropertyLabel { text: qsTr("Opacity") } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + sliderIndicatorVisible: true + backendValue: backendValues.opacity + decimals: 2 + minimumValue: 0 + maximumValue: 1 + hasSlider: true + stepSize: 0.1 + } + + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Font") } + + SecondColumnLayout { + FontComboBox { + id: fontComboBox + property string familyName: backendValue.value + backendValue: backendValues.font_family + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + width: implicitWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Size") } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.font_pixelSize + minimumValue: 0 + maximumValue: 400 + decimals: 0 + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { text: "px" } + + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Emphasis") } + + SecondColumnLayout { + BoolButtonRowButton { + id: boldButton + buttonIcon: StudioTheme.Constants.fontStyleBold + backendValue: backendValues.font_bold + } + + Spacer { + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + - (boldButton.implicitWidth + italicButton.implicitWidth) + } + + BoolButtonRowButton { + id: italicButton + buttonIcon: StudioTheme.Constants.fontStyleItalic + backendValue: backendValues.font_italic + } + + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Alignment H") } + + SecondColumnLayout { + AlignmentHorizontalButtons { + scope: "SafeText" + } + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Alignment V") } + + SecondColumnLayout { + AlignmentVerticalButtons { + scope: "SafeText" + } + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Wrap mode") } + + SecondColumnLayout { + ComboBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + width: implicitWidth + backendValue: backendValues.wrapMode + scope: "SafeText" + model: ["NoWrap", "WordWrap", "WrapAnywhere", "Wrap"] + enabled: backendValue.isAvailable + } + ExpandingSpacer {} + } + + PropertyLabel { text: qsTr("Dynamic") } + + SecondColumnLayout { + CheckBox { + text: backendValue.valueToString + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + backendValue: backendValues.runtimeEditable + } + + ExpandingSpacer {} + } + } + } + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtCharts/ChartViewSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtCharts/ChartViewSpecifics.qml new file mode 100644 index 00000000000..1397249460a --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtCharts/ChartViewSpecifics.qml @@ -0,0 +1,123 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Column { + width: parent.width + + Section { + caption: qsTr("Title") + width: parent.width + + SectionLayout { + PropertyLabel { + text: qsTr("Title") + } + + SecondColumnLayout { + LineEdit { + backendValue: backendValues.title + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Color") + } + + ColorEditor { + backendValue: backendValues.titleColor + supportGradient: false + } + } + } + + Section { + width: parent.width + caption: qsTr("Background") + + SectionLayout { + PropertyLabel { + text: qsTr("Color") + } + + ColorEditor { + backendValue: backendValues.backgroundColor + supportGradient: false + } + + PropertyLabel { + text: qsTr("Roundness") + tooltip: qsTr("Diameter of the rounding circle at the corners") + } + + SecondColumnLayout { + SpinBox { + backendValue: backendValues.backgroundRoundness + minimumValue: 0.1 + maximumValue: 100.0 + stepSize: 0.1 + decimals: 1 + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + + PropertyLabel { + text: qsTr("Drop Shadow") + tooltip: qsTr("Enable border drop shadow") + } + + SecondColumnLayout { + CheckBox { + text: backendValues.dropShadowEnabled.valueToString + backendValue: backendValues.dropShadowEnabled + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + } + } + + Section { + width: parent.width + caption: qsTr("Plot Area") + + SectionLayout { + PropertyLabel { + text: qsTr("Color") + } + + ColorEditor { + backendValue: backendValues.plotAreaColor + supportGradient: false + } + } + } + + Section { + width: parent.width + caption: qsTr("Localization") + + SectionLayout { + PropertyLabel { + text: qsTr("Localize Numbers") + } + + SecondColumnLayout { + CheckBox { + text: backendValues.localizeNumbers.valueToString + backendValue: backendValues.localizeNumbers + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/Bars3DSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/Bars3DSpecifics.qml new file mode 100644 index 00000000000..9c822a726f9 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/Bars3DSpecifics.qml @@ -0,0 +1,276 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import HelperWidgets +import QtQuick.Layouts +import StudioTheme as StudioTheme +import QtQuick.Controls as Controls + +Column { + width: parent.width + + Section { + width: parent.width + caption: qsTr("Bars") + + SectionLayout { + PropertyLabel { + text: qsTr("Uniform Scaling") + tooltip: qsTr("Proportionally scale multiple series") + } + SecondColumnLayout { + CheckBox { + backendValue: backendValues.multiSeriesUniform + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Thickness") + tooltip: qsTr("Thickness ratio between X and Z dimension") + } + SecondColumnLayout { + SpinBox { + backendValue: backendValues.barThickness + minimumValue: 0.01 + maximumValue: 100.0 + stepSize: 0.01 + decimals: 2 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + + PropertyLabel { + text: qsTr("Spacing") + tooltip: qsTr("Bar spacing in the X and Z dimensions") + } + SecondColumnLayout { + SpinBox { + backendValue: backendValues.barSpacing_width + minimumValue: 0.0 + maximumValue: 10.0 + stepSize: 0.01 + decimals: 2 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + - StudioTheme.Values.actionIndicatorWidth + } + ControlLabel { + text: qsTr("Col") + width: StudioTheme.Values.actionIndicatorWidth * 2 + } + } + + PropertyLabel {} + SecondColumnLayout { + SpinBox { + backendValue: backendValues.barSpacing_height + minimumValue: 0.0 + maximumValue: 10.0 + stepSize: 0.01 + decimals: 2 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + - StudioTheme.Values.actionIndicatorWidth + } + ControlLabel { + text: qsTr("Row") + width: StudioTheme.Values.actionIndicatorWidth * 2 + } + + } + PropertyLabel { + text: qsTr("Relative Spacing") + tooltip: qsTr("Set bar spacing relative to thickness") + } + SecondColumnLayout { + CheckBox { + backendValue: backendValues.barSpacingRelative + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Series Margin") + tooltip: qsTr("Margin between series columns in X and Z dimensions") + } + SecondColumnLayout { + SpinBox { + backendValue: backendValues.barSeriesMargin_width + minimumValue: 0.0 + maximumValue: 1.0 + stepSize: 0.01 + decimals: 2 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + - StudioTheme.Values.actionIndicatorWidth + } + ControlLabel { + text: qsTr("Col") + width: StudioTheme.Values.actionIndicatorWidth * 2 + } + } + PropertyLabel {} + SecondColumnLayout { + SpinBox { + backendValue: backendValues.barSeriesMargin_height + minimumValue: 0.0 + maximumValue: 1.0 + stepSize: 0.01 + decimals: 2 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + - StudioTheme.Values.actionIndicatorWidth + } + ControlLabel { + text: qsTr("Row") + width: StudioTheme.Values.actionIndicatorWidth * 2 + } + + } + PropertyLabel { + text: qsTr("Floor Level") + tooltip: qsTr("Floor level in Y-axis data coordinates") + } + SecondColumnLayout { + SpinBox { + backendValue: backendValues.floorLevel + minimumValue: 0.0 + maximumValue: 999999 + stepSize: 0.1 + decimals: 2 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + - StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Selection Mode") + tooltip: qsTr("Bar selection mode") + } + SecondColumnLayout { + id: selectionLayout + property bool isInModel: backendValue.isInModel; + property bool isInSubState: backendValue.isInSubState; + property bool selectionChangedFlag: selectionChanged + property variant backendValue: backendValues.selectionMode + property variant valueFromBackend: backendValue.value + property string enumScope: "Graphs3D.SelectionFlag" + property string enumSeparator: " | " + property int checkedCount: 0 + property bool item: false + property bool row: false + property bool column: false + property bool slice: false + property bool multi: false + + function checkValue(checkedVariable, variableText, expressionBase) { + var expressionStr = expressionBase + if (checkedVariable) { + if (expressionStr !== "") { + expressionStr += enumSeparator + } + expressionStr += enumScope + expressionStr += "." + expressionStr += variableText + checkedCount++ + } + return expressionStr + } + + function composeSelectionMode() { + var expressionStr = "" + checkedCount = 0 + expressionStr = checkValue(item, "Item", expressionStr) + expressionStr = checkValue(row, "Row", expressionStr) + expressionStr = checkValue(column, "Column", expressionStr) + expressionStr = checkValue(slice, "Slice", expressionStr) + expressionStr = checkValue(multi, "MultiSeries", expressionStr) + + if (checkedCount === 0) + backendValue.expression = enumScope + ".None" + else + backendValue.expression = expressionStr + } + + function evaluate() { + if (backendValue.value === undefined) + return + + item = (backendValue.expression.indexOf("Item") !== -1) + row = (backendValue.expression.indexOf("Row") !== -1) + column = (backendValue.expression.indexOf("Column") !== -1) + slice = (backendValue.expression.indexOf("Slice") !== -1) + multi = (backendValue.expression.indexOf("MultiSeries") !== -1) + + itemBox.checked = item + rowBox.checked = row + columnBox.checked = column + sliceBox.checked = slice + multiSeriesBox.checked = multi + } + + onSelectionChangedFlagChanged: evaluate() + + onIsInModelChanged: evaluate() + + onIsInSubStateChanged: evaluate() + + onBackendValueChanged: evaluate() + + onValueFromBackendChanged: evaluate() + + ColumnLayout { + anchors.fill: parent + + Controls.CheckBox { + id: itemBox + text: "Item" + Layout.fillWidth: true + onClicked: { + selectionLayout.item = checked + selectionLayout.composeSelectionMode() + } + } + Controls.CheckBox { + id: rowBox + text: "Row" + Layout.fillWidth: true + onClicked: { + selectionLayout.row = checked + selectionLayout.composeSelectionMode() + } + } + Controls.CheckBox { + id: columnBox + text: "Column" + Layout.fillWidth: true + onClicked: { + selectionLayout.column = checked + selectionLayout.composeSelectionMode() + } + } + Controls.CheckBox { + id: sliceBox + text: "Slice" + Layout.fillWidth: true + onClicked: { + selectionLayout.slice = checked + selectionLayout.composeSelectionMode() + } + } + Controls.CheckBox { + id: multiSeriesBox + text: "MultiSeries" + Layout.fillWidth: true + onClicked: { + selectionLayout.multi = checked + selectionLayout.composeSelectionMode() + } + } + } + } + } + } + + GraphsSection {} + + GraphsCameraSection {} +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/GraphsCameraSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/GraphsCameraSection.qml new file mode 100644 index 00000000000..dd7d64ee911 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/GraphsCameraSection.qml @@ -0,0 +1,189 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import HelperWidgets +import QtQuick.Layouts +import StudioTheme as StudioTheme + +Section { + width: parent.width + caption: qsTr("Camera") + + SectionLayout { + PropertyLabel { + text: qsTr("Preset") + tooltip: qsTr("Camera preset") + } + SecondColumnLayout { + ComboBox { + backendValue: backendValues.cameraPreset + model: ["NoPreset", "FrontLow", "Front", "FrontHigh", "LeftLow", + "Left", "LeftHigh", "RightLow", "Right", "RightHigh", "BehindLow", + "Behind", "BehindHigh", "IsometricLeft", "IsometricLeftHigh", + "IsometricRight", "IsometricRightHigh", "DirectlyAbove", + "DirectlyAboveCW45", "DirectlyAboveCCW45", "FrontBelow", + "LeftBelow", "RightBelow", "BehindBelow", "DirectlyBelow"] + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + scope: "Graphs3D" + } + } + PropertyLabel { + text: qsTr("Target") + tooltip: qsTr("Camera target position") + } + SecondColumnLayout { + SpinBox { + backendValue: backendValues.cameraTargetPosition_x + minimumValue: -1.0 + maximumValue: 1.0 + stepSize: 0.01 + decimals: 2 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + } + ControlLabel { + text: "X" + width: StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel {} + SecondColumnLayout { + SpinBox { + backendValue: backendValues.cameraTargetPosition_y + minimumValue: -1.0 + maximumValue: 1.0 + stepSize: 0.01 + decimals: 2 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + } + ControlLabel { + text:"Y" + width: StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel {} + SecondColumnLayout { + SpinBox { + backendValue: backendValues.cameraTargetPosition_z + minimumValue: -1.0 + maximumValue: 1.0 + stepSize: 0.01 + decimals: 2 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + } + ControlLabel { + text: "Z" + width: StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Zoom") + tooltip: qsTr("Camera zoom level") + } + SecondColumnLayout { + SpinBox { + backendValue: backendValues.cameraZoomLevel + minimumValue: 0 + maximumValue: 500 + stepSize: 1 + decimals: 0 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Min Zoom") + tooltip: qsTr("Camera minimum zoom") + } + SecondColumnLayout { + SpinBox { + backendValue: backendValues.minCameraZoomLevel + minimumValue: 0 + maximumValue: 500 + stepSize: 1 + decimals: 0 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Max Zoom") + tooltip: qsTr("Camera maximum zoom") + } + SecondColumnLayout { + SpinBox { + backendValue: backendValues.maxCameraZoomLevel + minimumValue: 0 + maximumValue: 500 + stepSize: 1 + decimals: 0 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("X Rotation") + tooltip: qsTr("Camera X rotation") + } + SecondColumnLayout { + SpinBox { + backendValue: backendValues.cameraXRotation + minimumValue: -180 + maximumValue: 180 + stepSize: 1 + decimals: 0 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Wrap X") + tooltip: qsTr("Wrap camera X rotation") + } + SecondColumnLayout { + CheckBox { + backendValue: backendValues.wrapCameraXRotation + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Y Rotation") + tooltip: qsTr("Camera Y rotation") + } + SecondColumnLayout { + SpinBox { + backendValue: backendValues.cameraYRotation + minimumValue: 0 + maximumValue: 90 + stepSize: 1 + decimals: 0 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Wrap Y") + tooltip: qsTr("Wrap camera Y rotation") + } + SecondColumnLayout { + CheckBox { + backendValue: backendValues.wrapCameraYRotation + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Orthographic") + tooltip: qsTr("Use orthographic camera") + } + SecondColumnLayout { + CheckBox { + backendValue: backendValues.orthoProjection + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/GraphsSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/GraphsSection.qml new file mode 100644 index 00000000000..ee97514b6b1 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/GraphsSection.qml @@ -0,0 +1,124 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import HelperWidgets +import QtQuick.Layouts +import StudioTheme as StudioTheme + +Section { + width: parent.width + caption: qsTr("Graph") + + SectionLayout { + PropertyLabel { + text: qsTr("Render Mode") + tooltip: qsTr("Rendering mode") + } + SecondColumnLayout { + ComboBox { + backendValue: backendValues.renderingMode + model: ["Indirect", "DirectToBackground"] + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + scope: "Graphs3D" + } + } + PropertyLabel { + text: qsTr("Shadow Quality") + tooltip: qsTr("Quality and style of the shadows") + } + SecondColumnLayout { + ComboBox { + backendValue: backendValues.shadowQuality + model: ["None", "Low", "Medium", + "High", "SoftLow", "SoftMedium", + "SoftHigh"] + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + scope: "Graphs3D" + } + } + PropertyLabel { + text: qsTr("Optimization") + tooltip: qsTr("Optimization hint") + } + SecondColumnLayout { + ComboBox { + backendValue: backendValues.optimizationHint + model: ["Default", "Legacy"] + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + scope: "Graphs3D" + } + } + PropertyLabel { + text: qsTr("MSAA") + tooltip: qsTr("Multisample anti-aliasing sample count") + } + SpinBox { + backendValue: backendValues.msaaSamples + minimumValue: 0 + maximumValue: 8 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + PropertyLabel { + text: qsTr("Aspect Ratio") + tooltip: qsTr("Horizontal to vertical aspect ratio") + } + SecondColumnLayout { + SpinBox { + backendValue: backendValues.aspectRatio + minimumValue: 0.1 + maximumValue: 10.0 + stepSize: 0.1 + decimals: 1 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Horizontal AR") + tooltip: qsTr("Horizontal aspect ratio") + } + SecondColumnLayout { + SpinBox { + backendValue: backendValues.horizontalAspectRatio + minimumValue: 0.1 + maximumValue: 10.0 + stepSize: 0.1 + decimals: 1 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Margin") + tooltip: qsTr("Graph background margin") + } + SecondColumnLayout { + SpinBox { + backendValue: backendValues.margin + minimumValue: -1.0 + maximumValue: 100.0 + stepSize: 0.1 + decimals: 1 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Measure FPS") + tooltip: qsTr("Measure rendering speed as Frames Per Second") + } + SecondColumnLayout { + CheckBox { + backendValue: backendValues.measureFps + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + } +} + diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/GraphsViewSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/GraphsViewSpecifics.qml new file mode 100644 index 00000000000..cb23b168ec4 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/GraphsViewSpecifics.qml @@ -0,0 +1,103 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import HelperWidgets +import QtQuick.Layouts +import StudioTheme as StudioTheme + +Column { + width: parent.width + + Section { + width: parent.width + caption: qsTr("Background") + + SectionLayout { + PropertyLabel { + text: qsTr("Color") + } + + ColorEditor { + backendValue: backendValues.backgroundColor + supportGradient: false + } + } + } + + Section { + width: parent.width + caption: qsTr("Margins") + + SectionLayout { + rows: 4 + PropertyLabel { + text: qsTr("Top") + tooltip: qsTr("The amount of empty space on the top of the graph.") + } + + SecondColumnLayout { + SpinBox { + backendValue: backendValues.marginTop + minimumValue: 0.0 + maximumValue: 9999.0 + stepSize: 1.0 + decimals: 1 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + + PropertyLabel { + text: qsTr("Bottom") + tooltip: qsTr("The amount of empty space on the bottom of the graph.") + } + + SecondColumnLayout { + SpinBox { + backendValue: backendValues.marginBottom + minimumValue: 0.0 + maximumValue: 9999.0 + stepSize: 1.0 + decimals: 1 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + + PropertyLabel { + text: qsTr("Left") + tooltip: qsTr("The amount of empty space on the left of the graph.") + } + + SecondColumnLayout { + SpinBox { + backendValue: backendValues.marginLeft + minimumValue: 0.0 + maximumValue: 9999.0 + stepSize: 1.0 + decimals: 1 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + + PropertyLabel { + text: qsTr("Right") + tooltip: qsTr("The amount of empty space on the right of the graph.") + } + + SecondColumnLayout { + SpinBox { + backendValue: backendValues.marginRight + minimumValue: 0.0 + maximumValue: 9999.0 + stepSize: 1.0 + decimals: 1 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/Scatter3DSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/Scatter3DSpecifics.qml new file mode 100644 index 00000000000..03e3ca6debc --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/Scatter3DSpecifics.qml @@ -0,0 +1,65 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import HelperWidgets +import QtQuick.Layouts +import StudioTheme as StudioTheme + +Column { + width: parent.width + + Section { + width: parent.width + caption: qsTr("Scatter") + + SectionLayout { + PropertyLabel { + text: qsTr("Polar Coordinates") + tooltip: qsTr("Use polar coordinates") + } + SecondColumnLayout { + CheckBox { + id: polarCheckbox + backendValue: backendValues.polar + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Label Offset") + tooltip: qsTr("Normalized horizontal radial label offset") + visible: polarCheckbox.checked + } + SecondColumnLayout { + visible: polarCheckbox.checked + SpinBox { + backendValue: backendValues.radialLabelOffset + minimumValue: 0.0 + maximumValue: 1.0 + stepSize: 0.01 + decimals: 2 + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + } + PropertyLabel { + text: qsTr("Selection Mode") + tooltip: qsTr("Scatter item selection mode") + } + SecondColumnLayout { + ComboBox { + backendValue: backendValues.selectionMode + model: ["None", "Item"] + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + scope: "Graphs3D" + } + } + } + } + + GraphsSection {} + + GraphsCameraSection {} +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/Surface3DSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/Surface3DSpecifics.qml new file mode 100644 index 00000000000..66a1d65f87c --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtGraphs/Surface3DSpecifics.qml @@ -0,0 +1,192 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import QtQuick +import HelperWidgets +import QtQuick.Layouts +import QtQuick.Controls as Controls + +Column { + anchors.left: parent.left + anchors.right: parent.right + + Section { + anchors.left: parent.left + anchors.right: parent.right + caption: qsTr("Surface") + + SectionLayout { + PropertyLabel { + text: qsTr("Flip Grid") + tooltip: qsTr("Flip horizontal grid") + Layout.fillWidth: true + } + SecondColumnLayout { + CheckBox { + backendValue: backendValues.flipHorizontalGrid + Layout.fillWidth: true + } + } + PropertyLabel { + text: qsTr("Polar Coordinates") + tooltip: qsTr("Use polar coordinates") + Layout.fillWidth: true + } + SecondColumnLayout { + CheckBox { + id: polarCheckbox + backendValue: backendValues.polar + Layout.fillWidth: true + } + } + PropertyLabel { + text: qsTr("Label Offset") + tooltip: qsTr("Normalized horizontal radial label offset") + Layout.fillWidth: true + visible: polarCheckbox.checked + } + SecondColumnLayout { + visible: polarCheckbox.checked + SpinBox { + backendValue: backendValues.radialLabelOffset + minimumValue: 0.0 + maximumValue: 1.0 + stepSize: 0.01 + decimals: 2 + Layout.fillWidth: true + } + } + PropertyLabel { + text: qsTr("Selection Mode") + tooltip: qsTr("Surface point selection mode") + Layout.fillWidth: true + } + SecondColumnLayout { + id: selectionLayout + property bool isInModel: backendValue.isInModel; + property bool isInSubState: backendValue.isInSubState; + property bool selectionChangedFlag: selectionChanged + property variant backendValue: backendValues.selectionMode + property variant valueFromBackend: backendValue.value + property string enumScope: "Graphs3D.SelectionFlag" + property string enumSeparator: " | " + property int checkedCount: 0 + property bool item: false + property bool row: false + property bool column: false + property bool slice: false + property bool multi: false + + function checkValue(checkedVariable, variableText, expressionBase) { + var expressionStr = expressionBase + if (checkedVariable) { + if (expressionStr !== "") { + expressionStr += enumSeparator + } + expressionStr += enumScope + expressionStr += "." + expressionStr += variableText + checkedCount++ + } + return expressionStr + } + + function composeSelectionMode() { + var expressionStr = "" + checkedCount = 0 + expressionStr = checkValue(item, "Item", expressionStr) + expressionStr = checkValue(row, "Row", expressionStr) + expressionStr = checkValue(column, "Column", expressionStr) + expressionStr = checkValue(slice, "Slice", expressionStr) + expressionStr = checkValue(multi, "MultiSeries", expressionStr) + + if (checkedCount === 0) + backendValue.expression = enumScope + ".None" + else + backendValue.expression = expressionStr + } + + function evaluate() { + if (backendValue.value === undefined) + return + + item = (backendValue.expression.indexOf("Item") !== -1) + row = (backendValue.expression.indexOf("Row") !== -1) + column = (backendValue.expression.indexOf("Column") !== -1) + slice = (backendValue.expression.indexOf("Slice") !== -1) + multi = (backendValue.expression.indexOf("MultiSeries") !== -1) + + itemBox.checked = item + rowBox.checked = row + columnBox.checked = column + sliceBox.checked = slice + multiSeriesBox.checked = multi + } + + onSelectionChangedFlagChanged: evaluate() + + onIsInModelChanged: evaluate() + + onIsInSubStateChanged: evaluate() + + onBackendValueChanged: evaluate() + + onValueFromBackendChanged: evaluate() + + ColumnLayout { + anchors.fill: parent + + Controls.CheckBox { + id: itemBox + text: "Item" + Layout.fillWidth: true + onClicked: { + selectionLayout.item = checked + selectionLayout.composeSelectionMode() + } + } + Controls.CheckBox { + id: rowBox + text: "Row" + Layout.fillWidth: true + onClicked: { + selectionLayout.row = checked + selectionLayout.composeSelectionMode() + } + } + Controls.CheckBox { + id: columnBox + text: "Column" + Layout.fillWidth: true + onClicked: { + selectionLayout.column = checked + selectionLayout.composeSelectionMode() + } + } + Controls.CheckBox { + id: sliceBox + text: "Slice" + Layout.fillWidth: true + onClicked: { + selectionLayout.slice = checked + selectionLayout.composeSelectionMode() + } + } + Controls.CheckBox { + id: multiSeriesBox + text: "MultiSeries" + Layout.fillWidth: true + onClicked: { + selectionLayout.multi = checked + selectionLayout.composeSelectionMode() + } + } + } + } + } + } + + GraphsSection {} + + GraphsCameraSection {} +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RectangleSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RectangleSpecifics.qml index cdcea69e066..f5d0b6ec017 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RectangleSpecifics.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/RectangleSpecifics.qml @@ -1,10 +1,10 @@ // Copyright (C) 2021 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 HelperWidgets 2.0 -import StudioTheme 1.0 as StudioTheme +import QtQuick +import QtQuick.Layouts +import HelperWidgets +import StudioTheme as StudioTheme Column { anchors.left: parent.left @@ -68,11 +68,21 @@ Column { width: implicitWidth backendValue: backendValues.radius minimumValue: 0 - maximumValue: Math.min(backendValues.height.value, backendValues.width.value) / 2 + maximumValue: 0xffff } ExpandingSpacer {} } } } + + CornerRadiusSection { + id: cornerRadiusSection + property bool radiiAvailable: backendValues.topLeftRadius.isAvailable + // && backendValues.topRightRadius.isAvailable + // && backendValues.bottomLeftRadius.isAvailable + // && backendValues.bottomRightRadius.isAvailable + + visible: majorQtQuickVersion >= 6 && minorQtQuickVersion >= 7 && cornerRadiusSection.radiiAvailable + } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/BoxShapeSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/BoxShapeSection.qml new file mode 100644 index 00000000000..6dfe93f83ee --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/BoxShapeSection.qml @@ -0,0 +1,85 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Section { + caption: qsTr("Box Shape") + width: parent.width + + SectionLayout { + PropertyLabel { + text: qsTr("Extents") + tooltip: qsTr("The extents of the box shape in the X, Y and Z directions.") + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: 0 + maximumValue: 9999999 + decimals: 3 + backendValue: backendValues.extents_x + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "X" + color: StudioTheme.Values.theme3DAxisXColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: 0 + maximumValue: 9999999 + decimals: 3 + backendValue: backendValues.extents_y + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Y" + color: StudioTheme.Values.theme3DAxisYColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: 0 + maximumValue: 9999999 + decimals: 3 + backendValue: backendValues.extents_z + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Z" + color: StudioTheme.Values.theme3DAxisZColor + } + + ExpandingSpacer {} + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/BoxShapeSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/BoxShapeSpecifics.qml new file mode 100644 index 00000000000..c6ac4e6964f --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/BoxShapeSpecifics.qml @@ -0,0 +1,22 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets + +Column { + width: parent.width + + BoxShapeSection { + width: parent.width + } + + CollisionShapeSection { + width: parent.width + } + + NodeSection { + width: parent.width + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CapsuleShapeSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CapsuleShapeSection.qml new file mode 100644 index 00000000000..2283f934489 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CapsuleShapeSection.qml @@ -0,0 +1,50 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Section { + caption: qsTr("Capsule Shape") + width: parent.width + + SectionLayout { + PropertyLabel { + text: qsTr("Diameter") + tooltip: qsTr("Sets the diameter of the capsule.") + } + + SecondColumnLayout { + SpinBox { + minimumValue: 0 + maximumValue: 9999999 + decimals: 3 + backendValue: backendValues.diameter + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Height") + tooltip: qsTr("Sets the height of the capsule.") + } + + SecondColumnLayout { + SpinBox { + minimumValue: 0 + maximumValue: 9999999 + decimals: 3 + backendValue: backendValues.height + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CapsuleShapeSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CapsuleShapeSpecifics.qml new file mode 100644 index 00000000000..eedfbb37e33 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CapsuleShapeSpecifics.qml @@ -0,0 +1,22 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets + +Column { + width: parent.width + + CapsuleShapeSection { + width: parent.width + } + + CollisionShapeSection { + width: parent.width + } + + NodeSection { + width: parent.width + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CharacterControllerSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CharacterControllerSection.qml new file mode 100644 index 00000000000..b7c1d82baa7 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CharacterControllerSection.qml @@ -0,0 +1,188 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Section { + caption: qsTr("Character Controller") + width: parent.width + + SectionLayout { + PropertyLabel { + text: "Gravity" + tooltip: "The gravitational acceleration that applies to the character." + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.gravity_x + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "X" + color: StudioTheme.Values.theme3DAxisXColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.gravity_y + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Y" + color: StudioTheme.Values.theme3DAxisYColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.gravity_z + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Z" + color: StudioTheme.Values.theme3DAxisZColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: "Movement" + tooltip: "The controlled motion of the character." + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.movement_x + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "X" + color: StudioTheme.Values.theme3DAxisXColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.movement_y + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Y" + color: StudioTheme.Values.theme3DAxisYColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.movement_z + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Z" + color: StudioTheme.Values.theme3DAxisZColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: "Mid Air Control" + tooltip: "Enables movement property to have an effect when the character is in free fall." + } + + SecondColumnLayout { + CheckBox { + text: backendValues.midAirControl.valueToString + backendValue: backendValues.midAirControl + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: "Enable ShapeHit Callback" + tooltip: "Enables the shapeHit callback for this character controller." + } + + SecondColumnLayout { + CheckBox { + text: backendValues.midAirControl.valueToString + backendValue: backendValues.enableShapeHitCallback + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CharacterControllerSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CharacterControllerSpecifics.qml new file mode 100644 index 00000000000..bc65d7ca752 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CharacterControllerSpecifics.qml @@ -0,0 +1,26 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets + +Column { + width: parent.width + + CharacterControllerSection { + width: parent.width + } + + PhysicsBodySection { + width: parent.width + } + + PhysicsNodeSection { + width: parent.width + } + + NodeSection { + width: parent.width + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CollisionShapeSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CollisionShapeSection.qml new file mode 100644 index 00000000000..8ab32582cea --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/CollisionShapeSection.qml @@ -0,0 +1,34 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Column { + width: parent.width + + Section { + width: parent.width + caption: qsTr("Collision Shape") + + SectionLayout { + PropertyLabel { + text: qsTr("Debug Draw") + tooltip: qsTr("Draws the collision shape in the scene view.") + } + + SecondColumnLayout { + CheckBox { + text: backendValues.enableDebugDraw.valueToString + backendValue: backendValues.enableDebugDraw + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/ConvexMeshShapeSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/ConvexMeshShapeSection.qml new file mode 100644 index 00000000000..cc7fb9cc04a --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/ConvexMeshShapeSection.qml @@ -0,0 +1,28 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets + +Section { + caption: qsTr("Convex Mesh Shape") + width: parent.width + + SectionLayout { + PropertyLabel { + text: qsTr("Source") + tooltip: qsTr("Defines the location of the mesh file used to define the shape.") + } + + SecondColumnLayout { + UrlChooser { + id: sourceUrlChooser + backendValue: backendValues.source + filter: "*.mesh" + } + + ExpandingSpacer {} + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/ConvexMeshShapeSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/ConvexMeshShapeSpecifics.qml new file mode 100644 index 00000000000..c4f4e325f7d --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/ConvexMeshShapeSpecifics.qml @@ -0,0 +1,22 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets + +Column { + width: parent.width + + ConvexMeshShapeSection { + width: parent.width + } + + CollisionShapeSection { + width: parent.width + } + + NodeSection { + width: parent.width + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/DynamicRigidBodySection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/DynamicRigidBodySection.qml new file mode 100644 index 00000000000..8574a37a5de --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/DynamicRigidBodySection.qml @@ -0,0 +1,658 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Column { + width: parent.width + + Section { + width: parent.width + caption: qsTr("Dynamic Rigid Body") + + SectionLayout { + id: baseSectionLayout + + property bool isDefaultDensityMode: massModeComboBox.currentIndex === 0 + property bool isCustomDensityMode: massModeComboBox.currentIndex === 1 + property bool isMassMode: massModeComboBox.currentIndex === 2 + property bool isMassAndInertiaTensorMode: massModeComboBox.currentIndex === 3 + property bool isMassAndInertiaMatrixMode: massModeComboBox.currentIndex === 4 + + PropertyLabel { + text: "Mass Mode" + tooltip: "Describes how mass and inertia are calculated for this body." + } + + SecondColumnLayout { + ComboBox { + id: massModeComboBox + scope: "DynamicRigidBody" + model: ["DefaultDensity", "CustomDensity", "Mass", "MassAndInertiaTensor", "MassAndInertiaMatrix"] + backendValue: backendValues.massMode + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { + visible: baseSectionLayout.isMassAndInertiaMatrixMode || baseSectionLayout.isMassAndInertiaTensorMode + } + + SecondColumnLayout { + visible: baseSectionLayout.isMassAndInertiaMatrixMode || baseSectionLayout.isMassAndInertiaTensorMode + + Item { + // spacer for the always hiden action indicator + width: StudioTheme.Values.actionIndicatorWidth + } + + Label { + text: qsTr("Tensor and Matrix modes require QML code.") + Layout.fillWidth: true + Layout.preferredWidth: StudioTheme.Values.singleControlColumnWidth + Layout.minimumWidth: StudioTheme.Values.singleControlColumnWidth + Layout.maximumWidth: StudioTheme.Values.singleControlColumnWidth + } + } + + PropertyLabel { + visible: !baseSectionLayout.isDefaultDensityMode && !baseSectionLayout.isCustomDensityMode + text: "Mass" + tooltip: "The mass of the body." + } + + SecondColumnLayout { + visible: !baseSectionLayout.isDefaultDensityMode && !baseSectionLayout.isCustomDensityMode + SpinBox { + minimumValue: 0 + maximumValue: 9999999 + decimals: 2 + stepSize: 0.01 + backendValue: backendValues.mass + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { + visible: baseSectionLayout.isCustomDensityMode + text: "Density" + tooltip: "The density of the body." + } + + SecondColumnLayout { + visible: baseSectionLayout.isCustomDensityMode + SpinBox { + minimumValue: -1 + maximumValue: 9999999 + decimals: 2 + stepSize: 0.01 + backendValue: backendValues.density + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: "Enable Gravity" + tooltip: "Sets if the body affected by gravity." + } + + SecondColumnLayout { + CheckBox { + text: backendValues.gravityEnabled.valueToString + backendValue: backendValues.gravityEnabled + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: "Linear Axis Lock" + tooltip: "Lock the linear axis of the body." + } + + SecondColumnLayout { + ActionIndicator { + id: linearAxisLockController + icon.color: extFuncLogic.color + icon.text: extFuncLogic.glyph + onClicked: extFuncLogic.show() + forceVisible: extFuncLogic.menuVisible + visible: true + + property var enableLockX: { "value": false, "isInModel": false} + property var enableLockY: { "value": false, "isInModel": false} + property var enableLockZ: { "value": false, "isInModel": false} + + property variant backendValue: backendValues.linearAxisLock + property variant valueFromBackend: backendValue === undefined ? 0 : backendValue.value + property bool blockLocks: false + + onBackendValueChanged: evaluateLocks() + onValueFromBackendChanged: evaluateLocks() + + Connections { + target: modelNodeBackend + function onSelectionChanged() { + evaluateLevels() + } + } + + Component.onCompleted: evaluateLocks() + + function evaluateLocks() { + blockLocks = true + enableLockX = { "value": valueFromBackend & 1, "isInModel": false} + enableLockY = { "value": valueFromBackend & 2, "isInModel": false} + enableLockZ = { "value": valueFromBackend & 4, "isInModel": false} + blockLocks = false + } + + function composeExpressionString() { + if (blockLocks) + return + + let expressionStr = ""; + + if (enableLockX.value || enableLockY.value || enableLockY.value) { + if (enableLockX.value) + expressionStr += " | DynamicRigidBody.LockX"; + if (enableLockY.value) + expressionStr += " | DynamicRigidBody.LockY"; + if (enableLockZ.value) + expressionStr += " | DynamicRigidBody.LockZ"; + + expressionStr = expressionStr.substring(3); + + backendValue.expression = expressionStr + } else { + expressionStr = "DynamicRigidBody.None"; + backendValue.expression = expressionStr + } + } + ExtendedFunctionLogic { + id: extFuncLogic + backendValue: backendValues.linearAxisLock + onReseted: { + linearAxisLockController.enableLockX = { "value": false, "isInModel": false} + linearAxisLockController.enableLockY = { "value": false, "isInModel": false} + linearAxisLockController.enableLockZ = { "value": false, "isInModel": false} + linearAxisLockController.evaluateLocks() + } + } + } + } + PropertyLabel { + // spacer + } + + SecondColumnLayout { + + Item { + // spacer for the always hiden action indicator + width: StudioTheme.Values.actionIndicatorWidth + } + + CheckBox { + text: qsTr("Lock X") + backendValue: linearAxisLockController.enableLockX + actionIndicatorVisible: false + onCheckedChanged: linearAxisLockController.composeExpressionString() + implicitWidth: StudioTheme.Values.twoControlColumnWidth + } + + ExpandingSpacer {} + } + PropertyLabel { + // spacer + } + + SecondColumnLayout { + + Item { + // spacer for the always hiden action indicator + width: StudioTheme.Values.actionIndicatorWidth + } + + CheckBox { + text: qsTr("Lock Y") + backendValue: linearAxisLockController.enableLockY + actionIndicatorVisible: false + onCheckedChanged: linearAxisLockController.composeExpressionString() + implicitWidth: StudioTheme.Values.twoControlColumnWidth + } + + ExpandingSpacer {} + } + PropertyLabel { + // spacer + } + + SecondColumnLayout { + + Item { + // spacer for the always hiden action indicator + width: StudioTheme.Values.actionIndicatorWidth + } + + CheckBox { + text: qsTr("Lock Z") + backendValue: linearAxisLockController.enableLockZ + actionIndicatorVisible: false + onCheckedChanged: linearAxisLockController.composeExpressionString() + implicitWidth: StudioTheme.Values.twoControlColumnWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: "Angular Axis Lock" + tooltip: "Lock the angular axis of the body." + } + + SecondColumnLayout { + ActionIndicator { + id: angularAxisLockController + icon.color: extFuncLogicAngular.color + icon.text: extFuncLogicAngular.glyph + onClicked: extFuncLogicAngular.show() + forceVisible: extFuncLogic.menuVisible + visible: true + + property var enableLockX: { "value": false, "isInModel": false} + property var enableLockY: { "value": false, "isInModel": false} + property var enableLockZ: { "value": false, "isInModel": false} + + property variant backendValue: backendValues.angularAxisLock + property variant valueFromBackend: backendValue === undefined ? 0 : backendValue.value + property bool blockLocks: false + + onBackendValueChanged: evaluateLocks() + onValueFromBackendChanged: evaluateLocks() + + Connections { + target: modelNodeBackend + function onSelectionChanged() { + evaluateLevels() + } + } + + Component.onCompleted: evaluateLocks() + + function evaluateLocks() { + blockLocks = true + enableLockX = { "value": valueFromBackend & 1, "isInModel": false} + enableLockY = { "value": valueFromBackend & 2, "isInModel": false} + enableLockZ = { "value": valueFromBackend & 4, "isInModel": false} + blockLocks = false + } + + function composeExpressionString() { + if (blockLocks) + return + + let expressionStr = ""; + + if (enableLockX.value || enableLockY.value || enableLockY.value) { + if (enableLockX.value) + expressionStr += " | DynamicRigidBody.LockX"; + if (enableLockY.value) + expressionStr += " | DynamicRigidBody.LockY"; + if (enableLockZ.value) + expressionStr += " | DynamicRigidBody.LockZ"; + + expressionStr = expressionStr.substring(3); + + backendValue.expression = expressionStr + } else { + expressionStr = "DynamicRigidBody.None"; + backendValue.expression = expressionStr + } + } + ExtendedFunctionLogic { + id: extFuncLogicAngular + backendValue: backendValues.angularAxisLock + onReseted: { + angularAxisLockController.enableLockX = { "value": false, "isInModel": false} + angularAxisLockController.enableLockY = { "value": false, "isInModel": false} + angularAxisLockController.enableLockZ = { "value": false, "isInModel": false} + angularAxisLockController.evaluateLocks() + } + } + } + } + PropertyLabel { + // spacer + } + + SecondColumnLayout { + + Item { + // spacer for the always hiden action indicator + width: StudioTheme.Values.actionIndicatorWidth + } + + CheckBox { + text: qsTr("Lock X") + backendValue: angularAxisLockController.enableLockX + actionIndicatorVisible: false + onCheckedChanged: angularAxisLockController.composeExpressionString() + implicitWidth: StudioTheme.Values.twoControlColumnWidth + } + + ExpandingSpacer {} + } + PropertyLabel { + // spacer + } + + SecondColumnLayout { + + Item { + // spacer for the always hiden action indicator + width: StudioTheme.Values.actionIndicatorWidth + } + + CheckBox { + text: qsTr("Lock Y") + backendValue: angularAxisLockController.enableLockY + actionIndicatorVisible: false + onCheckedChanged: angularAxisLockController.composeExpressionString() + implicitWidth: StudioTheme.Values.twoControlColumnWidth + } + + ExpandingSpacer {} + } + PropertyLabel { + // spacer + } + + SecondColumnLayout { + + Item { + // spacer for the always hiden action indicator + width: StudioTheme.Values.actionIndicatorWidth + } + + CheckBox { + text: qsTr("Lock Z") + backendValue: angularAxisLockController.enableLockZ + actionIndicatorVisible: false + onCheckedChanged: angularAxisLockController.composeExpressionString() + implicitWidth: StudioTheme.Values.twoControlColumnWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: "Is Kinematic" + tooltip: "Kinematic objects are not influenced by external forces and can be seen as an object of infinite mass." + } + + SecondColumnLayout { + CheckBox { + id: isKinematicCheckBox + text: backendValues.isKinematic.valueToString + backendValue: backendValues.isKinematic + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { + visible: isKinematicCheckBox.checked + text: "Kinematic Position" + tooltip: "The position of the kinematic object." + } + + SecondColumnLayout { + visible: isKinematicCheckBox.checked + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.kinematicPosition_x + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "X" + color: StudioTheme.Values.theme3DAxisXColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + visible: isKinematicCheckBox.checked + } + + SecondColumnLayout { + visible: isKinematicCheckBox.checked + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.kinematicPosition_y + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Y" + color: StudioTheme.Values.theme3DAxisYColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + visible: isKinematicCheckBox.checked + } + + SecondColumnLayout { + visible: isKinematicCheckBox.checked + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.kinematicPosition_z + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Z" + color: StudioTheme.Values.theme3DAxisZColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + visible: isKinematicCheckBox.checked + text: "Kinematic Rotation" + tooltip: "The rotation of the kinematic object." + } + + SecondColumnLayout { + visible: isKinematicCheckBox.checked + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.kinematicEulerRotation_x + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "X" + color: StudioTheme.Values.theme3DAxisXColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + visible: isKinematicCheckBox.checked + } + + SecondColumnLayout { + visible: isKinematicCheckBox.checked + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.kinematicEulerRotation_y + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Y" + color: StudioTheme.Values.theme3DAxisYColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + visible: isKinematicCheckBox.checked + } + + SecondColumnLayout { + visible: isKinematicCheckBox.checked + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.kinematicEulerRotation_z + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Z" + color: StudioTheme.Values.theme3DAxisZColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + visible: isKinematicCheckBox.checked + text: "Kinematic Pivot" + tooltip: "The pivot point of the kinematic object." + } + + SecondColumnLayout { + visible: isKinematicCheckBox.checked + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.kinematicPivot_x + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "X" + color: StudioTheme.Values.theme3DAxisXColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + visible: isKinematicCheckBox.checked + } + + SecondColumnLayout { + visible: isKinematicCheckBox.checked + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.kinematicPivot_y + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Y" + color: StudioTheme.Values.theme3DAxisYColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + visible: isKinematicCheckBox.checked + } + + SecondColumnLayout { + visible: isKinematicCheckBox.checked + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.kinematicPivot_z + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Z" + color: StudioTheme.Values.theme3DAxisZColor + } + + ExpandingSpacer {} + } + } + } +} + + // Other Properties Not covered by the UI + // QVector3D inertiaTensor + // QVector3D centerOfMassPosition + // QQuaternion centerOfMassRotation + // List inertiaMatrix (9 floats for a Mat3x3) + diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/DynamicRigidBodySpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/DynamicRigidBodySpecifics.qml new file mode 100644 index 00000000000..7322d3339be --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/DynamicRigidBodySpecifics.qml @@ -0,0 +1,26 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets + +Column { + width: parent.width + + DynamicRigidBodySection { + width: parent.width + } + + PhysicsBodySection { + width: parent.width + } + + PhysicsNodeSection { + width: parent.width + } + + NodeSection { + width: parent.width + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/HeightFieldShapeSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/HeightFieldShapeSection.qml new file mode 100644 index 00000000000..80c6f428e97 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/HeightFieldShapeSection.qml @@ -0,0 +1,98 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Section { + caption: qsTr("Height Field Shape") + width: parent.width + + SectionLayout { + PropertyLabel { + text: qsTr("Source") + tooltip: qsTr("Sets the location of an image file containing the heightmap data.") + } + + SecondColumnLayout { + UrlChooser { + backendValue: backendValues.source + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Extents") + tooltip: qsTr("The extents of the height field shape in the X, Y and Z directions.") + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: 0 + maximumValue: 9999999 + decimals: 3 + backendValue: backendValues.extents_x + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "X" + color: StudioTheme.Values.theme3DAxisXColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: 0 + maximumValue: 9999999 + decimals: 3 + backendValue: backendValues.extents_y + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Y" + color: StudioTheme.Values.theme3DAxisYColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: 0 + maximumValue: 9999999 + decimals: 3 + backendValue: backendValues.extents_z + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Z" + color: StudioTheme.Values.theme3DAxisZColor + } + + ExpandingSpacer {} + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/HeightFieldShapeSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/HeightFieldShapeSpecifics.qml new file mode 100644 index 00000000000..22aa0348b71 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/HeightFieldShapeSpecifics.qml @@ -0,0 +1,23 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Column { + width: parent.width + + HeightFieldShapeSection { + width: parent.width + } + + CollisionShapeSection { + width: parent.width + } + + NodeSection { + width: parent.width + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/NodeSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/NodeSection.qml new file mode 100644 index 00000000000..45dfe72a77d --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/NodeSection.qml @@ -0,0 +1,350 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Column { + width: parent.width + + Section { + width: parent.width + caption: qsTr("Node") + + SectionLayout { + PropertyLabel { + text: qsTr("Opacity") + tooltip: qsTr("Sets the local opacity value of the node.") + } + + SecondColumnLayout { + // ### should be a slider + SpinBox { + minimumValue: 0 + maximumValue: 1 + decimals: 2 + stepSize: 0.1 + backendValue: backendValues.opacity + sliderIndicatorVisible: true + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Visibility") + tooltip: qsTr("Sets the local visibility of the node.") + } + + SecondColumnLayout { + // ### should be a slider + CheckBox { + text: qsTr("Is Visible") + backendValue: backendValues.visible + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + } + } + + Section { + id: transformSection + width: parent.width + caption: qsTr("Transform") + + ColumnLayout { + spacing: StudioTheme.Values.transform3DSectionSpacing + + SectionLayout { + PropertyLabel { + text: qsTr("Translation") + tooltip: qsTr("Sets the translation of the node.") + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.x + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "X" + color: StudioTheme.Values.theme3DAxisXColor + } + + ExpandingSpacer {} + } + + PropertyLabel {} + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.y + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Y" + color: StudioTheme.Values.theme3DAxisYColor + } + + ExpandingSpacer {} + } + + PropertyLabel {} + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.z + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Z" + color: StudioTheme.Values.theme3DAxisZColor + } + + ExpandingSpacer {} + } + } + + SectionLayout { + PropertyLabel { + text: qsTr("Rotation") + tooltip: qsTr("Sets the rotation of the node in degrees.") + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.eulerRotation_x + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "X" + color: StudioTheme.Values.theme3DAxisXColor + } + + ExpandingSpacer {} + } + + PropertyLabel {} + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.eulerRotation_y + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Y" + color: StudioTheme.Values.theme3DAxisYColor + } + + ExpandingSpacer {} + } + + PropertyLabel {} + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.eulerRotation_z + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Z" + color: StudioTheme.Values.theme3DAxisZColor + } + + ExpandingSpacer {} + } + } + + SectionLayout { + PropertyLabel { + text: qsTr("Scale") + tooltip: qsTr("Sets the scale of the node.") + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.scale_x + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "X" + color: StudioTheme.Values.theme3DAxisXColor + } + + ExpandingSpacer {} + } + + PropertyLabel {} + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.scale_y + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Y" + color: StudioTheme.Values.theme3DAxisYColor + } + + ExpandingSpacer {} + } + + PropertyLabel {} + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.scale_z + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Z" + color: StudioTheme.Values.theme3DAxisZColor + } + + ExpandingSpacer {} + } + } + + SectionLayout { + PropertyLabel { + text: qsTr("Pivot") + tooltip: qsTr("Sets the pivot of the node.") + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.pivot_x + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "X" + color: StudioTheme.Values.theme3DAxisXColor + } + + ExpandingSpacer {} + } + + PropertyLabel {} + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.pivot_y + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Y" + color: StudioTheme.Values.theme3DAxisYColor + } + + ExpandingSpacer {} + } + + PropertyLabel {} + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.pivot_z + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Z" + color: StudioTheme.Values.theme3DAxisZColor + } + + ExpandingSpacer {} + } + } + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsBodySection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsBodySection.qml new file mode 100644 index 00000000000..8f5d67f4a42 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsBodySection.qml @@ -0,0 +1,34 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Column { + width: parent.width + + Section { + caption: qsTr("Physics Body") + width: parent.width + + SectionLayout { + PropertyLabel { + text: qsTr("Physics Material") + tooltip: qsTr("The physics material of the body.") + } + + SecondColumnLayout { + ItemFilterComboBox { + typeFilter: "QtQuick3D.Physics.PhysicsMaterial" + backendValue: backendValues.physicsMaterial + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsMaterialSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsMaterialSection.qml new file mode 100644 index 00000000000..3e0c08655ea --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsMaterialSection.qml @@ -0,0 +1,69 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Section { + caption: qsTr("Physics Material") + width: parent.width + + SectionLayout { + PropertyLabel { + text: "Static Friction" + tooltip: "The friction coefficient of the material when it is not moving." + } + + SecondColumnLayout { + SpinBox { + minimumValue: 0 + maximumValue: 9999999 + decimals: 2 + stepSize: 0.01 + backendValue: backendValues.staticFriction + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + ExpandingSpacer {} + } + + PropertyLabel { + text: "Dynamic Friction" + tooltip: "The friction coefficient of the material when it is moving." + } + + SecondColumnLayout { + SpinBox { + minimumValue: 0 + maximumValue: 9999999 + decimals: 2 + stepSize: 0.01 + backendValue: backendValues.dynamicFriction + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + ExpandingSpacer {} + } + + PropertyLabel { + text: "Restitution" + tooltip: "The coefficient of restitution of the material." + } + + SecondColumnLayout { + SpinBox { + minimumValue: 0 + maximumValue: 1 + decimals: 2 + stepSize: 0.01 + sliderIndicatorVisible: true + backendValue: backendValues.restitution + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + ExpandingSpacer {} + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsMaterialSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsMaterialSpecifics.qml new file mode 100644 index 00000000000..95ebaf70127 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsMaterialSpecifics.qml @@ -0,0 +1,13 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets + +Column { + width: parent.width + PhysicsMaterialSection { + width: parent.width + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsNodeSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsNodeSection.qml new file mode 100644 index 00000000000..26fdf0e4d87 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsNodeSection.qml @@ -0,0 +1,103 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Column { + width: parent.width + + Section { + width: parent.width + caption: qsTr("Physics Node") + + SectionLayout { + PropertyLabel { + text: qsTr("Collision Shapes") + Layout.alignment: Qt.AlignTop + Layout.topMargin: 5 + } + + SecondColumnLayout { + EditableListView { + backendValue: backendValues.collisionShapes + model: backendValues.collisionShapes.expressionAsList + Layout.fillWidth: true + typeFilter: "QtQuick3D.Physics.CollisionShape" + + onAdd: function(value) { backendValues.collisionShapes.idListAdd(value) } + onRemove: function(idx) { backendValues.collisionShapes.idListRemove(idx) } + onReplace: function (idx, value) { backendValues.collisionShapes.idListReplace(idx, value) } + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Receive Contact Reports") + tooltip: qsTr("Determines whether this body will receive contact reports when colliding with other bodies.") + } + + SecondColumnLayout { + CheckBox { + text: backendValues.receiveContactReports.valueToString + backendValue: backendValues.receiveContactReports + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Send Contact Reports") + tooltip: qsTr("Determines whether this body will send contact reports when colliding with other bodies.") + } + + SecondColumnLayout { + CheckBox { + text: backendValues.sendContactReports.valueToString + backendValue: backendValues.sendContactReports + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Receive Trigger Reports") + tooltip: qsTr("Determines whether this body will receive reports when entering or leaving a trigger body.") + } + + SecondColumnLayout { + CheckBox { + text: backendValues.receiveTriggerReports.valueToString + backendValue: backendValues.receiveTriggerReports + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + PropertyLabel { + text: qsTr("Send Trigger Reports") + tooltip: qsTr("Determines whether this body will send contact reports when colliding with other bodies.") + } + + SecondColumnLayout { + CheckBox { + text: backendValues.sendTriggerReports.valueToString + backendValue: backendValues.sendTriggerReports + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsWorldSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsWorldSection.qml new file mode 100644 index 00000000000..3299e984bec --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsWorldSection.qml @@ -0,0 +1,266 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Section { + caption: qsTr("Physics World") + width: parent.width + + SectionLayout { + // Q_PROPERTY(QQuick3DNode *scene + PropertyLabel { + text: qsTr("Scene") + tooltip: qsTr("The scene node to which the physics world is attached.") + } + + SecondColumnLayout { + ItemFilterComboBox { + typeFilter: "QtQuick3D.Node" + backendValue: backendValues.scene + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + // Q_PROPERTY(QQuick3DNode *viewport + PropertyLabel { + text: qsTr("Viewport") + tooltip: qsTr("The node to which the debug geometry of the physics world is added.") + } + + SecondColumnLayout { + ItemFilterComboBox { + typeFilter: "QtQuick3D.Node" + backendValue: backendValues.viewport + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + // Q_PROPERTY(bool running) + PropertyLabel { + text: qsTr("Running") + tooltip: qsTr("Whether the physics world is running.") + } + + SecondColumnLayout { + CheckBox { + text: backendValues.running.valueToString + backendValue: backendValues.running + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + // Q_PROPERTY(bool forceDebugDraw + PropertyLabel { + text: qsTr("Force Debug Draw") + tooltip: qsTr("Whether to force debug drawing of the physics world.") + } + + SecondColumnLayout { + CheckBox { + text: backendValues.forceDebugDraw.valueToString + backendValue: backendValues.forceDebugDraw + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + // Q_PROPERTY(bool enableCCD + PropertyLabel { + text: qsTr("CCD") + tooltip: qsTr("Whether to enable continuous collision detection.") + } + + SecondColumnLayout { + CheckBox { + text: backendValues.enableCCD.valueToString + backendValue: backendValues.enableCCD + implicitWidth: StudioTheme.Values.twoControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + // Q_PROPERTY(QVector3D gravity) + PropertyLabel { + text: qsTr("Gravity") + tooltip: qsTr("The gravity vector.") + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.gravity_x + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "X" + color: StudioTheme.Values.theme3DAxisXColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.gravity_y + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Y" + color: StudioTheme.Values.theme3DAxisYColor + } + + ExpandingSpacer {} + } + + PropertyLabel { + } + + SecondColumnLayout { + SpinBox { + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + minimumValue: -9999999 + maximumValue: 9999999 + decimals: 2 + backendValue: backendValues.gravity_z + } + + Spacer { implicitWidth: StudioTheme.Values.controlLabelGap } + + ControlLabel { + text: "Z" + color: StudioTheme.Values.theme3DAxisZColor + } + + ExpandingSpacer {} + } + + // Q_PROPERTY(float typicalLength) + PropertyLabel { + text: qsTr("Typical Length") + tooltip: qsTr("The typical length of objects in the scene.") + } + + SecondColumnLayout { + SpinBox { + minimumValue: 0.00001 + maximumValue: 9999999 + decimals: 5 + backendValue: backendValues.typicalLength + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + // Q_PROPERTY(float typicalSpeed + PropertyLabel { + text: qsTr("Typical Speed") + tooltip: qsTr("The typical speed of objects in the scene.") + } + + SecondColumnLayout { + SpinBox { + minimumValue: 0.00001 + maximumValue: 9999999 + decimals: 5 + backendValue: backendValues.typicalSpeed + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + // Q_PROPERTY(float defaultDensity) + PropertyLabel { + text: qsTr("Default Density") + tooltip: qsTr("The default density of objects in the scene.") + } + + SecondColumnLayout { + SpinBox { + minimumValue: 0.00001 + maximumValue: 9999999 + decimals: 5 + backendValue: backendValues.defaultDensity + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + // Q_PROPERTY(float minimumTimestep) + PropertyLabel { + text: qsTr("Min Timestep") + tooltip: qsTr("Defines the minimum simulation timestep in milliseconds.") + } + + SecondColumnLayout { + SpinBox { + minimumValue: 0.001 + maximumValue: 9999999 + decimals: 3 + backendValue: backendValues.minimumTimestep + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + + // Q_PROPERTY(float maximumTimestep) + PropertyLabel { + text: qsTr("Max Timestep") + tooltip: qsTr("Defines the maximum simulation timestep in milliseconds.") + } + + SecondColumnLayout { + SpinBox { + minimumValue: 0.001 + maximumValue: 9999999 + decimals: 3 + backendValue: backendValues.maximumTimestep + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsWorldSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsWorldSpecifics.qml new file mode 100644 index 00000000000..2c29985fd94 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PhysicsWorldSpecifics.qml @@ -0,0 +1,14 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets + +Column { + width: parent.width + + PhysicsWorldSection { + width: parent.width + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PlaneShapeSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PlaneShapeSpecifics.qml new file mode 100644 index 00000000000..0410b5fbf98 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/PlaneShapeSpecifics.qml @@ -0,0 +1,18 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets + +Column { + width: parent.width + + CollisionShapeSection { + width: parent.width + } + + NodeSection { + width: parent.width + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/SphereShapeSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/SphereShapeSection.qml new file mode 100644 index 00000000000..44db7cb322b --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/SphereShapeSection.qml @@ -0,0 +1,32 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Section { + caption: qsTr("Sphere Shape") + width: parent.width + + SectionLayout { + PropertyLabel { + text: qsTr("Diameter") + tooltip: qsTr("Sets the diameter of the capsule.") + } + + SecondColumnLayout { + SpinBox { + minimumValue: 0 + maximumValue: 9999999 + decimals: 3 + backendValue: backendValues.diameter + implicitWidth: StudioTheme.Values.singleControlColumnWidth + + StudioTheme.Values.actionIndicatorWidth + } + + ExpandingSpacer {} + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/SphereShapeSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/SphereShapeSpecifics.qml new file mode 100644 index 00000000000..abee2e31069 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/SphereShapeSpecifics.qml @@ -0,0 +1,22 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets + +Column { + width: parent.width + + SphereShapeSection { + width: parent.width + } + + CollisionShapeSection { + width: parent.width + } + + NodeSection { + width: parent.width + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/StaticRigidBodySpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/StaticRigidBodySpecifics.qml new file mode 100644 index 00000000000..1dc7c4806b0 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/StaticRigidBodySpecifics.qml @@ -0,0 +1,22 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets + +Column { + width: parent.width + + PhysicsBodySection { + width: parent.width + } + + PhysicsNodeSection { + width: parent.width + } + + NodeSection { + width: parent.width + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/TriangleMeshShapeSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/TriangleMeshShapeSection.qml new file mode 100644 index 00000000000..53959a3aa25 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/TriangleMeshShapeSection.qml @@ -0,0 +1,29 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets +import StudioTheme as StudioTheme + +Section { + caption: qsTr("Triangle Mesh Shape") + width: parent.width + + SectionLayout { + PropertyLabel { + text: qsTr("Source") + tooltip: qsTr("Defines the location of the mesh file used to define the shape.") + } + + SecondColumnLayout { + UrlChooser { + id: sourceUrlChooser + backendValue: backendValues.source + filter: "*.mesh" + } + + ExpandingSpacer {} + } + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/TriangleMeshShapeSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/TriangleMeshShapeSpecifics.qml new file mode 100644 index 00000000000..a428872f294 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/TriangleMeshShapeSpecifics.qml @@ -0,0 +1,22 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets + +Column { + width: parent.width + + TriangleMeshShapeSection { + width: parent.width + } + + CollisionShapeSection { + width: parent.width + } + + NodeSection { + width: parent.width + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/TriggerBodySpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/TriggerBodySpecifics.qml new file mode 100644 index 00000000000..f341e48b691 --- /dev/null +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick3D/Physics/TriggerBodySpecifics.qml @@ -0,0 +1,18 @@ +// Copyright (C) 2025 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.Layouts +import HelperWidgets + +Column { + width: parent.width + + PhysicsNodeSection { + width: parent.width + } + + NodeSection { + width: parent.width + } +} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Studio/Components/CornerRadiusSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CornerRadiusSection.qml similarity index 96% rename from share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Studio/Components/CornerRadiusSection.qml rename to share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CornerRadiusSection.qml index b51c7b2dcdf..824881ce2b6 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Studio/Components/CornerRadiusSection.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/CornerRadiusSection.qml @@ -21,7 +21,7 @@ Section { implicitWidth: StudioTheme.Values.twoControlColumnWidth + StudioTheme.Values.actionIndicatorWidth backendValue: backendValues.topLeftRadius - decimals: 1 + decimals: 0 minimumValue: 0 maximumValue: 0xffff stepSize: 1 @@ -40,7 +40,7 @@ Section { implicitWidth: StudioTheme.Values.twoControlColumnWidth + StudioTheme.Values.actionIndicatorWidth backendValue: backendValues.topRightRadius - decimals: 1 + decimals: 0 minimumValue: 0 maximumValue: 0xffff stepSize: 1 @@ -67,7 +67,7 @@ Section { implicitWidth: StudioTheme.Values.twoControlColumnWidth + StudioTheme.Values.actionIndicatorWidth backendValue: backendValues.bottomLeftRadius - decimals: 1 + decimals: 0 minimumValue: 0 maximumValue: 0xffff stepSize: 1 @@ -87,7 +87,7 @@ Section { implicitWidth: StudioTheme.Values.twoControlColumnWidth + StudioTheme.Values.actionIndicatorWidth backendValue: backendValues.bottomRightRadius - decimals: 1 + decimals: 0 minimumValue: 0 maximumValue: 0xffff stepSize: 1 @@ -114,7 +114,7 @@ Section { implicitWidth: StudioTheme.Values.twoControlColumnWidth + StudioTheme.Values.actionIndicatorWidth backendValue: backendValues.radius - decimals: 1 + decimals: 0 minimumValue: 0 maximumValue: 0xffff stepSize: 1 diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml index 0f192f8875f..4cc0c747f73 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml @@ -13,6 +13,7 @@ Item { readonly property bool __isSection: true // used by property search logic property string caption: "Title" + property string captionTooltip: "" property color labelColor: StudioTheme.Values.themeTextColor property int labelCapitalization: Font.AllUppercase property alias sectionHeight: header.height @@ -40,6 +41,20 @@ Item { font.capitalization: section.labelCapitalization anchors.verticalCenter: parent?.verticalCenter textFormat: Text.RichText + + MouseArea { + id: labelMouseArea + + anchors.fill: parent + acceptedButtons: Qt.NoButton + hoverEnabled: true + enabled: section.captionTooltip !== "" + } + + StudioControls.ToolTip { + visible: labelMouseArea.containsMouse + text: section.captionTooltip + } } property Item icons diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir index 29675dfde5b..3b0c5424448 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir @@ -18,6 +18,7 @@ ComponentButton 2.0 ComponentButton.qml ComponentSection 2.0 ComponentSection.qml ControlLabel 2.0 ControlLabel.qml singleton Controller 2.0 Controller.qml +CornerRadiusSection 2.0 CornerRadiusSection.qml DoubleSpinBox 2.0 DoubleSpinBox.qml DynamicPropertiesSection 2.0 DynamicPropertiesSection.qml EditableListView 2.0 EditableListView.qml diff --git a/src/libs/qmlpuppetcommunication/commands/captureddatacommand.h b/src/libs/qmlpuppetcommunication/commands/captureddatacommand.h index 9246317365b..12caf32ebd0 100644 --- a/src/libs/qmlpuppetcommunication/commands/captureddatacommand.h +++ b/src/libs/qmlpuppetcommunication/commands/captureddatacommand.h @@ -131,7 +131,7 @@ public: CapturedDataCommand() = default; - CapturedDataCommand(QVector &&stateData) + CapturedDataCommand(QList &&stateData) : stateData{std::move(stateData)} {} @@ -157,7 +157,7 @@ public: public: QImage image; - QVector stateData; + QList stateData; }; } // namespace QmlDesigner diff --git a/src/libs/qmlpuppetcommunication/commands/changeauxiliarycommand.h b/src/libs/qmlpuppetcommunication/commands/changeauxiliarycommand.h index d36b9e90c23..c74ad7f4eca 100644 --- a/src/libs/qmlpuppetcommunication/commands/changeauxiliarycommand.h +++ b/src/libs/qmlpuppetcommunication/commands/changeauxiliarycommand.h @@ -5,8 +5,8 @@ #include #include +#include #include -#include #include "propertyvaluecontainer.h" @@ -29,7 +29,7 @@ public: friend QDebug operator <<(QDebug debug, const ChangeAuxiliaryCommand &command); - QVector auxiliaryChanges; + QList auxiliaryChanges; }; } // namespace QmlDesigner diff --git a/src/libs/qmlpuppetcommunication/commands/changebindingscommand.h b/src/libs/qmlpuppetcommunication/commands/changebindingscommand.h index 5e9464bbc54..bbab2987c8b 100644 --- a/src/libs/qmlpuppetcommunication/commands/changebindingscommand.h +++ b/src/libs/qmlpuppetcommunication/commands/changebindingscommand.h @@ -3,8 +3,8 @@ #pragma once +#include #include -#include #include "propertybindingcontainer.h" @@ -25,7 +25,7 @@ public: friend QDebug operator <<(QDebug debug, const ChangeBindingsCommand &command); - QVector bindingChanges; + QList bindingChanges; }; } // namespace QmlDesigner diff --git a/src/libs/qmlpuppetcommunication/commands/changeidscommand.h b/src/libs/qmlpuppetcommunication/commands/changeidscommand.h index b0325d96521..6e337012312 100644 --- a/src/libs/qmlpuppetcommunication/commands/changeidscommand.h +++ b/src/libs/qmlpuppetcommunication/commands/changeidscommand.h @@ -4,7 +4,7 @@ #pragma once #include -#include +#include #include #include "idcontainer.h" @@ -27,7 +27,7 @@ public: } friend QDebug operator <<(QDebug debug, const ChangeIdsCommand &command); - QVector ids; + QList ids; }; } // namespace QmlDesigner diff --git a/src/libs/qmlpuppetcommunication/commands/changeselectioncommand.cpp b/src/libs/qmlpuppetcommunication/commands/changeselectioncommand.cpp index e12172da9dc..5ca9c89e4b7 100644 --- a/src/libs/qmlpuppetcommunication/commands/changeselectioncommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/changeselectioncommand.cpp @@ -10,12 +10,12 @@ namespace QmlDesigner { ChangeSelectionCommand::ChangeSelectionCommand() = default; -ChangeSelectionCommand::ChangeSelectionCommand(const QVector &idVector) +ChangeSelectionCommand::ChangeSelectionCommand(const QList &idVector) : m_instanceIdVector(idVector) { } -QVector ChangeSelectionCommand::instanceIds() const +QList ChangeSelectionCommand::instanceIds() const { return m_instanceIdVector; } diff --git a/src/libs/qmlpuppetcommunication/commands/changeselectioncommand.h b/src/libs/qmlpuppetcommunication/commands/changeselectioncommand.h index 56e2cb38ccd..5b245c6cc6c 100644 --- a/src/libs/qmlpuppetcommunication/commands/changeselectioncommand.h +++ b/src/libs/qmlpuppetcommunication/commands/changeselectioncommand.h @@ -3,12 +3,10 @@ #pragma once +#include #include -#include #include -#include "instancecontainer.h" - namespace QmlDesigner { class ChangeSelectionCommand @@ -20,12 +18,12 @@ class ChangeSelectionCommand public: ChangeSelectionCommand(); - explicit ChangeSelectionCommand(const QVector &idVector); + explicit ChangeSelectionCommand(const QList &idVector); - QVector instanceIds() const; + QList instanceIds() const; private: - QVector m_instanceIdVector; + QList m_instanceIdVector; }; QDataStream &operator<<(QDataStream &out, const ChangeSelectionCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/changestatecommand.h b/src/libs/qmlpuppetcommunication/commands/changestatecommand.h index 62cc39afc6d..fc6ce0dcaa2 100644 --- a/src/libs/qmlpuppetcommunication/commands/changestatecommand.h +++ b/src/libs/qmlpuppetcommunication/commands/changestatecommand.h @@ -3,10 +3,8 @@ #pragma once +#include #include -#include - -#include "propertyvaluecontainer.h" namespace QmlDesigner { diff --git a/src/libs/qmlpuppetcommunication/commands/changevaluescommand.cpp b/src/libs/qmlpuppetcommunication/commands/changevaluescommand.cpp index 0fb819d93c1..3a7765031f3 100644 --- a/src/libs/qmlpuppetcommunication/commands/changevaluescommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/changevaluescommand.cpp @@ -9,12 +9,12 @@ namespace QmlDesigner { ChangeValuesCommand::ChangeValuesCommand() = default; -ChangeValuesCommand::ChangeValuesCommand(const QVector &valueChangeVector) +ChangeValuesCommand::ChangeValuesCommand(const QList &valueChangeVector) : m_valueChangeVector (valueChangeVector) { } -const QVector ChangeValuesCommand::valueChanges() const +const QList ChangeValuesCommand::valueChanges() const { return m_valueChangeVector; } diff --git a/src/libs/qmlpuppetcommunication/commands/changevaluescommand.h b/src/libs/qmlpuppetcommunication/commands/changevaluescommand.h index 6dcea149056..3608dde7ffd 100644 --- a/src/libs/qmlpuppetcommunication/commands/changevaluescommand.h +++ b/src/libs/qmlpuppetcommunication/commands/changevaluescommand.h @@ -3,8 +3,8 @@ #pragma once +#include #include -#include #include "propertyvaluecontainer.h" @@ -17,12 +17,12 @@ class ChangeValuesCommand public: ChangeValuesCommand(); - explicit ChangeValuesCommand(const QVector &valueChangeVector); + explicit ChangeValuesCommand(const QList &valueChangeVector); - const QVector valueChanges() const; + const QList valueChanges() const; private: - QVector m_valueChangeVector; + QList m_valueChangeVector; }; QDataStream &operator<<(QDataStream &out, const ChangeValuesCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/childrenchangedcommand.cpp b/src/libs/qmlpuppetcommunication/commands/childrenchangedcommand.cpp index bd805a56aa3..51421d1637a 100644 --- a/src/libs/qmlpuppetcommunication/commands/childrenchangedcommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/childrenchangedcommand.cpp @@ -14,14 +14,14 @@ ChildrenChangedCommand::ChildrenChangedCommand() { } -ChildrenChangedCommand::ChildrenChangedCommand(qint32 parentInstanceId, const QVector &children, const QVector &informationVector) +ChildrenChangedCommand::ChildrenChangedCommand(qint32 parentInstanceId, const QList &children, const QList &informationVector) : m_parentInstanceId(parentInstanceId), m_childrenVector(children), m_informationVector(informationVector) { } -QVector ChildrenChangedCommand::childrenInstances() const +QList ChildrenChangedCommand::childrenInstances() const { return m_childrenVector; } @@ -31,7 +31,7 @@ qint32 ChildrenChangedCommand::parentInstanceId() const return m_parentInstanceId; } -QVector ChildrenChangedCommand::informations() const +QList ChildrenChangedCommand::informations() const { return m_informationVector; } diff --git a/src/libs/qmlpuppetcommunication/commands/childrenchangedcommand.h b/src/libs/qmlpuppetcommunication/commands/childrenchangedcommand.h index f90383ef385..500593a435c 100644 --- a/src/libs/qmlpuppetcommunication/commands/childrenchangedcommand.h +++ b/src/libs/qmlpuppetcommunication/commands/childrenchangedcommand.h @@ -3,8 +3,9 @@ #pragma once +#include #include -#include + #include "informationcontainer.h" namespace QmlDesigner { @@ -16,18 +17,18 @@ class ChildrenChangedCommand public: ChildrenChangedCommand(); - explicit ChildrenChangedCommand(qint32 parentInstanceId, const QVector &childrenInstancesconst, const QVector &informationVector); + explicit ChildrenChangedCommand(qint32 parentInstanceId, const QList &childrenInstancesconst, const QList &informationVector); - QVector childrenInstances() const; + QList childrenInstances() const; qint32 parentInstanceId() const; - QVector informations() const; + QList informations() const; void sort(); private: qint32 m_parentInstanceId; - QVector m_childrenVector; - QVector m_informationVector; + QList m_childrenVector; + QList m_informationVector; }; QDataStream &operator<<(QDataStream &out, const ChildrenChangedCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/completecomponentcommand.cpp b/src/libs/qmlpuppetcommunication/commands/completecomponentcommand.cpp index 9eda245dbfb..b3832866ffc 100644 --- a/src/libs/qmlpuppetcommunication/commands/completecomponentcommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/completecomponentcommand.cpp @@ -10,12 +10,12 @@ namespace QmlDesigner { CompleteComponentCommand::CompleteComponentCommand() = default; -CompleteComponentCommand::CompleteComponentCommand(const QVector &container) +CompleteComponentCommand::CompleteComponentCommand(const QList &container) : m_instanceVector(container) { } -const QVector CompleteComponentCommand::instances() const +const QList CompleteComponentCommand::instances() const { return m_instanceVector; } diff --git a/src/libs/qmlpuppetcommunication/commands/completecomponentcommand.h b/src/libs/qmlpuppetcommunication/commands/completecomponentcommand.h index 82955e8ca84..aaa5814844e 100644 --- a/src/libs/qmlpuppetcommunication/commands/completecomponentcommand.h +++ b/src/libs/qmlpuppetcommunication/commands/completecomponentcommand.h @@ -3,8 +3,8 @@ #pragma once +#include #include -#include #include namespace QmlDesigner { @@ -16,12 +16,12 @@ class CompleteComponentCommand public: CompleteComponentCommand(); - explicit CompleteComponentCommand(const QVector &container); + explicit CompleteComponentCommand(const QList &container); - const QVector instances() const; + const QList instances() const; private: - QVector m_instanceVector; + QList m_instanceVector; }; QDataStream &operator<<(QDataStream &out, const CompleteComponentCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/componentcompletedcommand.cpp b/src/libs/qmlpuppetcommunication/commands/componentcompletedcommand.cpp index 725e6d72f82..313ece9cf4a 100644 --- a/src/libs/qmlpuppetcommunication/commands/componentcompletedcommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/componentcompletedcommand.cpp @@ -12,12 +12,12 @@ namespace QmlDesigner { ComponentCompletedCommand::ComponentCompletedCommand() = default; -ComponentCompletedCommand::ComponentCompletedCommand(const QVector &container) +ComponentCompletedCommand::ComponentCompletedCommand(const QList &container) : m_instanceVector(container) { } -QVector ComponentCompletedCommand::instances() const +QList ComponentCompletedCommand::instances() const { return m_instanceVector; } diff --git a/src/libs/qmlpuppetcommunication/commands/componentcompletedcommand.h b/src/libs/qmlpuppetcommunication/commands/componentcompletedcommand.h index a0baee93a67..e612e6c2cb3 100644 --- a/src/libs/qmlpuppetcommunication/commands/componentcompletedcommand.h +++ b/src/libs/qmlpuppetcommunication/commands/componentcompletedcommand.h @@ -2,8 +2,9 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once + +#include #include -#include #include namespace QmlDesigner { @@ -15,14 +16,14 @@ class ComponentCompletedCommand public: ComponentCompletedCommand(); - explicit ComponentCompletedCommand(const QVector &container); + explicit ComponentCompletedCommand(const QList &container); - QVector instances() const; + QList instances() const; void sort(); private: - QVector m_instanceVector; + QList m_instanceVector; }; QDataStream &operator<<(QDataStream &out, const ComponentCompletedCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/createinstancescommand.cpp b/src/libs/qmlpuppetcommunication/commands/createinstancescommand.cpp index af18a2df00f..043b493489d 100644 --- a/src/libs/qmlpuppetcommunication/commands/createinstancescommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/createinstancescommand.cpp @@ -10,12 +10,12 @@ namespace QmlDesigner { CreateInstancesCommand::CreateInstancesCommand() = default; -CreateInstancesCommand::CreateInstancesCommand(const QVector &container) +CreateInstancesCommand::CreateInstancesCommand(const QList &container) : m_instanceVector(container) { } -QVector CreateInstancesCommand::instances() const +QList CreateInstancesCommand::instances() const { return m_instanceVector; } diff --git a/src/libs/qmlpuppetcommunication/commands/createinstancescommand.h b/src/libs/qmlpuppetcommunication/commands/createinstancescommand.h index de056244452..110bdc9eb28 100644 --- a/src/libs/qmlpuppetcommunication/commands/createinstancescommand.h +++ b/src/libs/qmlpuppetcommunication/commands/createinstancescommand.h @@ -3,8 +3,8 @@ #pragma once +#include #include -#include #include "instancecontainer.h" @@ -16,12 +16,12 @@ class CreateInstancesCommand public: CreateInstancesCommand(); - explicit CreateInstancesCommand(const QVector &container); + explicit CreateInstancesCommand(const QList &container); - QVector instances() const; + QList instances() const; private: - QVector m_instanceVector; + QList m_instanceVector; }; QDataStream &operator<<(QDataStream &out, const CreateInstancesCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/createscenecommand.h b/src/libs/qmlpuppetcommunication/commands/createscenecommand.h index 80456169db5..5f6b7836b49 100644 --- a/src/libs/qmlpuppetcommunication/commands/createscenecommand.h +++ b/src/libs/qmlpuppetcommunication/commands/createscenecommand.h @@ -3,12 +3,11 @@ #pragma once +#include +#include +#include #include #include -#include -#include -#include -#include #include "instancecontainer.h" #include "reparentcontainer.h" @@ -24,14 +23,14 @@ class CreateSceneCommand { public: CreateSceneCommand() = default; - explicit CreateSceneCommand(const QVector &instanceContainer, - const QVector &reparentContainer, - const QVector &idVector, - const QVector &valueChangeVector, - const QVector &bindingChangeVector, - const QVector &auxiliaryChangeVector, - const QVector &importVector, - const QVector &mockupTypeVector, + explicit CreateSceneCommand(const QList &instanceContainer, + const QList &reparentContainer, + const QList &idVector, + const QList &valueChangeVector, + const QList &bindingChangeVector, + const QList &auxiliaryChangeVector, + const QList &importVector, + const QList &mockupTypeVector, const QUrl &fileUrl, const QUrl &resourceUrl, const QHash &edit3dToolStates, @@ -91,14 +90,14 @@ public: } public: - QVector instances; - QVector reparentInstances; - QVector ids; - QVector valueChanges; - QVector bindingChanges; - QVector auxiliaryChanges; - QVector imports; - QVector mockupTypes; + QList instances; + QList reparentInstances; + QList ids; + QList valueChanges; + QList bindingChanges; + QList auxiliaryChanges; + QList imports; + QList mockupTypes; QUrl fileUrl; QUrl resourceUrl; QHash edit3dToolStates; diff --git a/src/libs/qmlpuppetcommunication/commands/debugoutputcommand.cpp b/src/libs/qmlpuppetcommunication/commands/debugoutputcommand.cpp index e10bce7cff7..b4124088373 100644 --- a/src/libs/qmlpuppetcommunication/commands/debugoutputcommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/debugoutputcommand.cpp @@ -9,7 +9,7 @@ namespace QmlDesigner { DebugOutputCommand::DebugOutputCommand() = default; -DebugOutputCommand::DebugOutputCommand(const QString &text, DebugOutputCommand::Type type, const QVector &instanceIds) +DebugOutputCommand::DebugOutputCommand(const QString &text, DebugOutputCommand::Type type, const QList &instanceIds) : m_instanceIds(instanceIds) , m_text(text) , m_type(type) @@ -26,7 +26,7 @@ QString DebugOutputCommand::text() const return m_text; } -QVector DebugOutputCommand::instanceIds() const +QList DebugOutputCommand::instanceIds() const { return m_instanceIds; } diff --git a/src/libs/qmlpuppetcommunication/commands/debugoutputcommand.h b/src/libs/qmlpuppetcommunication/commands/debugoutputcommand.h index 7818ce629be..05e0d240995 100644 --- a/src/libs/qmlpuppetcommunication/commands/debugoutputcommand.h +++ b/src/libs/qmlpuppetcommunication/commands/debugoutputcommand.h @@ -3,10 +3,10 @@ #pragma once +#include +#include #include #include -#include -#include namespace QmlDesigner { @@ -24,14 +24,14 @@ public: }; DebugOutputCommand(); - explicit DebugOutputCommand(const QString &text, Type type, const QVector &instanceIds); + explicit DebugOutputCommand(const QString &text, Type type, const QList &instanceIds); qint32 type() const; QString text() const; - QVector instanceIds() const; + QList instanceIds() const; private: - QVector m_instanceIds; + QList m_instanceIds; QString m_text; quint32 m_type; }; diff --git a/src/libs/qmlpuppetcommunication/commands/informationchangedcommand.cpp b/src/libs/qmlpuppetcommunication/commands/informationchangedcommand.cpp index 80dda76b23b..5cf4f9fc52b 100644 --- a/src/libs/qmlpuppetcommunication/commands/informationchangedcommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/informationchangedcommand.cpp @@ -6,20 +6,18 @@ #include #include -#include "propertyvaluecontainer.h" - #include namespace QmlDesigner { InformationChangedCommand::InformationChangedCommand() = default; -InformationChangedCommand::InformationChangedCommand(const QVector &informationVector) +InformationChangedCommand::InformationChangedCommand(const QList &informationVector) : m_informationVector(informationVector) { } -QVector InformationChangedCommand::informations() const +QList InformationChangedCommand::informations() const { return m_informationVector; } diff --git a/src/libs/qmlpuppetcommunication/commands/informationchangedcommand.h b/src/libs/qmlpuppetcommunication/commands/informationchangedcommand.h index 3181f185f34..c2dfcaa6381 100644 --- a/src/libs/qmlpuppetcommunication/commands/informationchangedcommand.h +++ b/src/libs/qmlpuppetcommunication/commands/informationchangedcommand.h @@ -3,8 +3,8 @@ #pragma once +#include #include -#include #include "informationcontainer.h" @@ -17,14 +17,14 @@ class InformationChangedCommand public: InformationChangedCommand(); - explicit InformationChangedCommand(const QVector &informationVector); + explicit InformationChangedCommand(const QList &informationVector); - QVector informations() const; + QList informations() const; void sort(); private: - QVector m_informationVector; + QList m_informationVector; }; QDataStream &operator<<(QDataStream &out, const InformationChangedCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/pixmapchangedcommand.cpp b/src/libs/qmlpuppetcommunication/commands/pixmapchangedcommand.cpp index 18f35043c11..57073722160 100644 --- a/src/libs/qmlpuppetcommunication/commands/pixmapchangedcommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/pixmapchangedcommand.cpp @@ -13,12 +13,12 @@ namespace QmlDesigner { PixmapChangedCommand::PixmapChangedCommand() = default; -PixmapChangedCommand::PixmapChangedCommand(const QVector &imageVector) +PixmapChangedCommand::PixmapChangedCommand(const QList &imageVector) : m_imageVector(imageVector) { } -QVector PixmapChangedCommand::images() const +QList PixmapChangedCommand::images() const { return m_imageVector; } diff --git a/src/libs/qmlpuppetcommunication/commands/pixmapchangedcommand.h b/src/libs/qmlpuppetcommunication/commands/pixmapchangedcommand.h index 72247f0c57c..d66289f1394 100644 --- a/src/libs/qmlpuppetcommunication/commands/pixmapchangedcommand.h +++ b/src/libs/qmlpuppetcommunication/commands/pixmapchangedcommand.h @@ -15,14 +15,14 @@ class PixmapChangedCommand public: PixmapChangedCommand(); - explicit PixmapChangedCommand(const QVector &imageVector); + explicit PixmapChangedCommand(const QList &imageVector); - QVector images() const; + QList images() const; void sort(); private: - QVector m_imageVector; + QList m_imageVector; }; QDataStream &operator<<(QDataStream &out, const PixmapChangedCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h b/src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h index a8f37a81e53..44d68f9ed29 100644 --- a/src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h +++ b/src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h @@ -16,7 +16,7 @@ public: Edit3DToolState, Render3DView, ActiveSceneChanged, - ActiveSplitChanged, + ActiveViewportChanged, RenderModelNodePreviewImage, Import3DPreviewIcon, Import3DPreviewImage, diff --git a/src/libs/qmlpuppetcommunication/commands/removeinstancescommand.cpp b/src/libs/qmlpuppetcommunication/commands/removeinstancescommand.cpp index f2289a3b543..7d89261096f 100644 --- a/src/libs/qmlpuppetcommunication/commands/removeinstancescommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/removeinstancescommand.cpp @@ -10,12 +10,12 @@ namespace QmlDesigner { RemoveInstancesCommand::RemoveInstancesCommand() = default; -RemoveInstancesCommand::RemoveInstancesCommand(const QVector &idVector) +RemoveInstancesCommand::RemoveInstancesCommand(const QList &idVector) : m_instanceIdVector(idVector) { } -const QVector RemoveInstancesCommand::instanceIds() const +const QList RemoveInstancesCommand::instanceIds() const { return m_instanceIdVector; } diff --git a/src/libs/qmlpuppetcommunication/commands/removeinstancescommand.h b/src/libs/qmlpuppetcommunication/commands/removeinstancescommand.h index 7c03a8970df..54766ba8d97 100644 --- a/src/libs/qmlpuppetcommunication/commands/removeinstancescommand.h +++ b/src/libs/qmlpuppetcommunication/commands/removeinstancescommand.h @@ -3,11 +3,9 @@ #pragma once -#include -#include #include - -#include "instancecontainer.h" +#include +#include namespace QmlDesigner { @@ -18,12 +16,12 @@ class RemoveInstancesCommand public: RemoveInstancesCommand(); - explicit RemoveInstancesCommand(const QVector &idVector); + explicit RemoveInstancesCommand(const QList &idVector); - const QVector instanceIds() const; + const QList instanceIds() const; private: - QVector m_instanceIdVector; + QList m_instanceIdVector; }; QDataStream &operator<<(QDataStream &out, const RemoveInstancesCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/removepropertiescommand.cpp b/src/libs/qmlpuppetcommunication/commands/removepropertiescommand.cpp index b15e441c298..a19ee12c9f0 100644 --- a/src/libs/qmlpuppetcommunication/commands/removepropertiescommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/removepropertiescommand.cpp @@ -9,12 +9,12 @@ namespace QmlDesigner { RemovePropertiesCommand::RemovePropertiesCommand() = default; -RemovePropertiesCommand::RemovePropertiesCommand(const QVector &properties) +RemovePropertiesCommand::RemovePropertiesCommand(const QList &properties) : m_properties(properties) { } -const QVector RemovePropertiesCommand::properties() const +const QList RemovePropertiesCommand::properties() const { return m_properties; } diff --git a/src/libs/qmlpuppetcommunication/commands/removepropertiescommand.h b/src/libs/qmlpuppetcommunication/commands/removepropertiescommand.h index c5f32b4a5dd..f25e0947a58 100644 --- a/src/libs/qmlpuppetcommunication/commands/removepropertiescommand.h +++ b/src/libs/qmlpuppetcommunication/commands/removepropertiescommand.h @@ -3,8 +3,8 @@ #pragma once +#include #include -#include #include "propertyabstractcontainer.h" @@ -17,12 +17,12 @@ class RemovePropertiesCommand public: RemovePropertiesCommand(); - explicit RemovePropertiesCommand(const QVector &properties); + explicit RemovePropertiesCommand(const QList &properties); - const QVector properties() const; + const QList properties() const; private: - QVector m_properties; + QList m_properties; }; QDataStream &operator<<(QDataStream &out, const RemovePropertiesCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/removesharedmemorycommand.cpp b/src/libs/qmlpuppetcommunication/commands/removesharedmemorycommand.cpp index 65e16b4752f..d7dd1eba26c 100644 --- a/src/libs/qmlpuppetcommunication/commands/removesharedmemorycommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/removesharedmemorycommand.cpp @@ -10,7 +10,7 @@ namespace QmlDesigner { RemoveSharedMemoryCommand::RemoveSharedMemoryCommand() = default; -RemoveSharedMemoryCommand::RemoveSharedMemoryCommand(const QString &typeName, const QVector &keyNumberVector) +RemoveSharedMemoryCommand::RemoveSharedMemoryCommand(const QString &typeName, const QList &keyNumberVector) : m_typeName(typeName), m_keyNumberVector(keyNumberVector) { @@ -21,7 +21,7 @@ QString RemoveSharedMemoryCommand::typeName() const return m_typeName; } -QVector RemoveSharedMemoryCommand::keyNumbers() const +QList RemoveSharedMemoryCommand::keyNumbers() const { return m_keyNumberVector; } diff --git a/src/libs/qmlpuppetcommunication/commands/removesharedmemorycommand.h b/src/libs/qmlpuppetcommunication/commands/removesharedmemorycommand.h index 60081608b3b..4d601234706 100644 --- a/src/libs/qmlpuppetcommunication/commands/removesharedmemorycommand.h +++ b/src/libs/qmlpuppetcommunication/commands/removesharedmemorycommand.h @@ -3,9 +3,9 @@ #pragma once +#include #include #include -#include namespace QmlDesigner { @@ -16,14 +16,14 @@ class RemoveSharedMemoryCommand public: RemoveSharedMemoryCommand(); - explicit RemoveSharedMemoryCommand(const QString &typeName, const QVector &keyNumberVector); + explicit RemoveSharedMemoryCommand(const QString &typeName, const QList &keyNumberVector); QString typeName() const; - QVector keyNumbers() const; + QList keyNumbers() const; private: QString m_typeName; - QVector m_keyNumberVector; + QList m_keyNumberVector; }; QDataStream &operator<<(QDataStream &out, const RemoveSharedMemoryCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/reparentinstancescommand.cpp b/src/libs/qmlpuppetcommunication/commands/reparentinstancescommand.cpp index 3de6b4f90c5..b260cd4e711 100644 --- a/src/libs/qmlpuppetcommunication/commands/reparentinstancescommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/reparentinstancescommand.cpp @@ -10,12 +10,12 @@ namespace QmlDesigner { ReparentInstancesCommand::ReparentInstancesCommand() = default; -ReparentInstancesCommand::ReparentInstancesCommand(const QVector &container) +ReparentInstancesCommand::ReparentInstancesCommand(const QList &container) : m_reparentInstanceVector(container) { } -const QVector ReparentInstancesCommand::reparentInstances() const +const QList ReparentInstancesCommand::reparentInstances() const { return m_reparentInstanceVector; } diff --git a/src/libs/qmlpuppetcommunication/commands/reparentinstancescommand.h b/src/libs/qmlpuppetcommunication/commands/reparentinstancescommand.h index 4a5e55c4839..46c74e20917 100644 --- a/src/libs/qmlpuppetcommunication/commands/reparentinstancescommand.h +++ b/src/libs/qmlpuppetcommunication/commands/reparentinstancescommand.h @@ -3,8 +3,8 @@ #pragma once +#include #include -#include #include "reparentcontainer.h" @@ -17,12 +17,12 @@ class ReparentInstancesCommand public: ReparentInstancesCommand(); - explicit ReparentInstancesCommand(const QVector &container); + explicit ReparentInstancesCommand(const QList &container); - const QVector reparentInstances() const; + const QList reparentInstances() const; private: - QVector m_reparentInstanceVector; + QList m_reparentInstanceVector; }; QDataStream &operator<<(QDataStream &out, const ReparentInstancesCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/statepreviewimagechangedcommand.cpp b/src/libs/qmlpuppetcommunication/commands/statepreviewimagechangedcommand.cpp index 5d7f6e85663..75ce5c00b7a 100644 --- a/src/libs/qmlpuppetcommunication/commands/statepreviewimagechangedcommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/statepreviewimagechangedcommand.cpp @@ -11,12 +11,12 @@ namespace QmlDesigner { StatePreviewImageChangedCommand::StatePreviewImageChangedCommand() = default; -StatePreviewImageChangedCommand::StatePreviewImageChangedCommand(const QVector &imageVector) +StatePreviewImageChangedCommand::StatePreviewImageChangedCommand(const QList &imageVector) : m_previewVector(imageVector) { } -QVector StatePreviewImageChangedCommand::previews()const +QList StatePreviewImageChangedCommand::previews() const { return m_previewVector; } diff --git a/src/libs/qmlpuppetcommunication/commands/statepreviewimagechangedcommand.h b/src/libs/qmlpuppetcommunication/commands/statepreviewimagechangedcommand.h index 81c55890110..3ffb0771840 100644 --- a/src/libs/qmlpuppetcommunication/commands/statepreviewimagechangedcommand.h +++ b/src/libs/qmlpuppetcommunication/commands/statepreviewimagechangedcommand.h @@ -16,14 +16,14 @@ class StatePreviewImageChangedCommand public: StatePreviewImageChangedCommand(); - explicit StatePreviewImageChangedCommand(const QVector &imageVector); + explicit StatePreviewImageChangedCommand(const QList &imageVector); - QVector previews() const; + QList previews() const; void sort(); private: - QVector m_previewVector; + QList m_previewVector; }; QDataStream &operator<<(QDataStream &out, const StatePreviewImageChangedCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/synchronizecommand.h b/src/libs/qmlpuppetcommunication/commands/synchronizecommand.h index e0c2c3a0397..da9f1ed6408 100644 --- a/src/libs/qmlpuppetcommunication/commands/synchronizecommand.h +++ b/src/libs/qmlpuppetcommunication/commands/synchronizecommand.h @@ -4,8 +4,8 @@ #pragma once #include +#include #include -#include namespace QmlDesigner { diff --git a/src/libs/qmlpuppetcommunication/commands/tokencommand.cpp b/src/libs/qmlpuppetcommunication/commands/tokencommand.cpp index 7d9aa45ad03..23892105ae0 100644 --- a/src/libs/qmlpuppetcommunication/commands/tokencommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/tokencommand.cpp @@ -15,7 +15,7 @@ TokenCommand::TokenCommand() { } -TokenCommand::TokenCommand(const QString &tokenName, qint32 tokenNumber, const QVector &instanceIdVector) +TokenCommand::TokenCommand(const QString &tokenName, qint32 tokenNumber, const QList &instanceIdVector) : m_tokenName(tokenName), m_tokenNumber(tokenNumber), m_instanceIdVector(instanceIdVector) @@ -32,7 +32,7 @@ qint32 TokenCommand::tokenNumber() const return m_tokenNumber; } -QVector TokenCommand::instances() const +QList TokenCommand::instances() const { return m_instanceIdVector; } diff --git a/src/libs/qmlpuppetcommunication/commands/tokencommand.h b/src/libs/qmlpuppetcommunication/commands/tokencommand.h index 1d249c20e9d..690c630fcb1 100644 --- a/src/libs/qmlpuppetcommunication/commands/tokencommand.h +++ b/src/libs/qmlpuppetcommunication/commands/tokencommand.h @@ -3,11 +3,10 @@ #pragma once - -#include -#include -#include #include +#include +#include +#include namespace QmlDesigner { @@ -18,18 +17,18 @@ class TokenCommand public: TokenCommand(); - explicit TokenCommand(const QString &tokenName, qint32 tokenNumber, const QVector &instances); + explicit TokenCommand(const QString &tokenName, qint32 tokenNumber, const QList &instances); QString tokenName() const; qint32 tokenNumber() const; - QVector instances() const; + QList instances() const; void sort(); private: QString m_tokenName; qint32 m_tokenNumber; - QVector m_instanceIdVector; + QList m_instanceIdVector; }; QDataStream &operator<<(QDataStream &out, const TokenCommand &command); diff --git a/src/libs/qmlpuppetcommunication/commands/valueschangedcommand.cpp b/src/libs/qmlpuppetcommunication/commands/valueschangedcommand.cpp index e36b7bb3519..e702efe6041 100644 --- a/src/libs/qmlpuppetcommunication/commands/valueschangedcommand.cpp +++ b/src/libs/qmlpuppetcommunication/commands/valueschangedcommand.cpp @@ -24,13 +24,13 @@ ValuesChangedCommand::ValuesChangedCommand() { } -ValuesChangedCommand::ValuesChangedCommand(const QVector &valueChangeVector) +ValuesChangedCommand::ValuesChangedCommand(const QList &valueChangeVector) : m_valueChangeVector (valueChangeVector), m_keyNumber(0) { } -const QVector ValuesChangedCommand::valueChanges() const +const QList ValuesChangedCommand::valueChanges() const { return m_valueChangeVector; } @@ -40,7 +40,7 @@ quint32 ValuesChangedCommand::keyNumber() const return m_keyNumber; } -void ValuesChangedCommand::removeSharedMemorys(const QVector &keyNumberVector) +void ValuesChangedCommand::removeSharedMemorys(const QList &keyNumberVector) { for (qint32 keyNumber : keyNumberVector) { SharedMemory *sharedMemory = globalSharedMemoryContainer()->take(keyNumber); @@ -75,7 +75,7 @@ QDataStream &operator<<(QDataStream &out, const ValuesChangedCommand &command) { static const bool dontUseSharedMemory = qEnvironmentVariableIsSet("DESIGNER_DONT_USE_SHARED_MEMORY"); - QVector propertyValueContainer = command.valueChanges(); + QList propertyValueContainer = command.valueChanges(); if (command.transactionOption != ValuesChangedCommand::TransactionOption::None) { PropertyValueContainer optionContainer(command.transactionOption); @@ -114,7 +114,7 @@ QDataStream &operator<<(QDataStream &out, const ValuesChangedCommand &command) return out; } -void readSharedMemory(qint32 key, QVector *valueChangeVector) +void readSharedMemory(qint32 key, QList *valueChangeVector) { SharedMemory sharedMemory(QString(valueKeyTemplateString).arg(key)); bool canAttach = sharedMemory.attach(QSharedMemory::ReadOnly); @@ -135,7 +135,7 @@ QDataStream &operator>>(QDataStream &in, ValuesChangedCommand &command) { in >> command.m_keyNumber; - QVector valueChangeVector; + QList valueChangeVector; if (command.keyNumber() > 0) readSharedMemory(command.keyNumber(), &valueChangeVector); diff --git a/src/libs/qmlpuppetcommunication/commands/valueschangedcommand.h b/src/libs/qmlpuppetcommunication/commands/valueschangedcommand.h index 43ce0b7d59c..17e3e3be56c 100644 --- a/src/libs/qmlpuppetcommunication/commands/valueschangedcommand.h +++ b/src/libs/qmlpuppetcommunication/commands/valueschangedcommand.h @@ -3,8 +3,8 @@ #pragma once +#include #include -#include #include "propertyvaluecontainer.h" @@ -19,18 +19,18 @@ class ValuesChangedCommand public: enum TransactionOption { Start = 1, End = 2, None = 0 }; ValuesChangedCommand(); - explicit ValuesChangedCommand(const QVector &valueChangeVector); + explicit ValuesChangedCommand(const QList &valueChangeVector); - const QVector valueChanges() const; + const QList valueChanges() const; quint32 keyNumber() const; - static void removeSharedMemorys(const QVector &keyNumberVector); + static void removeSharedMemorys(const QList &keyNumberVector); void sort(); TransactionOption transactionOption = TransactionOption::None; private: - QVector m_valueChangeVector; + QList m_valueChangeVector; mutable quint32 m_keyNumber; }; @@ -51,7 +51,7 @@ class ValuesModifiedCommand : public ValuesChangedCommand public: ValuesModifiedCommand() = default; - explicit ValuesModifiedCommand(const QVector &valueChangeVector) + explicit ValuesModifiedCommand(const QList &valueChangeVector) : ValuesChangedCommand(valueChangeVector) {} }; diff --git a/src/libs/qmlpuppetcommunication/container/idcontainer.h b/src/libs/qmlpuppetcommunication/container/idcontainer.h index 7e6c8260526..025e76fa05a 100644 --- a/src/libs/qmlpuppetcommunication/container/idcontainer.h +++ b/src/libs/qmlpuppetcommunication/container/idcontainer.h @@ -4,10 +4,9 @@ #pragma once #include -#include +#include #include - namespace QmlDesigner { class IdContainer diff --git a/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h b/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h index a05d9681f64..8b25001f83e 100644 --- a/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h +++ b/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h @@ -51,10 +51,11 @@ enum class View3DActionType { ParticlesRestart, ParticlesSeek, SyncEnvBackground, + ViewportPreset, GetNodeAtPos, GetNodeAtMainScenePos, SetBakeLightsView3D, - SplitViewToggle, + ViewportViewToggle, MaterialOverride, ShowWireframe, FlyModeToggle, diff --git a/src/libs/sqlite/sqliteids.h b/src/libs/sqlite/sqliteids.h index 15c42505925..2228f7372aa 100644 --- a/src/libs/sqlite/sqliteids.h +++ b/src/libs/sqlite/sqliteids.h @@ -70,7 +70,7 @@ public: explicit operator std::size_t() const { return static_cast(id); } - InternalIntegerType internalId() const { return id; } + constexpr InternalIntegerType internalId() const { return id; } [[noreturn, deprecated]] InternalIntegerType operator&() const { throw std::exception{}; } diff --git a/src/libs/utils/set_algorithm.h b/src/libs/utils/set_algorithm.h index 4c595717050..629ca17a1dd 100644 --- a/src/libs/utils/set_algorithm.h +++ b/src/libs/utils/set_algorithm.h @@ -241,6 +241,71 @@ struct set_greedy_difference_functor inline constexpr set_greedy_difference_functor set_greedy_difference{}; +struct set_difference_functor +{ + template Sentinel1, + std::input_iterator Iterator2, + std::sentinel_for Sentinel2, + std::invocable &> Callable, + typename Comp = std::ranges::less, + typename Projection1 = std::identity, + typename Projection2 = std::identity> + requires callmergeable + constexpr void operator()(Iterator1 first1, + Sentinel1 last1, + Iterator2 first2, + Sentinel2 last2, + Callable &&callable, + Comp comp = {}, + Projection1 proj1 = {}, + Projection2 proj2 = {}) const + { + while (first1 != last1 && first2 != last2) { + if (std::invoke(comp, std::invoke(proj1, *first1), std::invoke(proj2, *first2))) { + std::invoke(callable, *first1); + ++first1; + } else if (std::invoke(comp, std::invoke(proj2, *first2), std::invoke(proj1, *first1))) { + ++first2; + } else { + ++first1; + ++first2; + } + } + + while (first1 != last1) { + std::invoke(callable, *first1); + ++first1; + } + } + + template &> Callable, + typename Comp = std::ranges::less, + typename Projection1 = std::identity, + typename Projection2 = std::identity> + requires callmergeable, std::ranges::iterator_t, Comp, Projection1, Projection2> + constexpr void operator()(Range1 &&range1, + Range2 &&range2, + Callable &&callable, + Comp comp = {}, + Projection1 proj1 = {}, + Projection2 proj2 = {}) const + { + (*this)(std::ranges::begin(range1), + std::ranges::end(range1), + std::ranges::begin(range2), + std::ranges::end(range2), + std::forward(callable), + std::move(comp), + std::move(proj1), + std::move(proj2)); + } +}; + +inline constexpr set_difference_functor set_difference{}; + struct set_has_common_element_functor { template(size, false, false); std::char_traits::copy(shortString, string, size); } else { @@ -181,11 +181,20 @@ struct alignas(16) StringDataLayout constexpr bool isReadOnlyReference() const noexcept { return control.isReadOnlyReference(); } - char *data() noexcept { return Q_LIKELY(isShortString()) ? shortString : reference.pointer; } + char *data() noexcept + { + if (isShortString()) [[likely]] + return shortString; + else + return reference.pointer; + } const char *data() const noexcept { - return Q_LIKELY(isShortString()) ? shortString : reference.pointer; + if (isShortString()) [[likely]] + return shortString; + else + return reference.pointer; } void setPointer(char *p) noexcept { reference.pointer = p; } @@ -266,7 +275,7 @@ struct alignas(16) StringDataLayout(size)} , capacity_{static_cast(std::max(capacity, MaximumShortStringDataAreaSize))} { - if (Q_LIKELY(capacity <= shortStringCapacity())) { + if (capacity <= shortStringCapacity()) [[likely]] { std::char_traits::copy(buffer, string, size); pointer = buffer; } else { diff --git a/src/libs/utils/span.h b/src/libs/utils/span.h index f2c545940b7..3b716ae892e 100644 --- a/src/libs/utils/span.h +++ b/src/libs/utils/span.h @@ -6,9 +6,8 @@ #include // The (Apple) Clang implementation of span is incomplete until LLVM 15 / Xcode 14.3 / macOS 13 -#if __cplusplus >= 202002L \ - && !(defined(__apple_build_version__) && __apple_build_version__ < 14030022) -#include +#ifdef __cpp_lib_span_initializer_list +# include namespace Utils { using std::as_bytes; @@ -27,9 +26,9 @@ QT_WARNING_PUSH // disable automatic usage of std::span in span-lite // since we make that decision ourselves at the top of this header -#define span_CONFIG_SELECT_SPAN span_SPAN_NONSTD - -#include <3rdparty/span/span.hpp> +# define span_CONFIG_SELECT_SPAN span_SPAN_NONSTD +# define span_FEATURE_WITH_INITIALIZER_LIST_P2447 1 +# include <3rdparty/span/span.hpp> namespace Utils { using namespace nonstd; diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt index 86cebca8fd8..65645263f1c 100644 --- a/src/plugins/CMakeLists.txt +++ b/src/plugins/CMakeLists.txt @@ -113,6 +113,7 @@ if (WITH_QMLDESIGNER) endif() add_subdirectory(qmldesigner ${qmldesigner_builddir}) add_subdirectory(qmldesignerlite) + add_subdirectory(extrapropertyeditormanager) add_subdirectory(effectcomposer) add_subdirectory(studiowelcome) add_subdirectory(insight) diff --git a/src/plugins/effectcomposer/compositionnode.cpp b/src/plugins/effectcomposer/compositionnode.cpp index 1792952c3c9..ba3dd38cfcd 100644 --- a/src/plugins/effectcomposer/compositionnode.cpp +++ b/src/plugins/effectcomposer/compositionnode.cpp @@ -210,7 +210,7 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c for (const QJsonValueConstRef &prop : jsonProps) { const auto uniform = new Uniform(effectName, prop.toObject(), qenPath); m_uniformsModel.addUniform(uniform); - g_propertyData.insert(uniform->name(), uniform->value()); + g_propertyData()->insert(uniform->name(), uniform->value()); if (uniform->type() == Uniform::Type::Define) { // Changing defines requires rebaking the shaders connect(uniform, &Uniform::uniformValueChanged, this, &CompositionNode::rebakeRequested); @@ -335,7 +335,7 @@ void CompositionNode::openCodeEditor() void CompositionNode::addUniform(const QVariantMap &data) { const auto uniform = new Uniform({}, QJsonObject::fromVariantMap(data), {}); - g_propertyData.insert(uniform->name(), uniform->value()); + g_propertyData()->insert(uniform->name(), uniform->value()); m_uniformsModel.addUniform(uniform); updateAreUniformsInUse(true); } @@ -346,7 +346,7 @@ void CompositionNode::updateUniform(int index, const QVariantMap &data) const auto uniform = new Uniform({}, QJsonObject::fromVariantMap(data), {}); - g_propertyData.insert(uniform->name(), uniform->value()); + g_propertyData()->insert(uniform->name(), uniform->value()); m_uniformsModel.updateUniform(index, uniform); updateAreUniformsInUse(true); } diff --git a/src/plugins/effectcomposer/effectcomposermodel.cpp b/src/plugins/effectcomposer/effectcomposermodel.cpp index 17d6afd9a13..4d3d0595a05 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.cpp +++ b/src/plugins/effectcomposer/effectcomposermodel.cpp @@ -2547,8 +2547,8 @@ QString EffectComposerModel::getQmlComponentString(bool localFiles) s += l3 + "id: blurHelper\n"; s += l3 + "source: rootItem.source\n"; int blurMax = 32; - if (g_propertyData.contains("BLUR_HELPER_MAX_LEVEL")) - blurMax = g_propertyData["BLUR_HELPER_MAX_LEVEL"].toInt(); + if (g_propertyData()->contains("BLUR_HELPER_MAX_LEVEL")) + blurMax = g_propertyData()->value("BLUR_HELPER_MAX_LEVEL").toInt(); s += l3 + QString("property int blurMax: %1\n").arg(blurMax); s += l3 + "property real blurMultiplier: rootItem.blurMultiplier\n"; s += l2 + "}\n"; diff --git a/src/plugins/effectcomposer/effectcomposernodesmodel.cpp b/src/plugins/effectcomposer/effectcomposernodesmodel.cpp index 6b0eea8f615..18733a776a9 100644 --- a/src/plugins/effectcomposer/effectcomposernodesmodel.cpp +++ b/src/plugins/effectcomposer/effectcomposernodesmodel.cpp @@ -52,7 +52,7 @@ void EffectComposerNodesModel::loadModel() auto nodesPath = Utils::FilePath::fromString(EffectUtils::nodesSourcesPath()); if (!nodesPath.exists()) { - qWarning() << __FUNCTION__ << "Effects not found."; + qWarning() << __FUNCTION__ << "Effects not found in: " << nodesPath; return; } diff --git a/src/plugins/effectcomposer/effectcomposeruniformsmodel.cpp b/src/plugins/effectcomposer/effectcomposeruniformsmodel.cpp index 1a48cee7b99..47b37f08cf0 100644 --- a/src/plugins/effectcomposer/effectcomposeruniformsmodel.cpp +++ b/src/plugins/effectcomposer/effectcomposeruniformsmodel.cpp @@ -68,10 +68,10 @@ bool EffectComposerUniformsModel::setData(const QModelIndex &index, const QVaria updatedValue = QUrl::fromLocalFile(path).toString(); uniform->setValue(updatedValue); - g_propertyData.insert(uniform->name(), updatedValue); + g_propertyData()->insert(uniform->name(), updatedValue); } else { uniform->setValue(value); - g_propertyData.insert(uniform->name(), value); + g_propertyData()->insert(uniform->name(), value); } emit dataChanged(index, index, {role}); diff --git a/src/plugins/effectcomposer/effectcomposerwidget.cpp b/src/plugins/effectcomposer/effectcomposerwidget.cpp index 412eaa843d0..4e7041f735a 100644 --- a/src/plugins/effectcomposer/effectcomposerwidget.cpp +++ b/src/plugins/effectcomposer/effectcomposerwidget.cpp @@ -100,11 +100,12 @@ EffectComposerWidget::EffectComposerWidget(EffectComposerView *view) QmlDesigner::QmlDesignerPlugin::trackWidgetFocusTime(this, QmlDesigner::Constants::EVENT_EFFECTCOMPOSER_TIME); - m_quickWidget->rootContext()->setContextProperty("g_propertyData", &g_propertyData); + qmlRegisterSingletonInstance( + "EffectComposerPropertyData", 1, 0, "GlobalPropertyData", 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")); + g_propertyData()->insert("blur_vs_path", QString(blurPath + "bluritems.vert.qsb")); + g_propertyData()->insert("blur_fs_path", QString(blurPath + "bluritems.frag.qsb")); auto map = m_quickWidget->registerPropertyMap("EffectComposerBackend"); map->setProperties({{"effectComposerNodesModel", QVariant::fromValue(effectComposerNodesModel().data())}, diff --git a/src/plugins/effectcomposer/propertyhandler.cpp b/src/plugins/effectcomposer/propertyhandler.cpp index b440410a0bf..44e04ce810f 100644 --- a/src/plugins/effectcomposer/propertyhandler.cpp +++ b/src/plugins/effectcomposer/propertyhandler.cpp @@ -3,8 +3,14 @@ #include "propertyhandler.h" +#include + namespace EffectComposer { -QQmlPropertyMap g_propertyData; +Q_GLOBAL_STATIC(QQmlPropertyMap, globalEffectComposerPropertyData) +QQmlPropertyMap *g_propertyData() +{ + return globalEffectComposerPropertyData(); +} } diff --git a/src/plugins/effectcomposer/propertyhandler.h b/src/plugins/effectcomposer/propertyhandler.h index 96bc49f78e0..5d685a1f948 100644 --- a/src/plugins/effectcomposer/propertyhandler.h +++ b/src/plugins/effectcomposer/propertyhandler.h @@ -3,13 +3,16 @@ #pragma once -#include +#include + +QT_BEGIN_NAMESPACE +class QQmlPropertyMap; +QT_END_NAMESPACE namespace EffectComposer { // This will be used for binding dynamic properties // changes between C++ and QML. -extern QQmlPropertyMap g_propertyData; - +QQmlPropertyMap *g_propertyData(); } diff --git a/src/plugins/effectcomposer/uniform.cpp b/src/plugins/effectcomposer/uniform.cpp index 149db291a70..aad3fc571b4 100644 --- a/src/plugins/effectcomposer/uniform.cpp +++ b/src/plugins/effectcomposer/uniform.cpp @@ -47,7 +47,7 @@ Uniform::Uniform(const QString &effectName, const QJsonObject &propObj, const QS m_enableMipmap = getBoolValue(propObj.value("enableMipmap"), false); // Update the mipmap property QString mipmapProperty = mipmapPropertyName(m_name); - g_propertyData[mipmapProperty] = m_enableMipmap; + g_propertyData()->insert(mipmapProperty, m_enableMipmap); } QString controlType = propObj.value("controlType").toString(); diff --git a/src/plugins/extrapropertyeditormanager/CMakeLists.txt b/src/plugins/extrapropertyeditormanager/CMakeLists.txt new file mode 100644 index 00000000000..5959fb20e2a --- /dev/null +++ b/src/plugins/extrapropertyeditormanager/CMakeLists.txt @@ -0,0 +1,12 @@ +add_qtc_plugin(ExtraPropertyEditorManager + CONDITION TARGET QtCreator::QmlDesigner AND NOT QTC_USE_QML_DESIGNER_LITE + PLUGIN_DEPENDS + QtCreator::QmlDesigner + DEPENDS + Qt::Core Qt::CorePrivate QtCreator::Utils + SOURCES + extrapropertyeditormanagerplugin.cpp + extrapropertyeditormanagerplugin.h + extrapropertyeditorview.cpp + extrapropertyeditorview.h +) diff --git a/src/plugins/extrapropertyeditormanager/ExtraPropertyEditorManager.json.in b/src/plugins/extrapropertyeditormanager/ExtraPropertyEditorManager.json.in new file mode 100644 index 00000000000..a6caddc919b --- /dev/null +++ b/src/plugins/extrapropertyeditormanager/ExtraPropertyEditorManager.json.in @@ -0,0 +1,19 @@ +{ + "Id" : "extrapropertyeditormanager", + "DisplayName" : "Extra Property Editor Manager", + "Name" : "ExtraPropertyEditorManager", + "Version" : "${IDE_VERSION}", + "CompatVersion" : "${IDE_VERSION_COMPAT}", + "VendorId" : "theqtcompany", + "Vendor" : "The Qt Company Ltd", + "Copyright" : "${IDE_COPYRIGHT}", + "License" : [ "Commercial Usage", + "", + "Licensees holding valid Qt Enterprise licenses may use this plugin in accordance with the Qt Enterprise License Agreement provided with the Software or, alternatively, in accordance with the terms contained in a written agreement between you and The Qt Company." + ], + "Description" : "Plugin for displaying additional instances of property editor.", + "Url" : "https://www.qt.io", + "DocumentationUrl" : "https://doc.qt.io/qtdesignstudio", + "DisabledByDefault": "${NOT_BUILDING_DESIGNSTUDIO}", + ${IDE_PLUGIN_DEPENDENCIES} +} diff --git a/src/plugins/extrapropertyeditormanager/extrapropertyeditormanagerplugin.cpp b/src/plugins/extrapropertyeditormanager/extrapropertyeditormanagerplugin.cpp new file mode 100644 index 00000000000..591f6d61477 --- /dev/null +++ b/src/plugins/extrapropertyeditormanager/extrapropertyeditormanagerplugin.cpp @@ -0,0 +1,23 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "extrapropertyeditormanagerplugin.h" +#include "extrapropertyeditorview.h" + +#include +#include + +namespace ExtraPropertyEditorManager { + +bool ExtraPropertyEditorManagerPlugin::delayedInitialize() +{ + auto *designerPlugin = QmlDesigner::QmlDesignerPlugin::instance(); + auto &viewManager = designerPlugin->viewManager(); + viewManager.registerView(std::make_unique( + designerPlugin->imageCache(), + QmlDesigner::QmlDesignerPlugin::externalDependenciesForPluginInitializationOnly())); + + return true; +} + +} // namespace ExtraPropertyEditorManager diff --git a/src/plugins/extrapropertyeditormanager/extrapropertyeditormanagerplugin.h b/src/plugins/extrapropertyeditormanager/extrapropertyeditormanagerplugin.h new file mode 100644 index 00000000000..bf04454bdc2 --- /dev/null +++ b/src/plugins/extrapropertyeditormanager/extrapropertyeditormanagerplugin.h @@ -0,0 +1,17 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include + +namespace ExtraPropertyEditorManager { + +class ExtraPropertyEditorManagerPlugin final : public ExtensionSystem::IPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE + "ExtraPropertyEditorManager.json") + public: + bool delayedInitialize() override; +}; + +} // namespace ExtraPropertyEditorManager diff --git a/src/plugins/extrapropertyeditormanager/extrapropertyeditorview.cpp b/src/plugins/extrapropertyeditormanager/extrapropertyeditorview.cpp new file mode 100644 index 00000000000..31744775811 --- /dev/null +++ b/src/plugins/extrapropertyeditormanager/extrapropertyeditorview.cpp @@ -0,0 +1,19 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "extrapropertyeditorview.h" + +#include + +namespace QmlDesigner { + +ExtraPropertyEditorView::ExtraPropertyEditorView(class AsynchronousImageCache &imageCache, + ExternalDependenciesInterface &externalDependencies) + : AbstractView{externalDependencies} + , m_imageCache{imageCache} + , m_externalDependencies{externalDependencies} +{} + +ExtraPropertyEditorView::~ExtraPropertyEditorView() {}; + +} // namespace QmlDesigner diff --git a/src/plugins/extrapropertyeditormanager/extrapropertyeditorview.h b/src/plugins/extrapropertyeditormanager/extrapropertyeditorview.h new file mode 100644 index 00000000000..4a09c2cbdeb --- /dev/null +++ b/src/plugins/extrapropertyeditormanager/extrapropertyeditorview.h @@ -0,0 +1,23 @@ +// Copyright (C) 2025 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 ExtraPropertyEditorView : public AbstractView +{ + Q_OBJECT +public: + ExtraPropertyEditorView(class AsynchronousImageCache &imageCache, + ExternalDependenciesInterface &externalDependencies); + ~ExtraPropertyEditorView() override; + +private: + AsynchronousImageCache &m_imageCache; + ExternalDependenciesInterface &m_externalDependencies; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp index 10ce71a3351..e15fb8f00b3 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.cpp @@ -25,6 +25,7 @@ #include #include #include +#include namespace QmlDesigner { @@ -80,10 +81,13 @@ void AssetsLibraryView::customNotification(const AbstractView * /*view*/, const QList & /*nodeList*/, const QList & /*data*/) { - if (identifier == "delete_selected_assets") + if (identifier == "delete_selected_assets") { m_widget->deleteSelectedAssets(); - else if (identifier == "asset_import_finished") + } else if (identifier == "asset_import_finished") { + // TODO: This custom notification should be removed once QDS-15163 is fixed and + // exportedTypeNamesChanged notification is reliable m_3dImportsSyncTimer.start(); + } } void AssetsLibraryView::modelAttached(Model *model) @@ -104,6 +108,13 @@ void AssetsLibraryView::modelAboutToBeDetached(Model *model) m_3dImportsSyncTimer.stop(); } +void AssetsLibraryView::exportedTypeNamesChanged(const ExportedTypeNames &added, + const ExportedTypeNames &removed) +{ + if (Utils3D::hasImported3dType(this, added, removed)) + m_3dImportsSyncTimer.start(); +} + void AssetsLibraryView::setResourcePath(const QString &resourcePath) { if (resourcePath == m_lastResourcePath) @@ -148,10 +159,6 @@ void AssetsLibraryView::sync3dImports() if (!model()) return; - // TODO: Once project storage supports notifications for new and removed types, - // sync3dImports() should be called in that case as well. - // Also, custom notification "asset_import_finished" should not be necessary in that case. - // Sync generated 3d imports to .q3d files in project content const GeneratedComponentUtils &compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils(); diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h index 2dc8f47cdf4..4eafc0f68cb 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibraryview.h @@ -33,6 +33,9 @@ public: // AbstractView void modelAttached(Model *model) override; void modelAboutToBeDetached(Model *model) override; + void exportedTypeNamesChanged(const ExportedTypeNames &added, + const ExportedTypeNames &removed) override; + void setResourcePath(const QString &resourcePath); private: diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp index bb98db869c4..3b5461581c3 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp @@ -177,10 +177,8 @@ bool isType(const TypeName &first, const TypeName &second, const Tuple &...types bool compareTypes(const NodeMetaInfo &sourceType, const NodeMetaInfo &targetType) { #ifdef QDS_USE_PROJECTSTORAGE - return targetType.isVariant() || sourceType.isVariant() || targetType == sourceType - || (targetType.isNumber() && sourceType.isNumber()) - || (targetType.isColor() && sourceType.isColor()) - || (targetType.isString() && sourceType.isString()); + return targetType.isVariant() || sourceType.isVariant() + || (targetType.isNumber() && sourceType.isNumber()) || sourceType.isBasedOn(targetType); #else const TypeName source = sourceType.simplifiedTypeName(); const TypeName target = targetType.simplifiedTypeName(); @@ -207,8 +205,9 @@ void BindingEditor::prepareBindings() for (const auto &objnode : allNodes) { BindingEditorDialog::BindingOption binding; - for (const auto &property : objnode.metaInfo().properties()) { - const auto &propertyType = property.propertyType(); + for (const auto &property : + MetaInfoUtils::addInflatedValueAndReadOnlyProperties(objnode.metaInfo().properties())) { + const auto &propertyType = property.property.propertyType(); if (compareTypes(m_backendValueType, propertyType)) { binding.properties.append(QString::fromUtf8(property.name())); @@ -260,8 +259,12 @@ void BindingEditor::prepareBindings() } if (!binding.properties.isEmpty()) { - binding.item = metaInfo.displayName(); - bindings.append(binding); + for (auto &exportedType : + metaInfo.exportedTypeNamesForSourceId(model->fileUrlSourceId())) { + binding.item = exportedType.name.toQString(); + bindings.append(binding); + break; + } } } } diff --git a/src/plugins/qmldesigner/components/componentcore/bundleimporter.cpp b/src/plugins/qmldesigner/components/componentcore/bundleimporter.cpp index aa55f8b4608..55bb7dfa616 100644 --- a/src/plugins/qmldesigner/components/componentcore/bundleimporter.cpp +++ b/src/plugins/qmldesigner/components/componentcore/bundleimporter.cpp @@ -12,9 +12,7 @@ #include #include -#ifndef QDS_USE_PROJECTSTORAGE #include -#endif #include #include @@ -54,9 +52,9 @@ QString BundleImporter::importComponent(const QString &bundleDir, if (!bundleImportPath.exists() && !bundleImportPath.createDir()) return QStringLiteral("Failed to create bundle import folder: '%1'").arg(bundleImportPath.toUrlishString()); + bool doReset = false; #ifndef QDS_USE_PROJECTSTORAGE bool doScan = false; - bool doReset = false; #endif FilePath qmldirPath = bundleImportPath.pathAppended("qmldir"); QString qmldirContent = QString::fromUtf8(qmldirPath.fileContents().value_or(QByteArray())); @@ -81,9 +79,7 @@ QString BundleImporter::importComponent(const QString &bundleDir, qmldirContent.append(qmlFile); qmldirContent.append('\n'); qmldirPath.writeFileContents(qmldirContent.toUtf8()); -#ifndef QDS_USE_PROJECTSTORAGE doReset = true; -#endif } QStringList allFiles; @@ -129,6 +125,7 @@ QString BundleImporter::importComponent(const QString &bundleDir, Import import = Import::createLibraryImport(module, "1.0"); #ifdef QDS_USE_PROJECTSTORAGE model->changeImports({import}, {}); + m_pendingFullReset = doReset; #else if (doScan) data.pathToScan = bundleImportPath; @@ -163,6 +160,7 @@ void BundleImporter::handleImportTimer() auto handleFailure = [this] { m_importTimer.stop(); m_importTimerCount = 0; + m_pendingFullReset = false; // Emit dummy finished signals for all pending types const QList pendingTypes = m_pendingImports.keys(); @@ -198,6 +196,17 @@ void BundleImporter::handleImportTimer() } } + if (keys.size() > 0) + return; // Do the code model reset/cleanup on next timer tick + + if (m_pendingFullReset) { + m_pendingFullReset = false; + // Force code model reset to notice changes to existing module + auto modelManager = QmlJS::ModelManagerInterface::instance(); + if (modelManager) + modelManager->resetCodeModel(); + } + if (m_pendingImports.isEmpty()) { m_bundleId.clear(); m_importTimer.stop(); diff --git a/src/plugins/qmldesigner/components/componentcore/bundleimporter.h b/src/plugins/qmldesigner/components/componentcore/bundleimporter.h index 3c743bfe55b..9a346225894 100644 --- a/src/plugins/qmldesigner/components/componentcore/bundleimporter.h +++ b/src/plugins/qmldesigner/components/componentcore/bundleimporter.h @@ -56,6 +56,7 @@ private: bool isImport = true; // false = unimport TypeName type; }; + bool m_pendingFullReset = false; // Reset old QMLJS code model (it's used for code view warnings) #else struct ImportData { diff --git a/src/plugins/qmldesigner/components/componentcore/propertycomponentgenerator.cpp b/src/plugins/qmldesigner/components/componentcore/propertycomponentgenerator.cpp index 1b9e7c409e2..9c349f3dec6 100644 --- a/src/plugins/qmldesigner/components/componentcore/propertycomponentgenerator.cpp +++ b/src/plugins/qmldesigner/components/componentcore/propertycomponentgenerator.cpp @@ -128,7 +128,7 @@ QString PropertyComponentGenerator::generateComplexComponentText(Utils::SmallStr static QString templateText = QStringLiteral( R"xy( Section { - caption: %1 - %2 + caption: "%1 - %2" anchors.left: parent.left anchors.right: parent.right leftPadding: 8 diff --git a/src/plugins/qmldesigner/components/componentcore/utils3d.cpp b/src/plugins/qmldesigner/components/componentcore/utils3d.cpp index 3121ed9cdfb..11e3a9a4e21 100644 --- a/src/plugins/qmldesigner/components/componentcore/utils3d.cpp +++ b/src/plugins/qmldesigner/components/componentcore/utils3d.cpp @@ -566,5 +566,24 @@ void openNodeInPropertyEditor(const ModelNode &node) node.view()->emitCustomNotification("force_editing_node", {node}); // To PropertyEditor } +bool hasImported3dType(AbstractView *view, + const AbstractView::ExportedTypeNames &added, + const AbstractView::ExportedTypeNames &removed) +{ + QTC_ASSERT(view && view->model(), return false); + + using Storage::Info::ExportedTypeName; + + const QByteArray import3dPrefix = QmlDesignerPlugin::instance()->documentManager() + .generatedComponentUtils().import3dTypePrefix().toUtf8(); + + auto generatedModuleIds = view->model()->moduleIdsStartsWith(import3dPrefix, + Storage::ModuleKind::QmlLibrary); + std::ranges::sort(generatedModuleIds); + + return Utils::set_has_common_element(added, generatedModuleIds, {}, &ExportedTypeName::moduleId) + || Utils::set_has_common_element(removed, generatedModuleIds, {}, &ExportedTypeName::moduleId); +} + } // namespace Utils3D } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/utils3d.h b/src/plugins/qmldesigner/components/componentcore/utils3d.h index 2bc17366207..c1cacb9ac46 100644 --- a/src/plugins/qmldesigner/components/componentcore/utils3d.h +++ b/src/plugins/qmldesigner/components/componentcore/utils3d.h @@ -52,7 +52,9 @@ void duplicateMaterial(AbstractView *view, const ModelNode &material); bool addQuick3DImportAndView3D(AbstractView *view, bool suppressWarningDialog = false); void assignMaterialTo3dModel(AbstractView *view, const ModelNode &modelNode, const ModelNode &materialNode = {}); - +bool hasImported3dType(AbstractView *view, + const AbstractView::ExportedTypeNames &added, + const AbstractView::ExportedTypeNames &removed); } // namespace Utils3D } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp index 379ff6d423c..63fea75f1ae 100644 --- a/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp +++ b/src/plugins/qmldesigner/components/componentcore/viewmanager.cpp @@ -438,36 +438,19 @@ void ViewManager::setNodeInstanceViewTarget(ProjectExplorer::Target *target) d->nodeInstanceView.setTarget(target); } -QList ViewManager::widgetInfos() const +void ViewManager::initializeWidgetInfos() { - QList widgetInfoList; - -#ifndef QTC_USE_QML_DESIGNER_LITE - widgetInfoList.append(d->edit3DView.widgetInfo()); -#endif - widgetInfoList.append(d->formEditorView.widgetInfo()); - widgetInfoList.append(d->textEditorView.widgetInfo()); - widgetInfoList.append(d->assetsLibraryView.widgetInfo()); - widgetInfoList.append(d->itemLibraryView.widgetInfo()); - widgetInfoList.append(d->navigatorView.widgetInfo()); - widgetInfoList.append(d->propertyEditorView.widgetInfo()); -#ifndef QTC_USE_QML_DESIGNER_LITE - widgetInfoList.append(d->materialBrowserView.widgetInfo()); -#endif - widgetInfoList.append(d->statesEditorView.widgetInfo()); - - if (checkEnterpriseLicense()) - widgetInfoList.append(d->contentLibraryView.widgetInfo()); - - if (d->debugView.hasWidget()) - widgetInfoList.append(d->debugView.widgetInfo()); - - for (auto &view : d->additionalViews) { - if (view->hasWidget()) - widgetInfoList.append(view->widgetInfo()); + for (const auto &view : views()) { + if (view->hasWidget()) { + view->setWidgetRegistration(this); + view->registerWidgetInfo(); + } } +} - return widgetInfoList; +QList ViewManager::widgetInfos() +{ + return m_widgetInfo; } void ViewManager::disableWidgets() @@ -599,4 +582,14 @@ void ViewManager::addView(std::unique_ptr &&view) registerViewAction(*d->additionalViews.back()); } +void ViewManager::registerWidgetInfo(WidgetInfo info) +{ + m_widgetInfo.append(info); +} + +void ViewManager::deregisterWidgetInfo(WidgetInfo info) +{ + m_widgetInfo.removeIf(Utils::equal(&WidgetInfo::uniqueId, info.uniqueId)); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/viewmanager.h b/src/plugins/qmldesigner/components/componentcore/viewmanager.h index 1ca067f213d..76d214981c7 100644 --- a/src/plugins/qmldesigner/components/componentcore/viewmanager.h +++ b/src/plugins/qmldesigner/components/componentcore/viewmanager.h @@ -5,10 +5,11 @@ #include -#include - #include +#include +#include + #include #include @@ -31,13 +32,12 @@ namespace Internal { class DesignModeWidget; } class ViewManagerData; -class QMLDESIGNERCOMPONENTS_EXPORT ViewManager +class QMLDESIGNERCOMPONENTS_EXPORT ViewManager : private WidgetRegistrationInterface { public: ViewManager(class AsynchronousImageCache &imageCache, class ExternalDependenciesInterface &externalDependencies); ~ViewManager(); - void attachRewriterView(); void detachRewriterView(); @@ -50,7 +50,6 @@ public: void setComponentNode(const ModelNode &componentNode); void setComponentViewToMaster(); void setNodeInstanceViewTarget(ProjectExplorer::Target *target); - void resetPropertyEditorView(); void registerFormEditorTool(std::unique_ptr &&tool); @@ -61,8 +60,7 @@ public: addView(std::move(view)); return notOwningPointer; } - - QList widgetInfos() const; + QList widgetInfos(); void disableWidgets(); void enableWidgets(); @@ -99,6 +97,9 @@ public: void hideView(AbstractView &view); void showView(AbstractView &view); + void registerWidgetInfo(WidgetInfo info) override; + void deregisterWidgetInfo(WidgetInfo info) override; + void initializeWidgetInfos(); private: // functions Q_DISABLE_COPY(ViewManager) @@ -123,10 +124,12 @@ private: // functions void registerViewActions(); void registerViewAction(AbstractView &view); void enableView(AbstractView &view); + void disableView(AbstractView &view); private: // variables std::unique_ptr d; + QList m_widgetInfo; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp index 47b06781123..20661cfa50b 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.cpp @@ -9,6 +9,7 @@ #include "contentlibrarytexture.h" #include "contentlibrarywidget.h" +#include #include #include #include @@ -16,6 +17,7 @@ #include #include +#include #include #include @@ -28,10 +30,18 @@ namespace QmlDesigner { ContentLibraryUserModel::ContentLibraryUserModel(ContentLibraryWidget *parent) : QAbstractListModel(parent) , m_widget(parent) + , m_fileWatcher(Utils::makeUniqueObjectPtr(parent)) { createCategories(); + + connect(m_fileWatcher.get(), &Utils::FileSystemWatcher::directoryChanged, + this, [this] (const auto &dirPath) { + reloadTextureCategory(dirPath); + }); } +ContentLibraryUserModel::~ContentLibraryUserModel() = default; + int ContentLibraryUserModel::rowCount(const QModelIndex &) const { return m_userCategories.size(); @@ -44,17 +54,22 @@ QVariant ContentLibraryUserModel::data(const QModelIndex &index, int role) const UserCategory *currCat = m_userCategories.at(index.row()); - if (role == TitleRole) + switch (role) { + case TitleRole: return currCat->title(); - if (role == ItemsRole) + case BundlePathRole: + return currCat->bundlePath().toVariant(); + + case ItemsRole: return QVariant::fromValue(currCat->items()); - if (role == NoMatchRole) + case NoMatchRole: return currCat->noMatch(); - if (role == EmptyRole) + case EmptyRole: return currCat->isEmpty(); + } return {}; } @@ -76,6 +91,71 @@ void ContentLibraryUserModel::createCategories() compUtils.user3DBundleId()}; m_userCategories << catMaterial << catTexture << cat3D; + + loadCustomCategories(userBundlePath); +} + +void ContentLibraryUserModel::loadCustomCategories(const Utils::FilePath &userBundlePath) +{ + auto jsonFilePath = userBundlePath.pathAppended(Constants::CUSTOM_BUNDLES_JSON_FILENAME); + if (!jsonFilePath.exists()) { + const QString jsonContent = QStringLiteral(R"({ "version": "%1", "items": {}})") + .arg(CUSTOM_BUNDLES_JSON_FILE_VERSION); + Utils::Result res = jsonFilePath.writeFileContents(jsonContent.toLatin1()); + QTC_ASSERT_RESULT(res, return); + } + + Utils::Result jsonContents = jsonFilePath.fileContents(); + QTC_ASSERT_RESULT(jsonContents, return); + + QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonContents.value()); + QTC_ASSERT(!jsonDoc.isNull(), return); + + m_customCatsRootObj = jsonDoc.object(); + m_customCatsObj = m_customCatsRootObj.value("items").toObject(); + + for (auto it = m_customCatsObj.constBegin(); it != m_customCatsObj.constEnd(); ++it) { + auto dirPath = Utils::FilePath::fromString(it.key()); + if (!dirPath.exists()) + continue; + + addBundleDir(dirPath); + } +} + +bool ContentLibraryUserModel::bundleDirExists(const QString &dirPath) const +{ + return m_customCatsObj.contains(dirPath); +} + +void ContentLibraryUserModel::addBundleDir(const Utils::FilePath &dirPath) +{ + QTC_ASSERT(!dirPath.isEmpty(), return); + + // TODO: detect if a bundle exists in the dir, determine its type, and create a matching category. + // For now we consider a custom folder as a texture bundle + + auto newCat = new UserTextureCategory{dirPath.fileName(), dirPath}; + newCat->loadBundle(); + + beginInsertRows({}, m_userCategories.size(), m_userCategories.size()); + m_userCategories << newCat; + endInsertRows(); + + m_fileWatcher->addDirectory(dirPath, Utils::FileSystemWatcher::WatchAllChanges); + + // add the folder to custom bundles json file if it is missing + const QString dirPathStr = dirPath.toFSPathString(); + if (!m_customCatsObj.contains(dirPathStr)) { + m_customCatsObj.insert(dirPathStr, QJsonObject{}); + + m_customCatsRootObj["items"] = m_customCatsObj; + + auto userBundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User"); + auto jsonFilePath = userBundlePath.pathAppended(Constants::CUSTOM_BUNDLES_JSON_FILENAME); + auto result = jsonFilePath.writeFileContents(QJsonDocument(m_customCatsRootObj).toJson()); + QTC_CHECK_RESULT(result); + } } void ContentLibraryUserModel::addItem(const QString &bundleId, const QString &name, @@ -102,22 +182,36 @@ void ContentLibraryUserModel::refreshSection(const QString &bundleId) updateIsEmpty(); } -void ContentLibraryUserModel::addTextures(const Utils::FilePaths &paths) +void ContentLibraryUserModel::addTextures(const Utils::FilePaths &paths, const Utils::FilePath &bundlePath) { - auto texCat = qobject_cast(m_userCategories[TexturesSectionIdx]); + int catIdx = bundlePathToIndex(bundlePath); + UserTextureCategory *texCat = qobject_cast(m_userCategories.at(catIdx)); QTC_ASSERT(texCat, return); texCat->addItems(paths); - emit dataChanged(index(TexturesSectionIdx), index(TexturesSectionIdx), {ItemsRole, EmptyRole}); + emit dataChanged(index(catIdx), index(catIdx), {ItemsRole, EmptyRole}); updateIsEmpty(); } -void ContentLibraryUserModel::removeTextures(const QStringList &fileNames) +void ContentLibraryUserModel::reloadTextureCategory(const Utils::FilePath &dirPath) +{ + int catIdx = bundlePathToIndex(dirPath); + UserTextureCategory *texCat = qobject_cast(m_userCategories.at(catIdx)); + QTC_ASSERT(texCat, return); + + const Utils::FilePaths &paths = dirPath.dirEntries({Asset::supportedImageSuffixes(), QDir::Files}); + + texCat->clearItems(); + addTextures(paths, dirPath); +} + +void ContentLibraryUserModel::removeTextures(const QStringList &fileNames, const Utils::FilePath &bundlePath) { // note: this method doesn't refresh the model after textures removal - auto texCat = qobject_cast(m_userCategories[TexturesSectionIdx]); + int catIdx = bundlePathToIndex(bundlePath); + UserTextureCategory *texCat = qobject_cast(m_userCategories.at(catIdx)); QTC_ASSERT(texCat, return); const QObjectList items = texCat->items(); @@ -137,13 +231,28 @@ void ContentLibraryUserModel::removeTexture(ContentLibraryTexture *tex, bool ref Utils::FilePath::fromString(tex->iconPath()).removeFile(); // remove from model - m_userCategories[TexturesSectionIdx]->removeItem(tex); + UserTextureCategory *itemCat = qobject_cast(tex->parent()); + QTC_ASSERT(itemCat, return); + itemCat->removeItem(tex); // update model if (refresh) { - emit dataChanged(index(TexturesSectionIdx), index(TexturesSectionIdx)); + int catIdx = bundlePathToIndex(itemCat->bundlePath()); + emit dataChanged(index(catIdx), index(catIdx)); updateIsEmpty(); } + + const QString bundlePathStr = itemCat->bundlePath().toFSPathString(); + if (m_customCatsObj.contains(bundlePathStr)) { + m_customCatsObj.remove(bundlePathStr); + + m_customCatsRootObj["items"] = m_customCatsObj; + + auto userBundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User"); + auto jsonFilePath = userBundlePath.pathAppended(Constants::CUSTOM_BUNDLES_JSON_FILENAME); + auto result = jsonFilePath.writeFileContents(QJsonDocument(m_customCatsRootObj).toJson()); + QTC_CHECK_RESULT(result); + } } void ContentLibraryUserModel::removeFromContentLib(QObject *item) @@ -154,6 +263,30 @@ void ContentLibraryUserModel::removeFromContentLib(QObject *item) removeItem(castedItem); } +void ContentLibraryUserModel::removeBundleDir(int catIdx) +{ + auto texCat = qobject_cast(m_userCategories.at(catIdx)); + QTC_ASSERT(texCat, return); + + QString dirPath = texCat->bundlePath().toFSPathString(); + + // remove from json + QTC_ASSERT(m_customCatsObj.contains(dirPath), return); + m_customCatsObj.remove(dirPath); + m_customCatsRootObj["items"] = m_customCatsObj; + + auto userBundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User"); + auto jsonFilePath = userBundlePath.pathAppended(Constants::CUSTOM_BUNDLES_JSON_FILENAME); + auto result = jsonFilePath.writeFileContents(QJsonDocument(m_customCatsRootObj).toJson()); + QTC_ASSERT_RESULT(result, return); + + // remove from model + beginRemoveRows({}, catIdx, catIdx); + delete texCat; + m_userCategories.removeAt(catIdx); + endRemoveRows(); +} + void ContentLibraryUserModel::removeItemByName(const QString &qmlFileName, const QString &bundleId) { ContentLibraryItem *itemToRemove = nullptr; @@ -239,10 +372,27 @@ ContentLibraryUserModel::SectionIndex ContentLibraryUserModel::bundleIdToSection return {}; } +int ContentLibraryUserModel::bundlePathToIndex(const QString &bundlePath) const +{ + return bundlePathToIndex(Utils::FilePath::fromString(bundlePath)); +} + +int ContentLibraryUserModel::bundlePathToIndex(const Utils::FilePath &bundlePath) const +{ + for (int i = 0; i < m_userCategories.size(); ++i) { + if (m_userCategories.at(i)->bundlePath() == bundlePath) + return i; + } + + qWarning() << __FUNCTION__ << "Invalid bundlePath:" << bundlePath; + return -1; +} + QHash ContentLibraryUserModel::roleNames() const { static const QHash roles { {TitleRole, "categoryTitle"}, + {BundlePathRole, "categoryBundlePath"}, {EmptyRole, "categoryEmpty"}, {ItemsRole, "categoryItems"}, {NoMatchRole, "categoryNoMatch"} diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.h index 172bad093a3..72b849aeba3 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.h +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryusermodel.h @@ -6,10 +6,15 @@ #include "usercategory.h" #include +#include #include #include +namespace Utils { +class FileSystemWatcher; +} + QT_FORWARD_DECLARE_CLASS(QUrl) namespace QmlDesigner { @@ -28,6 +33,7 @@ class ContentLibraryUserModel : public QAbstractListModel public: ContentLibraryUserModel(ContentLibraryWidget *parent = nullptr); + ~ContentLibraryUserModel(); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; @@ -50,8 +56,9 @@ public: void addItem(const QString &bundleId, const QString &name, const QString &qml,const QUrl &icon, const QStringList &files); void refreshSection(const QString &bundleId); - void addTextures(const Utils::FilePaths &paths); - void removeTextures(const QStringList &fileNames); + void addTextures(const Utils::FilePaths &paths, const Utils::FilePath &bundlePath); + void reloadTextureCategory(const Utils::FilePath &dirPath); + void removeTextures(const QStringList &fileNames, const Utils::FilePath &bundlePath); void removeItemByName(const QString &qmlFileName, const QString &bundleId); @@ -59,12 +66,15 @@ public: QJsonObject &bundleObjectRef(const QString &bundleId); void loadBundles(bool force = false); + void addBundleDir(const Utils::FilePath &dirPath); + bool bundleDirExists(const QString &dirPath) const; Q_INVOKABLE void applyToSelected(QmlDesigner::ContentLibraryItem *mat, bool add = false); Q_INVOKABLE void addToProject(ContentLibraryItem *item); Q_INVOKABLE void removeFromProject(QObject *item); Q_INVOKABLE void removeTexture(QmlDesigner::ContentLibraryTexture *tex, bool refresh = true); Q_INVOKABLE void removeFromContentLib(QObject *item); + Q_INVOKABLE void removeBundleDir(int catIdx); signals: void hasRequiredQuick3DImportChanged(); @@ -79,14 +89,20 @@ private: EffectsSectionIdx }; void createCategories(); + void loadCustomCategories(const Utils::FilePath &userBundlePath); void loadMaterialBundle(); void load3DBundle(); void loadTextureBundle(); void removeItem(ContentLibraryItem *item); SectionIndex bundleIdToSectionIndex(const QString &bundleId) const; + int bundlePathToIndex(const QString &bundlePath) const; + int bundlePathToIndex(const Utils::FilePath &bundlePath) const; ContentLibraryWidget *m_widget = nullptr; + QJsonObject m_customCatsRootObj; + QJsonObject m_customCatsObj; QString m_searchText; + Utils::UniqueObjectPtr m_fileWatcher; QList m_userCategories; @@ -95,7 +111,9 @@ private: int m_quick3dMajorVersion = -1; int m_quick3dMinorVersion = -1; - enum Roles { TitleRole = Qt::UserRole + 1, ItemsRole, EmptyRole, NoMatchRole }; + enum Roles { TitleRole = Qt::UserRole + 1, BundlePathRole, ItemsRole, EmptyRole, NoMatchRole }; + + static constexpr char CUSTOM_BUNDLES_JSON_FILE_VERSION[] = "1.0"; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp index 7f41ebb4e83..ac0d4c7a507 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -71,6 +72,12 @@ bool ContentLibraryView::hasWidget() const return true; } +void ContentLibraryView::registerWidgetInfo() +{ + if (QmlDesigner::checkEnterpriseLicense()) + AbstractView::registerWidgetInfo(); +} + WidgetInfo ContentLibraryView::widgetInfo() { if (m_widget.isNull()) { @@ -95,7 +102,7 @@ WidgetInfo ContentLibraryView::widgetInfo() }); connect(m_widget, &ContentLibraryWidget::acceptTextureDrop, this, - [this](const QString &internalId) { + [this](const QString &internalId, const QString &bundlePath) { ModelNode texNode = QmlDesignerPlugin::instance()->viewManager() .view()->modelNodeForInternalId(internalId.toInt()); auto [qmlString, depAssets] = m_bundleHelper->modelNodeToQmlString(texNode); @@ -108,11 +115,11 @@ WidgetInfo ContentLibraryView::widgetInfo() paths.append(path); } - addLibAssets(paths); + addLibAssets(paths, bundlePath); }); connect(m_widget, &ContentLibraryWidget::acceptTexturesDrop, this, - [this](const QList &urls) { + [this](const QList &urls, const QString &bundlePath) { QStringList paths; for (const QUrl &url : urls) { @@ -121,7 +128,7 @@ WidgetInfo ContentLibraryView::widgetInfo() if (Asset(path).isValidTextureSource()) paths.append(path); } - addLibAssets(paths); + addLibAssets(paths, bundlePath); }); connect(m_widget, &ContentLibraryWidget::acceptMaterialDrop, this, @@ -217,6 +224,8 @@ void ContentLibraryView::connectImporter() ModelNode newNode = createModelNode( typeName, -1, -1, {{"x", pos.x()}, {"y", pos.y()}, {"z", pos.z()}}); m_bundleItemTarget.defaultNodeListProperty().reparentHere(newNode); + newNode.setIdWithoutRefactoring(model()->generateNewId( + newNode.simplifiedTypeName(), "node")); clearSelectedModelNodes(); selectModelNode(newNode); }); @@ -573,14 +582,16 @@ void ContentLibraryView::applyBundleMaterialToDropTarget(const ModelNode &bundle } #endif -void ContentLibraryView::addLibAssets(const QStringList &paths) +void ContentLibraryView::addLibAssets(const QStringList &paths, const QString &bundlePath) { - auto bundlePath = Utils::FilePath::fromString(Paths::bundlesPathSetting() + "/User/textures"); + auto fullBundlePath = Utils::FilePath::fromString(bundlePath.isEmpty() + ? Paths::bundlesPathSetting() + "/User/textures" + : bundlePath); Utils::FilePaths sourcePathsToAdd; Utils::FilePaths targetPathsToAdd; QStringList fileNamesToRemove; - const QStringList existingAssetsFileNames = Utils::transform(bundlePath.dirEntries(QDir::Files), + const QStringList existingAssetsFileNames = Utils::transform(fullBundlePath.dirEntries(QDir::Files), &Utils::FilePath::fileName); for (const QString &path : paths) { @@ -602,21 +613,13 @@ void ContentLibraryView::addLibAssets(const QStringList &paths) } // remove the to-be-overwritten resources from target bundle path - m_widget->userModel()->removeTextures(fileNamesToRemove); + m_widget->userModel()->removeTextures(fileNamesToRemove, fullBundlePath); // copy resources to target bundle path for (const Utils::FilePath &sourcePath : sourcePathsToAdd) { - Utils::FilePath targetPath = bundlePath.pathAppended(sourcePath.fileName()); + Utils::FilePath targetPath = fullBundlePath.pathAppended(sourcePath.fileName()); Asset asset{sourcePath.toFSPathString()}; - // save icon - QString iconSavePath = bundlePath.pathAppended("icons/" + sourcePath.baseName() + ".png") - .toFSPathString(); - QPixmap icon = asset.pixmap({120, 120}); - bool iconSaved = icon.save(iconSavePath); - if (!iconSaved) - qWarning() << __FUNCTION__ << "icon save failed"; - // save asset auto result = sourcePath.copyFile(targetPath); QTC_ASSERT_RESULT(result,); @@ -624,7 +627,7 @@ void ContentLibraryView::addLibAssets(const QStringList &paths) targetPathsToAdd.append(targetPath); } - m_widget->userModel()->addTextures(targetPathsToAdd); + m_widget->userModel()->addTextures(targetPathsToAdd, fullBundlePath); } // TODO: combine this method with BundleHelper::exportComponent() diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h index e8cc641c32c..4fd21fafc2a 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h @@ -37,7 +37,7 @@ public: bool hasWidget() const override; WidgetInfo widgetInfo() override; - + void registerWidgetInfo() override; // AbstractView void modelAttached(Model *model) override; void modelAboutToBeDetached(Model *model) override; @@ -63,7 +63,7 @@ private: bool isItemBundle(const QString &bundleId) const; void active3DSceneChanged(qint32 sceneId); void updateBundlesQuick3DVersion(); - void addLibAssets(const QStringList &paths); + void addLibAssets(const QStringList &paths, const QString &bundlePath = {}); void addLib3DComponent(const ModelNode &node); void addLibItem(const ModelNode &node, const QPixmap &iconPixmap = {}); void importBundleToContentLib(); diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp index 2fdf606e03f..d46a2fa338f 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp @@ -13,7 +13,6 @@ #include "contentlibraryusermodel.h" #include -#include #include #include #include @@ -27,6 +26,9 @@ #include #include +#include +#include + #include #include #include @@ -135,6 +137,7 @@ ContentLibraryWidget::ContentLibraryWidget() , m_environmentsModel(new ContentLibraryTexturesModel("Environments", this)) , m_effectsModel(new ContentLibraryEffectsModel(this)) , m_userModel(new ContentLibraryUserModel(this)) + , m_showInGraphicalShellMsg(Core::FileUtils::msgGraphicalShellAction()) { qmlRegisterType("WebFetcher", 1, 0, "FileDownloader"); qmlRegisterType("WebFetcher", 1, 0, "FileExtractor"); @@ -190,6 +193,21 @@ ContentLibraryWidget::~ContentLibraryWidget() { } +void ContentLibraryWidget::browseBundleFolder() +{ + DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); + QTC_ASSERT(document, return); + const QString currentDir = document->fileName().parentDir().toUrlishString(); + + QString dir = QFileDialog::getExistingDirectory(Core::ICore::dialogParent(), + tr("Choose Directory"), + currentDir, + QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); + + if (!dir.isEmpty() && !m_userModel->bundleDirExists(dir)) + m_userModel->addBundleDir(Utils::FilePath::fromString(dir)); +} + void ContentLibraryWidget::createImporter() { m_importer = new BundleImporter(); @@ -931,4 +949,9 @@ void ContentLibraryWidget::setHasModelSelection(bool b) emit hasModelSelectionChanged(); } +void ContentLibraryWidget::showInGraphicalShell(const QString &path) +{ + Core::FileUtils::showInGraphicalShell(Utils::FilePath::fromString(path)); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h index 76a4c24b8b8..7509b94d361 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h @@ -42,6 +42,7 @@ class ContentLibraryWidget : public QFrame Q_PROPERTY(bool isQt6Project READ isQt6Project NOTIFY isQt6ProjectChanged) Q_PROPERTY(bool importerRunning READ importerRunning WRITE setImporterRunning NOTIFY importerRunningChanged) Q_PROPERTY(bool hasModelSelection READ hasModelSelection NOTIFY hasModelSelectionChanged) + Q_PROPERTY(QString showInGraphicalShellMsg MEMBER m_showInGraphicalShellMsg CONSTANT) // Needed for a workaround for a bug where after drag-n-dropping an item, the ScrollView scrolls to a random position Q_PROPERTY(bool isDragging MEMBER m_isDragging NOTIFY isDraggingChanged) @@ -104,6 +105,8 @@ public: Q_INVOKABLE bool has3DNode(const QByteArray &data) const; Q_INVOKABLE bool hasTexture(const QString &format, const QVariant &data) const; Q_INVOKABLE void addQtQuick3D(); + Q_INVOKABLE void browseBundleFolder(); + Q_INVOKABLE void showInGraphicalShell(const QString &path); QSize sizeHint() const override; @@ -127,8 +130,8 @@ signals: void hasModelSelectionChanged(); void importBundle(); void requestTab(int tabIndex); - void acceptTexturesDrop(const QList &urls); - void acceptTextureDrop(const QString &internalId); + void acceptTexturesDrop(const QList &urls, const QString &bundlePath = {}); + void acceptTextureDrop(const QString &internalId, const QString &bundlePath = {}); void acceptMaterialDrop(const QString &internalId); void accept3DDrop(const QByteArray &internalIds); void importQtQuick3D(); @@ -179,6 +182,7 @@ private: bool m_hasModelSelection = false; QString m_textureBundleUrl; QString m_bundlePath; + QString m_showInGraphicalShellMsg; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/usertexturecategory.cpp b/src/plugins/qmldesigner/components/contentlibrary/usertexturecategory.cpp index 22b9cf20aa3..2a88557f180 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/usertexturecategory.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/usertexturecategory.cpp @@ -5,9 +5,11 @@ #include "contentlibrarytexture.h" -#include +#include #include +#include + namespace QmlDesigner { UserTextureCategory::UserTextureCategory(const QString &title, const Utils::FilePath &bundlePath) @@ -27,7 +29,7 @@ void UserTextureCategory::loadBundle(bool force) m_bundlePath.ensureWritableDir(); m_bundlePath.pathAppended("icons").ensureWritableDir(); - addItems(m_bundlePath.dirEntries(QDir::Files)); + addItems(m_bundlePath.dirEntries({Asset::supportedImageSuffixes(), QDir::Files})); m_bundleLoaded = true; } @@ -55,6 +57,14 @@ void UserTextureCategory::addItems(const Utils::FilePaths &paths) QSize imgDims = info.first; qint64 imgFileSize = info.second; + if (!iconFileInfo.exists()) { // generate an icon if one doesn't exist + Asset asset{filePath.toFSPathString()}; + QPixmap icon = asset.pixmap({120, 120}); + bool iconSaved = icon.save(iconFileInfo.filePath()); + if (!iconSaved) + qWarning() << __FUNCTION__ << "icon save failed"; + } + auto tex = new ContentLibraryTexture(this, iconFileInfo, dirPath, suffix, imgDims, imgFileSize); m_items.append(tex); } @@ -63,4 +73,13 @@ void UserTextureCategory::addItems(const Utils::FilePaths &paths) emit itemsChanged(); } +void UserTextureCategory::clearItems() +{ + qDeleteAll(m_items); + m_items.clear(); + + setIsEmpty(true); + emit itemsChanged(); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/contentlibrary/usertexturecategory.h b/src/plugins/qmldesigner/components/contentlibrary/usertexturecategory.h index 511e2ea3f83..8687f322fd3 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/usertexturecategory.h +++ b/src/plugins/qmldesigner/components/contentlibrary/usertexturecategory.h @@ -16,10 +16,11 @@ class UserTextureCategory : public UserCategory public: UserTextureCategory(const QString &title, const Utils::FilePath &bundlePath); - void loadBundle(bool force) override; + void loadBundle(bool force = false) override; void filter(const QString &searchText) override; void addItems(const Utils::FilePaths &paths); + void clearItems(); }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.cpp b/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.cpp index 820ec51e5ad..7b27bbb52d8 100644 --- a/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.cpp +++ b/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.cpp @@ -11,8 +11,7 @@ #include namespace QmlDesigner { -DesignSystemInterface::DesignSystemInterface(DSStore *store) - : m_store(store) +DesignSystemInterface::DesignSystemInterface() { qmlRegisterUncreatableMetaObject( QmlDesigner::staticMetaObject, "QmlDesigner.DesignSystem", 1, 0, "GroupType", ""); @@ -23,6 +22,8 @@ DesignSystemInterface::~DesignSystemInterface() {} void DesignSystemInterface::loadDesignSystem() { + QTC_ASSERT(m_store, return); + m_models.clear(); if (auto err = m_store->load()) @@ -33,6 +34,8 @@ void DesignSystemInterface::loadDesignSystem() CollectionModel *DesignSystemInterface::model(const QString &typeName) { + QTC_ASSERT(m_store, return nullptr); + if (auto collection = m_store->collection(typeName)) return createModel(typeName, collection); @@ -41,17 +44,22 @@ CollectionModel *DesignSystemInterface::model(const QString &typeName) QString DesignSystemInterface::generateCollectionName(const QString &hint) const { + QTC_ASSERT(m_store, return {}); return m_store->uniqueCollectionName(hint); } void DesignSystemInterface::addCollection(const QString &name) { + QTC_ASSERT(m_store, return); + if (m_store->addCollection(name)) emit collectionsChanged(); } void DesignSystemInterface::removeCollection(const QString &name) { + QTC_ASSERT(m_store, return); + if (m_store->collection(name)) { m_models.erase(name); m_store->removeCollection(name); @@ -61,6 +69,8 @@ void DesignSystemInterface::removeCollection(const QString &name) void DesignSystemInterface::renameCollection(const QString &oldName, const QString &newName) { + QTC_ASSERT(m_store, return); + if (m_store->renameCollection(oldName, newName)) emit collectionsChanged(); } @@ -74,9 +84,16 @@ ThemeProperty DesignSystemInterface::createThemeProperty(const QString &name, QStringList DesignSystemInterface::collections() const { + QTC_ASSERT(m_store, return {}); + return m_store->collectionNames(); } +void DesignSystemInterface::setDSStore(DSStore *store) +{ + m_store = store; +} + CollectionModel *DesignSystemInterface::createModel(const QString &typeName, DSThemeManager *collection) { auto [iterator, inserted] = m_models.try_emplace(typeName, collection, m_store); diff --git a/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.h b/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.h index 6aaa7e92023..6f4f8c1e0a5 100644 --- a/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.h +++ b/src/plugins/qmldesigner/components/designsystemview/designsysteminterface.h @@ -18,7 +18,7 @@ class DesignSystemInterface : public QObject Q_PROPERTY(QStringList collections READ collections NOTIFY collectionsChanged FINAL) public: - DesignSystemInterface(DSStore *store); + DesignSystemInterface(); ~DesignSystemInterface(); Q_INVOKABLE void loadDesignSystem(); @@ -35,6 +35,8 @@ public: QStringList collections() const; + void setDSStore(DSStore *store); + signals: void collectionsChanged(); diff --git a/src/plugins/qmldesigner/components/designsystemview/designsystemview.cpp b/src/plugins/qmldesigner/components/designsystemview/designsystemview.cpp index 29e8cf49f49..a7f9ef33a52 100644 --- a/src/plugins/qmldesigner/components/designsystemview/designsystemview.cpp +++ b/src/plugins/qmldesigner/components/designsystemview/designsystemview.cpp @@ -21,17 +21,14 @@ namespace QmlDesigner { -DesignSystemView::DesignSystemView(ExternalDependenciesInterface &externalDependencies, - ProjectStorageDependencies projectStorageDependencies) +DesignSystemView::DesignSystemView(ExternalDependenciesInterface &externalDependencies) : AbstractView(externalDependencies) , m_externalDependencies(externalDependencies) - , m_dsStore(std::make_unique(m_externalDependencies, projectStorageDependencies)) - , m_dsInterface(m_dsStore.get()) { connect(ProjectExplorer::ProjectManager::instance(), &ProjectExplorer::ProjectManager::startupProjectChanged, this, - [this](ProjectExplorer::Project *) { loadDesignSystem(); }); + [this](ProjectExplorer::Project *) { resetDesignSystem(); }); connect(Core::EditorManager::instance(), &Core::EditorManager::saved, @@ -63,12 +60,31 @@ bool DesignSystemView::hasWidget() const return true; } +void DesignSystemView::modelAttached(Model *model) +{ + AbstractView::modelAttached(model); + /* Only load on first attach */ + if (!m_dsStore) + loadDesignSystem(); +} + void DesignSystemView::loadDesignSystem() { /*This is only used to load internally - when saving we have to take care of reflection. * Saving should not trigger a load again. */ + + m_dsStore = std::make_unique(m_externalDependencies, + model()->projectStorageDependencies()); + m_dsInterface.setDSStore(m_dsStore.get()); + m_dsInterface.loadDesignSystem(); } +void DesignSystemView::resetDesignSystem() +{ + m_dsStore.reset(); + m_dsInterface.setDSStore(nullptr); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/designsystemview/designsystemview.h b/src/plugins/qmldesigner/components/designsystemview/designsystemview.h index b3c44cfb873..42332c13819 100644 --- a/src/plugins/qmldesigner/components/designsystemview/designsystemview.h +++ b/src/plugins/qmldesigner/components/designsystemview/designsystemview.h @@ -4,6 +4,7 @@ #pragma once #include "designsysteminterface.h" +#include "qmldesignerprojectmanager.h" #include #include @@ -13,21 +14,24 @@ namespace QmlDesigner { class DSStore; class ExternalDependenciesInterface; class DesignSystemWidget; +class QmlDesignerProjectManager; class DesignSystemView : public AbstractView { Q_OBJECT public: - explicit DesignSystemView(ExternalDependenciesInterface &externalDependencies, - ProjectStorageDependencies projectStorageDependencies); + explicit DesignSystemView(ExternalDependenciesInterface &externalDependencies); ~DesignSystemView() override; WidgetInfo widgetInfo() override; bool hasWidget() const override; + void modelAttached(Model *model) override; + private: void loadDesignSystem(); + void resetDesignSystem(); QWidget *createViewWidget(); private: diff --git a/src/plugins/qmldesigner/components/edit3d/bakelights.cpp b/src/plugins/qmldesigner/components/edit3d/bakelights.cpp index 0410bbf3e5e..b715deb9c3c 100644 --- a/src/plugins/qmldesigner/components/edit3d/bakelights.cpp +++ b/src/plugins/qmldesigner/components/edit3d/bakelights.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include namespace QmlDesigner { @@ -74,6 +73,9 @@ BakeLights::BakeLights(AbstractView *view) return; } + m_pendingRebakeTimer.setInterval(100); + connect(&m_pendingRebakeTimer, &QTimer::timeout, this, &BakeLights::handlePendingRebakeTimeout); + showSetupDialog(); } @@ -215,7 +217,8 @@ void BakeLights::rebake() void BakeLights::exposeModelsAndLights(const QString &nodeId) { ModelNode compNode = m_view->modelNodeForId(nodeId); - if (!compNode.isValid() || !compNode.isComponent()) { + if (!compNode.isValid() || !compNode.isComponent() + || (m_pendingRebakeTimer.isActive() && compNode == m_pendingRebakeCheckNode)) { return; } @@ -294,8 +297,9 @@ void BakeLights::exposeModelsAndLights(const QString &nodeId) compModel->setRewriterView({}); - // Rebake to relaunch setup dialog with updated properties - rebake(); + m_pendingRebakeTimerCount = 0; + m_pendingRebakeCheckNode = compNode; + m_pendingRebakeTimer.start(); } void BakeLights::showSetupDialog() @@ -376,6 +380,8 @@ void BakeLights::cleanup() m_model.reset(); } + pendingRebakeCleanup(); + delete m_setupDialog; delete m_progressDialog; delete m_rewriterView; @@ -386,6 +392,43 @@ void BakeLights::cleanup() m_manualMode = false; } +void BakeLights::handlePendingRebakeTimeout() +{ + QScopeGuard timerCleanup([this]() { + pendingRebakeCleanup(); + }); + + if (m_view.isNull() || !m_pendingRebakeCheckNode || !m_pendingRebakeCheckNode.isComponent()) + return; + + const Model *model = m_pendingRebakeCheckNode.model(); + if (!model) + return; + + const QList props = m_pendingRebakeCheckNode.properties(); + PropertyMetaInfos metaInfos = m_pendingRebakeCheckNode.metaInfo().properties(); + for (const PropertyMetaInfo &mi : metaInfos) { + if (mi.isValid() && !mi.isPrivate() && mi.isWritable()) { + if (mi.propertyType().isBasedOn(model->qtQuick3DModelMetaInfo(), + model->qtQuick3DLightMetaInfo())) { + // Rebake to relaunch setup dialog with updated properties + rebake(); + return; + } + } + } + + if (++m_pendingRebakeTimerCount < 100) + timerCleanup.dismiss(); +} + +void BakeLights::pendingRebakeCleanup() +{ + m_pendingRebakeTimer.stop(); + m_pendingRebakeTimerCount = 0; + m_pendingRebakeCheckNode = {}; +} + void BakeLights::cancel() { if (!m_setupDialog.isNull() && m_setupDialog->isVisible()) diff --git a/src/plugins/qmldesigner/components/edit3d/bakelights.h b/src/plugins/qmldesigner/components/edit3d/bakelights.h index 2b6848bd482..3bdb8bfec9d 100644 --- a/src/plugins/qmldesigner/components/edit3d/bakelights.h +++ b/src/plugins/qmldesigner/components/edit3d/bakelights.h @@ -7,6 +7,7 @@ #include #include +#include QT_BEGIN_NAMESPACE class QQuickView; @@ -53,6 +54,8 @@ private: void showSetupDialog(); void showProgressDialog(); void cleanup(); + void handlePendingRebakeTimeout(); + void pendingRebakeCleanup(); // Separate dialogs for setup and progress, as setup needs to be modal QPointer m_setupDialog; @@ -66,6 +69,9 @@ private: ModelPointer m_model; QString m_view3dId; bool m_manualMode = false; + QTimer m_pendingRebakeTimer; + ModelNode m_pendingRebakeCheckNode; + int m_pendingRebakeTimerCount = 0; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp index a0ac71a9399..3545c218a54 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dcanvas.cpp @@ -98,11 +98,11 @@ void Edit3DCanvas::setFlyMode(bool enabled, const QPoint &pos) m_flyModeStartCursorPos = pos; m_flyModeFirstUpdate = true; - // Hide cursor on the middle of the active split to make the wheel work during flight mode. - // We can't rely on current activeSplit value, as mouse press to enter flight mode can change the - // active split, so hide the cursor based on its current location. + // Hide cursor on the middle of the active viewport to make the wheel work during flight mode. + // We can't rely on current activeViewport value, as mouse press to enter flight mode can change the + // active viewport, so hide the cursor based on its current location. QPoint center = mapToGlobal(QPoint(width() / 2, height() / 2)); - if (m_parent->view()->isSplitView()) { + if (m_parent->view()->isMultiViewportView()) { if (pos.x() <= center.x()) { if (pos.y() <= center.y()) m_hiddenCursorPos = mapToGlobal(QPoint(width() / 4, height() / 4)); @@ -192,7 +192,7 @@ void Edit3DCanvas::mouseMoveEvent(QMouseEvent *e) if (!m_flyModeFirstUpdate) { // We notify explicit camera rotation needs for QML Puppet rather than relying on mouse events, // as mouse isn't grabbed on QML Puppet side and can't handle fast movements that go out of - // edit camera mouse area. This also simplifies split view handling. + // edit camera mouse area. This also simplifies viewport view handling. QPointF diff = m_isQDSTrusted ? (m_hiddenCursorPos - globalPos) : (m_lastCursorPos - e->globalPosition().toPoint()); diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp index fdfecebdf58..37c9c66f542 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp @@ -73,7 +73,7 @@ Edit3DView::Edit3DView(ExternalDependenciesInterface &externalDependencies) connect(&m_compressionTimer, &QTimer::timeout, this, &Edit3DView::handleEntriesChanged); for (int i = 0; i < 4; ++i) - m_splitToolStates.append({0, false, i == 0}); + m_viewportToolStates.append({0, false, i == 0}); } void Edit3DView::createEdit3DWidget() @@ -120,15 +120,15 @@ void Edit3DView::renderImage3DChanged(const QImage &img) void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) { - const QString activeSplitKey = QStringLiteral("activeSplit"); - if (sceneState.contains(activeSplitKey)) { - setActiveSplit(sceneState[activeSplitKey].toInt()); - // If the sceneState contained just activeSplit key, then this is simply an active split + const QString activeViewportKey = QStringLiteral("activeViewport"); + if (sceneState.contains(activeViewportKey)) { + setActiveViewport(sceneState[activeViewportKey].toInt()); + // If the sceneState contained just activeViewport key, then this is simply an active Viewport // change rather than entire active scene change, and we don't need to process further. if (sceneState.size() == 1) return; } else { - setActiveSplit(0); + setActiveViewport(0); } const QString sceneKey = QStringLiteral("sceneInstanceId"); @@ -146,7 +146,7 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) const QString particleEmitterKey = QStringLiteral("showParticleEmitter"); const QString particlesPlayKey = QStringLiteral("particlePlay"); const QString syncEnvBgKey = QStringLiteral("syncEnvBackground"); - const QString splitViewKey = QStringLiteral("splitView"); + const QString activePresetKey = QStringLiteral("activePreset"); const QString matOverrideKey = QStringLiteral("matOverride"); const QString showWireframeKey = QStringLiteral("showWireframe"); @@ -177,10 +177,10 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) if (sceneState.contains(perspectiveKey)) { const QVariantList showList = sceneState[perspectiveKey].toList(); for (int i = 0; i < 4; ++i) - m_splitToolStates[i].isPerspective = i < showList.size() ? showList[i].toBool() : i == 0; + m_viewportToolStates[i].isPerspective = i < showList.size() ? showList[i].toBool() : i == 0; } else { for (int i = 0; i < 4; ++i) { - SplitToolState &state = m_splitToolStates[i]; + ViewportToolState &state = m_viewportToolStates[i]; state.isPerspective = i == 0; } } @@ -235,26 +235,21 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) else m_particlesPlayAction->action()->setChecked(true); - if (sceneState.contains(splitViewKey)) - m_splitViewAction->action()->setChecked(sceneState[splitViewKey].toBool()); - else - m_splitViewAction->action()->setChecked(false); - if (sceneState.contains(matOverrideKey)) { const QVariantList overrides = sceneState[matOverrideKey].toList(); for (int i = 0; i < 4; ++i) - m_splitToolStates[i].matOverride = i < overrides.size() ? overrides[i].toInt() : 0; + m_viewportToolStates[i].matOverride = i < overrides.size() ? overrides[i].toInt() : 0; } else { - for (SplitToolState &state : m_splitToolStates) + for (ViewportToolState &state : m_viewportToolStates) state.matOverride = 0; } if (sceneState.contains(showWireframeKey)) { const QVariantList showList = sceneState[showWireframeKey].toList(); for (int i = 0; i < 4; ++i) - m_splitToolStates[i].showWireframe = i < showList.size() ? showList[i].toBool() : false; + m_viewportToolStates[i].showWireframe = i < showList.size() ? showList[i].toBool() : false; } else { - for (SplitToolState &state : m_splitToolStates) + for (ViewportToolState &state : m_viewportToolStates) state.showWireframe = false; } @@ -274,10 +269,10 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState) storeCurrentSceneEnvironment(); } -void Edit3DView::setActiveSplit(int split) +void Edit3DView::setActiveViewport(int viewport) { - m_activeSplit = split; - m_cameraModeAction->action()->setChecked(m_splitToolStates[m_activeSplit].isPerspective); + m_activeViewport = viewport; + m_cameraModeAction->action()->setChecked(m_viewportToolStates[m_activeViewport].isPerspective); } void Edit3DView::modelAttached(Model *model) @@ -317,8 +312,6 @@ void Edit3DView::modelAttached(Model *model) m_isBakingLightsSupported = qtVer->qtVersion() >= QVersionNumber(6, 5, 0); } #ifdef QDS_USE_PROJECTSTORAGE - // TODO: Handle actual entries changed signal/notification once it is available. - // Until then, we simply get what entries are available at model attach time. onEntriesChanged(); #else connect(model->metaInfo().itemLibraryInfo(), @@ -462,7 +455,9 @@ void Edit3DView::customNotification([[maybe_unused]] const AbstractView *view, self->m_pickView3dNode = self->modelNodeForInternalId(qint32(data[1].toInt())); }); } else if (identifier == "asset_import_finished" || identifier == "assets_deleted") { - handleEntriesChanged(); + // TODO: These custom notifications should be removed once QDS-15163 is fixed and + // exportedTypeNamesChanged notification is reliable + onEntriesChanged(); } } @@ -571,6 +566,13 @@ void Edit3DView::variantPropertiesChanged(const QList &property maybeStoreCurrentSceneEnvironment(propertyList); } +void Edit3DView::exportedTypeNamesChanged(const ExportedTypeNames &added, + const ExportedTypeNames &removed) +{ + if (Utils3D::hasImported3dType(this, added, removed)) + onEntriesChanged(); +} + void Edit3DView::sendInputEvent(QEvent *e) const { if (isAttached()) @@ -702,6 +704,45 @@ void Edit3DView::createSyncEnvBackgroundAction() tooltip); } +void Edit3DView::createViewportPresetActions() +{ + auto createViewportPresetAction = [this](std::unique_ptr &targetAction, + const QByteArray &id, + const QString &label, + bool isChecked) { + auto operation = [this, &targetAction, label](const SelectionContext &) { + for (Edit3DAction *action : std::as_const(m_viewportPresetActions)) { + if (action->menuId() != targetAction->menuId()) + action->action()->setChecked(false); + } + emitView3DAction(View3DActionType::ViewportPreset, label); + }; + + targetAction = std::make_unique( + id, + View3DActionType::Empty, + label, + QKeySequence(), + true, + isChecked, + QIcon(), + this, + operation); + }; + + createViewportPresetAction(m_viewportPresetSingleAction, Constants::EDIT3D_PRESET_SINGLE, "Single", true); + createViewportPresetAction(m_viewportPresetQuadAction, Constants::EDIT3D_PRESET_QUAD, "Quad", false); + createViewportPresetAction(m_viewportPreset3Left1RightAction, Constants::EDIT3D_PRESET_3LEFT1RIGHT, "3Left1Right", false); + createViewportPresetAction(m_viewportPreset2HorizontalAction, Constants::EDIT3D_PRESET_2HORIZONTAL, "2Horizontal", false); + createViewportPresetAction(m_viewportPreset2VerticalAction, Constants::EDIT3D_PRESET_2VERTICAL, "2Vertical", false); + + m_viewportPresetActions << m_viewportPresetSingleAction.get(); + m_viewportPresetActions << m_viewportPresetQuadAction.get(); + m_viewportPresetActions << m_viewportPreset3Left1RightAction.get(); + m_viewportPresetActions << m_viewportPreset2HorizontalAction.get(); + m_viewportPresetActions << m_viewportPreset2VerticalAction.get(); +} + void Edit3DView::createSeekerSliderAction() { m_seekerAction = std::make_unique( @@ -923,27 +964,27 @@ void Edit3DView::storeCurrentSceneEnvironment() } } -const QList &Edit3DView::splitToolStates() const +const QList &Edit3DView::viewportToolStates() const { - return m_splitToolStates; + return m_viewportToolStates; } -void Edit3DView::setSplitToolState(int splitIndex, const SplitToolState &state) +void Edit3DView::setViewportToolState(int viewportIndex, const ViewportToolState &state) { - if (splitIndex >= m_splitToolStates.size()) + if (viewportIndex >= m_viewportToolStates.size()) return; - m_splitToolStates[splitIndex] = state; + m_viewportToolStates[viewportIndex] = state; } -int Edit3DView::activeSplit() const +int Edit3DView::activeViewport() const { - return m_activeSplit; + return m_activeViewport; } -bool Edit3DView::isSplitView() const +bool Edit3DView::isMultiViewportView() const { - return m_splitViewAction->action()->isChecked(); + return m_viewportPresetsMenuAction->action()->isChecked(); } void Edit3DView::createEdit3DActions() @@ -1015,12 +1056,12 @@ void Edit3DView::createEdit3DActions() SelectionContextOperation cameraModeTrigger = [this](const SelectionContext &) { QVariantList list; - for (int i = 0; i < m_splitToolStates.size(); ++i) { - Edit3DView::SplitToolState state = m_splitToolStates[i]; - if (i == m_activeSplit) { + for (int i = 0; i < m_viewportToolStates.size(); ++i) { + Edit3DView::ViewportToolState state = m_viewportToolStates[i]; + if (i == m_activeViewport) { bool isChecked = m_cameraModeAction->action()->isChecked(); state.isPerspective = isChecked; - setSplitToolState(i, state); + setViewportToolState(i, state); list.append(isChecked); } else { list.append(state.isPerspective); @@ -1308,14 +1349,24 @@ void Edit3DView::createEdit3DActions() this, snapConfigTrigger); - m_splitViewAction = std::make_unique(QmlDesigner::Constants::EDIT3D_SPLIT_VIEW, - View3DActionType::SplitViewToggle, - Tr::tr("Toggle Split View On/Off"), - QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_Q), - true, + SelectionContextOperation viewportPresetsActionTrigger = [this](const SelectionContext &) { + if (!edit3DWidget()->viewportPresetsMenu()) + return; + + edit3DWidget()->showViewportPresetsMenu( + !edit3DWidget()->viewportPresetsMenu()->isVisible(), + resolveToolbarPopupPos(m_viewportPresetsMenuAction.get())); + }; + + m_viewportPresetsMenuAction = std::make_unique(QmlDesigner::Constants::EDIT3D_PRESETS, + View3DActionType::Empty, + Tr::tr("Show Viewport Modes"), + QKeySequence(), + false, false, toolbarIcon(DesignerIcons::SplitViewIcon), - this); + this, + viewportPresetsActionTrigger); SelectionContextOperation cameraSpeedConfigTrigger = [this](const SelectionContext &) { if (!m_cameraSpeedConfiguration) { @@ -1365,7 +1416,7 @@ void Edit3DView::createEdit3DActions() m_leftActions << nullptr; m_leftActions << m_visibilityTogglesAction.get(); m_leftActions << m_backgroundColorMenuAction.get(); - m_leftActions << m_splitViewAction.get(); + m_leftActions << m_viewportPresetsMenuAction.get(); m_rightActions << m_particleViewModeAction.get(); m_rightActions << m_particlesPlayAction.get(); @@ -1393,6 +1444,8 @@ void Edit3DView::createEdit3DActions() m_backgroundColorActions << m_selectGridColorAction.get(); m_backgroundColorActions << m_syncEnvBackgroundAction.get(); m_backgroundColorActions << m_resetColorAction.get(); + + createViewportPresetActions(); } QVector Edit3DView::leftActions() const @@ -1415,6 +1468,10 @@ QVector Edit3DView::backgroundColorActions() const return m_backgroundColorActions; } +QVector Edit3DView::viewportPresetActions() const +{ + return m_viewportPresetActions; +} Edit3DAction *Edit3DView::edit3DAction(View3DActionType type) const { diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h index e89cf8cac22..1c5d478357d 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h @@ -39,7 +39,7 @@ class QMLDESIGNERCOMPONENTS_EXPORT Edit3DView : public AbstractView Q_OBJECT public: - struct SplitToolState + struct ViewportToolState { int matOverride = 0; bool showWireframe = false; @@ -80,7 +80,8 @@ public: PropertyChangeFlags propertyChange) override; void variantPropertiesChanged(const QList &propertyList, PropertyChangeFlags propertyChange) override; - + void exportedTypeNamesChanged(const ExportedTypeNames &added, + const ExportedTypeNames &removed) override; void sendInputEvent(QEvent *e) const; void edit3DViewResized(const QSize &size) const; @@ -91,6 +92,7 @@ public: QVector rightActions() const; QVector visibilityToggleActions() const; QVector backgroundColorActions() const; + QVector viewportPresetActions() const; Edit3DAction *edit3DAction(View3DActionType type) const; Edit3DBakeLightsAction *bakeLightsAction() const; @@ -109,11 +111,11 @@ public: void setCameraSpeedAuxData(double speed, double multiplier); void getCameraSpeedAuxData(double &speed, double &multiplier); - const QList &splitToolStates() const; - void setSplitToolState(int splitIndex, const SplitToolState &state); + const QList &viewportToolStates() const; + void setViewportToolState(int viewportIndex, const ViewportToolState &state); - int activeSplit() const; - bool isSplitView() const; + int activeViewport() const; + bool isMultiViewportView() const; void setFlyMode(bool enabled); void emitView3DAction(View3DActionType type, const QVariant &value); @@ -146,12 +148,13 @@ private: void createGridColorSelectionAction(); void createResetColorAction(QAction *syncEnvBackgroundAction); void createSyncEnvBackgroundAction(); + void createViewportPresetActions(); void createSeekerSliderAction(); void syncCameraSpeedToNewView(); QmlObjectNode currentSceneEnv(); void storeCurrentSceneEnvironment(); - void setActiveSplit(int split); + void setActiveViewport(int viewportIndex); QPoint resolveToolbarPopupPos(Edit3DAction *action) const; @@ -163,6 +166,7 @@ private: QVector m_rightActions; QVector m_visibilityToggleActions; QVector m_backgroundColorActions; + QVector m_viewportPresetActions; QMap m_edit3DActions; std::unique_ptr m_selectionModeAction; @@ -190,7 +194,14 @@ private: std::unique_ptr m_selectBackgroundColorAction; std::unique_ptr m_selectGridColorAction; std::unique_ptr m_resetColorAction; - std::unique_ptr m_splitViewAction; + + // Viewport presets actions + std::unique_ptr m_viewportPresetSingleAction; + std::unique_ptr m_viewportPresetQuadAction; + std::unique_ptr m_viewportPreset3Left1RightAction; + std::unique_ptr m_viewportPreset2HorizontalAction; + std::unique_ptr m_viewportPreset2VerticalAction; + std::unique_ptr m_viewportPresetsMenuAction; // View3DActionType::Empty actions std::unique_ptr m_resetAction; @@ -215,9 +226,9 @@ private: bool m_isBakingLightsSupported = false; QPointer m_snapConfiguration; QPointer m_cameraSpeedConfiguration; - int m_activeSplit = 0; + int m_activeViewport = 0; - QList m_splitToolStates; + QList m_viewportToolStates; ModelNode m_contextMenuPendingNode; ModelNode m_pickView3dNode; diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp index 495343e7fd9..9b1f60e5e19 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp @@ -179,6 +179,10 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) handleActions(view->backgroundColorActions(), m_backgroundColorMenu, false); + m_viewportPresetsMenu = new QMenu(this); + m_viewportPresetsMenu->setToolTipsVisible(true); + handleActions(view->viewportPresetActions(), m_viewportPresetsMenu, false); + createContextMenu(); // Onboarding label contains instructions for new users how to get 3D content into the project @@ -568,11 +572,11 @@ void Edit3DWidget::onMatOverrideAction(QAction *action) 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()) { + for (int i = 0; i < m_view->viewportToolStates().size(); ++i) { + Edit3DView::ViewportToolState state = m_view->viewportToolStates()[i]; + if (i == m_view->activeViewport()) { state.matOverride = action->data().toInt(); - m_view->setSplitToolState(i, state); + m_view->setViewportToolState(i, state); list.append(action->data()); } else { list.append(state.matOverride); @@ -588,11 +592,11 @@ void Edit3DWidget::onWireframeAction() 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()) { + for (int i = 0; i < m_view->viewportToolStates().size(); ++i) { + Edit3DView::ViewportToolState state = m_view->viewportToolStates()[i]; + if (i == m_view->activeViewport()) { state.showWireframe = m_wireFrameAction->isChecked(); - m_view->setSplitToolState(i, state); + m_view->setViewportToolState(i, state); list.append(m_wireFrameAction->isChecked()); } else { list.append(state.showWireframe); @@ -610,11 +614,11 @@ void Edit3DWidget::onResetAllOverridesAction() QVariantList wList; QVariantList mList; - for (int i = 0; i < m_view->splitToolStates().size(); ++i) { - Edit3DView::SplitToolState state; + for (int i = 0; i < m_view->viewportToolStates().size(); ++i) { + Edit3DView::ViewportToolState state; state.showWireframe = false; state.matOverride = 0; - m_view->setSplitToolState(i, state); + m_view->setViewportToolState(i, state); wList.append(state.showWireframe); mList.append(state.matOverride); } @@ -675,6 +679,21 @@ void Edit3DWidget::showBackgroundColorMenu(bool show, const QPoint &pos) m_backgroundColorMenu->close(); } +QMenu *Edit3DWidget::viewportPresetsMenu() const +{ + return m_viewportPresetsMenu.data(); +} + +void Edit3DWidget::showViewportPresetsMenu(bool show, const QPoint &pos) +{ + if (m_viewportPresetsMenu.isNull()) + return; + if (show) + m_viewportPresetsMenu->popup(pos); + else + m_viewportPresetsMenu->close(); +} + void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode, const QVector3D &pos3d) { auto compUtils = QmlDesignerPlugin::instance()->documentManager().generatedComponentUtils(); @@ -711,11 +730,11 @@ void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode m_materialsAction->updateMenu(view()->selectedModelNodes()); if (m_view) { - int idx = m_view->activeSplit(); - m_wireFrameAction->setChecked(m_view->splitToolStates()[idx].showWireframe); + int idx = m_view->activeViewport(); + m_wireFrameAction->setChecked(m_view->viewportToolStates()[idx].showWireframe); for (QAction *a : std::as_const(m_matOverrideActions)) a->setChecked(false); - int type = m_view->splitToolStates()[idx].matOverride; + int type = m_view->viewportToolStates()[idx].matOverride; m_matOverrideActions[type]->setChecked(true); } diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h index 9b286699977..bc5a1b20d60 100644 --- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h +++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h @@ -58,6 +58,9 @@ public: QMenu *backgroundColorMenu() const; void showBackgroundColorMenu(bool show, const QPoint &pos); + QMenu *viewportPresetsMenu() const; + void showViewportPresetsMenu(bool show, const QPoint &pos); + void showContextMenu(const QPoint &pos, const ModelNode &modelNode, const QVector3D &pos3d); void updateCreateSubMenu(const QList &entriesList); @@ -91,6 +94,7 @@ private: Core::IContext *m_context = nullptr; QPointer m_visibilityTogglesMenu; QPointer m_backgroundColorMenu; + QPointer m_viewportPresetsMenu; QPointer m_contextMenu; QPointer m_bakeLightsAction; QPointer m_editComponentAction; diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp index 198ba819fcc..c8935baa4e5 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorscene.cpp @@ -82,7 +82,7 @@ double FormEditorScene::canvasHeight() const return QmlDesignerPlugin::settings().value(DesignerSettingsKey::CANVASHEIGHT).toDouble(); } -QList FormEditorScene::itemsForQmlItemNodes(const QList &nodeList) const +QList FormEditorScene::itemsForQmlItemNodes(Utils::span nodeList) const { return CoreUtils::to( nodeList | std::views::transform(std::bind_front(&FormEditorScene::itemForQmlItemNode, this)) @@ -400,7 +400,7 @@ void FormEditorScene::clearFormEditorItems() auto cast = [](QGraphicsItem *item) { return qgraphicsitem_cast(item); }; - auto formEditorItems = itemList | std::views::transform(cast) + auto formEditorItems = Utils::span{itemList} | std::views::transform(cast) | std::views::filter(std::identity{}); for (FormEditorItem *item : formEditorItems) diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorscene.h b/src/plugins/qmldesigner/components/formeditor/formeditorscene.h index 29330402b82..c2f0f0e170b 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorscene.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditorscene.h @@ -5,6 +5,8 @@ #include #include "abstractformeditortool.h" +#include + #include #include #include @@ -46,7 +48,7 @@ public: FormEditorItem* itemForQmlItemNode(const QmlItemNode &qmlItemNode) const; - QList itemsForQmlItemNodes(const QList &nodeList) const; + QList itemsForQmlItemNodes(Utils::span nodeList) const; QList allFormEditorItems() const; void updateAllFormEditorItems(); diff --git a/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp b/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp index d30539d52b6..13a26252877 100644 --- a/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp +++ b/src/plugins/qmldesigner/components/formeditor/selectiontool.cpp @@ -223,9 +223,12 @@ void SelectionTool::itemsAboutToRemoved(const QList &itemList) { const QList current = items(); - QList remaining = Utils::filtered(current, [&itemList](FormEditorItem *item) { - return !itemList.contains(item); - }); + const auto allItems = scene()->items(); + QList remaining = Utils::filtered(current, + [&itemList, &allItems](FormEditorItem *item) { + return !itemList.contains(item) + && allItems.contains(item); + }); if (!remaining.isEmpty()) { m_selectionIndicator.setItems(remaining); diff --git a/src/plugins/qmldesigner/components/integration/designdocumentview.cpp b/src/plugins/qmldesigner/components/integration/designdocumentview.cpp index 22175921e99..37d4aae0552 100644 --- a/src/plugins/qmldesigner/components/integration/designdocumentview.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocumentview.cpp @@ -123,6 +123,7 @@ QString DesignDocumentView::toText() const rewriterView->setCheckSemanticErrors(false); rewriterView->setPossibleImportsEnabled(false); rewriterView->setTextModifier(&modifier); + rewriterView->setRemoveImports(false); outputModel->setRewriterView(rewriterView.get()); ModelMerger merger(rewriterView.get()); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp index bdac4a78cb5..80f4dd7405d 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryimport.cpp @@ -239,8 +239,12 @@ ItemLibraryImport::SectionType ItemLibraryImport::sectionType() const void ItemLibraryImport::updateRemovable() { +#ifdef QDS_USE_PROJECTSTORAGE + bool importRemovable = m_sectionType == SectionType::Default && m_import.url() != "QtQuick"; +#else bool importRemovable = !m_importUsed && m_sectionType == SectionType::Default - && m_import.url() != "QtQuick"; + && m_import.url() != "QtQuick"; +#endif if (importRemovable != m_importRemovable) { m_importRemovable = importRemovable; emit importRemovableChanged(); diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index 3baacb2571f..19a57659c8e 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -358,15 +358,14 @@ void ItemLibraryModel::update(Model *model) itemLibImport->setImportExpanded(loadExpandedState(itemLibImport->importUrl())); } -#ifndef QDS_USE_PROJECTSTORAGE DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument(); const bool blockNewImports = document->inFileComponentModelActive(); -#endif TypeName currentFileType = QFileInfo(model->fileUrl().toLocalFile()).baseName().toUtf8(); - const QList itemLibEntries = model->itemLibraryEntries(); - for (const ItemLibraryEntry &entry : itemLibEntries) { + QList itemLibEntries = model->allItemLibraryEntries(); + itemLibEntries.append(model->directoryImportsItemLibraryEntries()); + for (const ItemLibraryEntry &entry : std::as_const(itemLibEntries)) { NodeMetaInfo metaInfo; #ifdef QDS_USE_PROJECTSTORAGE @@ -407,15 +406,14 @@ void ItemLibraryModel::update(Model *model) } } -#ifndef QDS_USE_PROJECTSTORAGE Import import = entryToImport(entry); bool hasImport = model->hasImport(import, true, true); +#ifndef QDS_USE_PROJECTSTORAGE bool isImportPossible = false; if (!hasImport) isImportPossible = !blockNewImports && model->isImportPossible(import, true, true); #else - bool hasImport = true; - bool isImportPossible = false; + bool isImportPossible = !blockNewImports; #endif bool isUsable = (valid && (isItem || forceVisibility)) && (entry.requiredImport().isEmpty() || hasImport); diff --git a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.cpp b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.cpp index 11440ea11da..bbbda2e095f 100644 --- a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.cpp +++ b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.cpp @@ -20,8 +20,6 @@ #include #include -#include - namespace QmlDesigner { namespace { @@ -46,7 +44,8 @@ ListModelEditorDialog::ListModelEditorDialog(QWidget *parent) m_tableView = new QTableView; mainLayout->addWidget(m_tableView); - m_addRowAction = toolBar->addAction(getIcon(Theme::Icon::addRowAfter), tr("Add Row")); + m_addRowAboveAction = toolBar->addAction(getIcon(Theme::Icon::addRowBefore), tr("Add Row Above")); + m_addRowBelowAction = toolBar->addAction(getIcon(Theme::Icon::addRowAfter), tr("Add Row Below")); m_removeRowsAction = toolBar->addAction(getIcon(Theme::Icon::deleteRow), tr("Remove Rows")); m_addColumnAction = toolBar->addAction(getIcon(Theme::Icon::addColumnAfter), tr("Add Column")); m_removeColumnsAction = toolBar->addAction(getIcon(Theme::Icon::deleteColumn), @@ -54,7 +53,7 @@ ListModelEditorDialog::ListModelEditorDialog(QWidget *parent) m_moveDownAction = toolBar->addAction(Icons::ARROW_DOWN.icon(), tr("Move Down (Ctrl + Down)")); m_moveDownAction->setShortcut(QKeySequence(Qt::Key_Down | Qt::CTRL)); m_moveUpAction = toolBar->addAction(Icons::ARROW_UP.icon(), tr("Move Up (Ctrl + Up)")); - m_moveDownAction->setShortcut(QKeySequence(Qt::Key_Up | Qt::CTRL)); + m_moveUpAction->setShortcut(QKeySequence(Qt::Key_Up | Qt::CTRL)); } ListModelEditorDialog::~ListModelEditorDialog() = default; @@ -63,7 +62,8 @@ void ListModelEditorDialog::setModel(ListModelEditorModel *model) { m_model = model; - connect(m_addRowAction, &QAction::triggered, m_model, &ListModelEditorModel::addRow); + connect(m_addRowAboveAction, &QAction::triggered, this, &ListModelEditorDialog::addRowAbove); + connect(m_addRowBelowAction, &QAction::triggered, this, &ListModelEditorDialog::addRowBelow); connect(m_addColumnAction, &QAction::triggered, this, &ListModelEditorDialog::openColumnDialog); connect(m_removeRowsAction, &QAction::triggered, this, &ListModelEditorDialog::removeRows); connect(m_removeColumnsAction, &QAction::triggered, this, &ListModelEditorDialog::removeColumns); @@ -79,16 +79,48 @@ void ListModelEditorDialog::setModel(ListModelEditorModel *model) m_tableView->verticalHeader()->setMinimumSectionSize(25); m_tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); m_tableView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); + + connect(model, + &ListModelEditorModel::rowsInserted, + this, + &ListModelEditorDialog::onRowsInserted, + Qt::ConnectionType::UniqueConnection); + + connect(model, + &ListModelEditorModel::columnsInserted, + this, + &ListModelEditorDialog::onColumnsInserted, + Qt::ConnectionType::UniqueConnection); + + connect(m_tableView->selectionModel(), + &QItemSelectionModel::selectionChanged, + this, + &ListModelEditorDialog::updateSelection, + Qt::ConnectionType::UniqueConnection); + updateSelection(); } void ListModelEditorDialog::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Delete) { - for (const QModelIndex index : m_tableView->selectionModel()->selectedIndexes()) + const QModelIndexList selectedIndexes = m_tableView->selectionModel()->selectedIndexes(); + for (const QModelIndex index : selectedIndexes) m_model->setData(index, QVariant(), Qt::EditRole); } } +void ListModelEditorDialog::addRowAbove() +{ + // If there's no items in the model, or nothing is selected, The item should be prepended. + int curInteractionRow = ListModelEditorModel::currentInteractionRow(*m_tableView->selectionModel()); + m_model->addRow(std::max(0, curInteractionRow)); +} + +void ListModelEditorDialog::addRowBelow() +{ + m_model->addRow(ListModelEditorModel::nextInteractionRow(*m_tableView->selectionModel())); +} + void ListModelEditorDialog::openColumnDialog() { bool ok; @@ -126,13 +158,58 @@ void ListModelEditorDialog::changeHeader(int column) void ListModelEditorDialog::moveRowsDown() { QItemSelection selection = m_model->moveRowsDown(m_tableView->selectionModel()->selectedRows()); - m_tableView->selectionModel()->select(selection, QItemSelectionModel::Select); + m_tableView->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect); + if (!selection.isEmpty()) { + m_tableView->selectionModel()->setCurrentIndex(selection.first().topLeft(), + QItemSelectionModel::Current); + } } void ListModelEditorDialog::moveRowsUp() { QItemSelection selection = m_model->moveRowsUp(m_tableView->selectionModel()->selectedRows()); - m_tableView->selectionModel()->select(selection, QItemSelectionModel::Select); + m_tableView->selectionModel()->select(selection, QItemSelectionModel::ClearAndSelect); + if (!selection.isEmpty()) { + m_tableView->selectionModel()->setCurrentIndex(selection.first().topLeft(), + QItemSelectionModel::Current); + } +} + +void ListModelEditorDialog::updateSelection() +{ + QItemSelectionModel *selection = m_tableView->selectionModel(); + bool hasRowSelection = !selection->selectedRows().isEmpty(); + bool hasColumnSelection = !selection->selectedColumns().isEmpty(); + const int rows = m_tableView->model()->rowCount(); + + m_moveUpAction->setEnabled(hasRowSelection && !selection->isRowSelected(0)); + m_moveDownAction->setEnabled(hasRowSelection && !selection->isRowSelected(rows - 1)); + m_removeRowsAction->setEnabled(hasRowSelection); + m_removeColumnsAction->setEnabled(hasColumnSelection); +} + +void ListModelEditorDialog::onRowsInserted(const QModelIndex &parent, int first, int last) +{ + QItemSelectionModel *selection = m_tableView->selectionModel(); + auto model = selection->model(); + const int cols = model->columnCount(parent); + auto topLeft = model->index(first, 0, parent); + auto bottomRight = model->index(last, cols - 1, parent); + QItemSelection rowsSelection{topLeft, bottomRight}; + + selection->select(rowsSelection, QItemSelectionModel::ClearAndSelect); +} + +void ListModelEditorDialog::onColumnsInserted(const QModelIndex &parent, int first, int last) +{ + QItemSelectionModel *selection = m_tableView->selectionModel(); + auto model = selection->model(); + const int rows = model->rowCount(parent); + auto topLeft = model->index(0, first, parent); + auto bottomRight = model->index(rows - 1, last, parent); + QItemSelection columnSelection{topLeft, bottomRight}; + + selection->select(columnSelection, QItemSelectionModel::ClearAndSelect); } } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.h b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.h index 8afafad79d7..d881c45b871 100644 --- a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.h +++ b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditordialog.h @@ -8,6 +8,7 @@ QT_BEGIN_NAMESPACE class QAbstractItemModel; class QTableView; +class QModelIndex; QT_END_NAMESPACE namespace Ui { @@ -32,17 +33,23 @@ protected: void keyPressEvent(QKeyEvent *) override; private: - void addRow(); + void addRowAbove(); + void addRowBelow(); void openColumnDialog(); void removeRows(); void removeColumns(); void changeHeader(int column); void moveRowsDown(); void moveRowsUp(); + void updateSelection(); + + void onRowsInserted(const QModelIndex &parent, int first, int last); + void onColumnsInserted(const QModelIndex &parent, int first, int last); private: ListModelEditorModel *m_model{}; - QAction *m_addRowAction{}; + QAction *m_addRowBelowAction{}; + QAction *m_addRowAboveAction{}; QAction *m_removeRowsAction{}; QAction *m_addColumnAction{}; QAction *m_removeColumnsAction{}; diff --git a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp index 0eb654bf0d0..6d5197b1bb5 100644 --- a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp +++ b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -14,9 +15,12 @@ #include #include #include +#include namespace QmlDesigner { +namespace { + class ListModelItem : public QStandardItem { public: @@ -91,7 +95,6 @@ public: bool hasInvalidValue = false; }; -namespace { QList getPropertyNames(const ModelNode &listElementNode) { auto properties = listElementNode.variantProperties(); @@ -102,7 +105,7 @@ QList getPropertyNames(const ModelNode &listElementNode) for (const auto &property : properties) names.push_back(property.name().toByteArray()); - std::sort(names.begin(), names.end()); + std::ranges::sort(names); return names; } @@ -113,11 +116,7 @@ QList mergeProperyNames(const QList &first, QList merged; merged.reserve(first.size() + second.size()); - std::set_union(first.begin(), - first.end(), - second.begin(), - second.end(), - std::back_inserter(merged)); + std::ranges::set_union(first, second, std::back_inserter(merged)); return merged; } @@ -213,14 +212,23 @@ void ListModelEditorModel::createItems(const QList &listElementNodes) appendItems(listElementNode); } -void ListModelEditorModel::appendItems(const ModelNode &listElementNode) +static QList createRow(const auto &propertyNames, const auto &listElementNode) { QList row; - row.reserve(m_propertyNames.size()); - for (const PropertyName &propertyName : propertyNames()) + row.reserve(propertyNames.size()); + for (const PropertyName &propertyName : propertyNames) row.push_back(createItem(listElementNode, propertyName).release()); + return row; +} - appendRow(row); +void ListModelEditorModel::insertItems(const ModelNode &listElementNode, int index) +{ + insertRow(index, createRow(m_propertyNames, listElementNode)); +} + +void ListModelEditorModel::appendItems(const ModelNode &listElementNode) +{ + appendRow(createRow(m_propertyNames, listElementNode)); } void ListModelEditorModel::setListModel(ModelNode node) @@ -234,19 +242,25 @@ void ListModelEditorModel::setListView(ModelNode listView) setListModel(listModelNode(listView, m_createModelCallback, m_goIntoComponentCallback)); } -void ListModelEditorModel::addRow() +void ListModelEditorModel::addRow(int rowIndex) { - auto newElement = m_createElementCallback(); - m_listModelNode.defaultNodeListProperty().reparentHere(newElement); + if (rowIndex < 0 || rowIndex > rowCount()) + return; - appendItems(newElement); + NodeListProperty defaultNodeListProperty = m_listModelNode.defaultNodeListProperty(); + defaultNodeListProperty.view()->executeInTransaction(__FUNCTION__, [&] { + auto newElement = m_createElementCallback(); + defaultNodeListProperty.reparentHere(newElement); + defaultNodeListProperty.slide(defaultNodeListProperty.count() - 1, rowIndex); + insertItems(newElement, rowIndex); + }); } void ListModelEditorModel::addColumn(const QString &columnName) { PropertyName propertyName = columnName.toUtf8(); - auto found = std::lower_bound(m_propertyNames.begin(), m_propertyNames.end(), propertyName); + auto found = std::ranges::lower_bound(m_propertyNames, propertyName); if (found != m_propertyNames.end() && *found == propertyName) return; @@ -271,7 +285,7 @@ bool ListModelEditorModel::setValue(int row, int column, QVariant value, Qt::Ite void ListModelEditorModel::removeColumn(int column) { - QList columnItems = QStandardItemModel::takeColumn(column); + QList columnItems = Super::takeColumn(column); m_propertyNames.removeAt(column); for (QStandardItem *columnItem : columnItems) { @@ -282,27 +296,27 @@ void ListModelEditorModel::removeColumn(int column) void ListModelEditorModel::removeColumns(const QList &indices) { + using std::ranges::views::reverse; + std::vector columns = filterColumns(indices); - std::reverse(columns.begin(), columns.end()); - - for (int column : columns) + for (int column : columns | reverse) removeColumn(column); } void ListModelEditorModel::removeRows(const QList &indices) { + using std::ranges::views::reverse; + std::vector rows = filterRows(indices); - std::reverse(rows.begin(), rows.end()); - - for (int row : rows) + for (int row : rows | reverse) removeRow(row); } void ListModelEditorModel::removeRow(int row) { - QList rowItems = QStandardItemModel::takeRow(row); + QList rowItems = Super::takeRow(row); if (rowItems.size()) static_cast(rowItems.front())->node.destroy(); @@ -314,7 +328,7 @@ void ListModelEditorModel::renameColumn(int oldColumn, const QString &newColumnN { const PropertyName newPropertyName = newColumnName.toUtf8(); - auto found = std::lower_bound(m_propertyNames.begin(), m_propertyNames.end(), newPropertyName); + auto found = std::ranges::lower_bound(m_propertyNames, newPropertyName); if (found != m_propertyNames.end() && *found == newPropertyName) return; @@ -358,6 +372,8 @@ QItemSelection ListModelEditorModel::moveRowsUp(const QList &indice QItemSelection ListModelEditorModel::moveRowsDown(const QList &indices) { + using std::ranges::views::reverse; + std::vector rows = filterRows(indices); if (rows.empty() || rows.back() >= (rowCount() - 1)) @@ -365,29 +381,35 @@ QItemSelection ListModelEditorModel::moveRowsDown(const QList &indi auto nodeListProperty = m_listModelNode.defaultNodeListProperty(); - std::reverse(rows.begin(), rows.end()); - - for (int row : rows) { + for (int row : rows | reverse) { insertRow(row + 1, takeRow(row)); nodeListProperty.slide(row, row + 1); } - return {index(rows.front() + 1, 0), index(rows.back() + 1, columnCount() - 1)}; + return {index(rows.back() + 1, 0), index(rows.front() + 1, columnCount() - 1)}; } +namespace { +void removeDuplicates(std::vector &container) +{ + std::ranges::sort(container); + + auto removed = std::ranges::unique(container); + container.erase(removed.begin(), removed.end()); +} +} // namespace + std::vector ListModelEditorModel::filterColumns(const QList &indices) { std::vector columns; - columns.reserve(indices.size()); + columns.reserve(Utils::usize(indices)); for (QModelIndex index : indices) { if (index.column() >= 0) columns.push_back(index.column()); } - std::sort(columns.begin(), columns.end()); - - columns.erase(std::unique(columns.begin(), columns.end()), columns.end()); + removeDuplicates(columns); return columns; } @@ -395,18 +417,39 @@ std::vector ListModelEditorModel::filterColumns(const QList &i std::vector ListModelEditorModel::filterRows(const QList &indices) { std::vector rows; - rows.reserve(indices.size()); + rows.reserve(Utils::usize(indices)); for (QModelIndex index : indices) { if (index.row() >= 0) rows.push_back(index.row()); } - std::sort(rows.begin(), rows.end()); - - rows.erase(std::unique(rows.begin(), rows.end()), rows.end()); + removeDuplicates(rows); return rows; } +static int interactionRow(const QItemSelectionModel &selectionModel, + QModelIndex &(QModelIndexList::*defaultRowSelector)()) +{ + QModelIndexList selectedRows = selectionModel.selectedRows(); + auto defaultRow = std::mem_fn(defaultRowSelector); + int index = !selectedRows.isEmpty() ? defaultRow(selectedRows).row() : -1; + if (index < 0 && selectionModel.hasSelection()) + index = defaultRow(selectionModel.selectedIndexes()).row(); + if (index < 0 && selectionModel.currentIndex().isValid()) + index = selectionModel.currentIndex().row(); + return index; +} + +int ListModelEditorModel::currentInteractionRow(const QItemSelectionModel &selectionModel) +{ + return interactionRow(selectionModel, &QModelIndexList::first); +} + +int ListModelEditorModel::nextInteractionRow(const QItemSelectionModel &selectionModel) +{ + return interactionRow(selectionModel, &QModelIndexList::last) + 1; +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h index 049c7e888d2..017d8acb334 100644 --- a/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h +++ b/src/plugins/qmldesigner/components/listmodeleditor/listmodeleditormodel.h @@ -12,8 +12,9 @@ namespace QmlDesigner { class ListModelEditorModel : public QStandardItemModel { - using QStandardItemModel::removeColumns; - using QStandardItemModel::removeRows; + using Super = QStandardItemModel; + using Super::removeColumns; + using Super::removeRows; public: ListModelEditorModel(std::function createModelCallback, @@ -28,7 +29,7 @@ public: void setListView(ModelNode listView); - void addRow(); + void addRow(int rowIndex); void addColumn(const QString &columnName); const QList &propertyNames() const { return m_propertyNames; } @@ -44,11 +45,15 @@ public: static std::vector filterColumns(const QList &indices); static std::vector filterRows(const QList &indices); + static int currentInteractionRow(const QItemSelectionModel &selectionModel); + static int nextInteractionRow(const QItemSelectionModel &selectionModel); + private: void removeRow(int row); void removeColumn(int column); void populateModel(); void createItems(const QList &listElementNodes); + void insertItems(const ModelNode &listElementNode, int index); void appendItems(const ModelNode &listElementNode); private: diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 3592066e125..cd3aed74ebe 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -46,6 +46,11 @@ static bool isTexture(const ModelNode &node) return node.metaInfo().isQtQuick3DTexture(); } +static bool isModel3D(const ModelNode &node) +{ + return node.metaInfo().isQtQuick3DModel(); +} + static QString propertyEditorResourcesPath() { #ifdef SHARE_QML_PATH @@ -354,8 +359,10 @@ void MaterialBrowserView::selectedNodesChanged([[maybe_unused]] const QListmaterialBrowserModel()->notifySelectionChanges(selectedMaterials, deselectedMaterials); - m_widget->materialBrowserModel()->setHasModelSelection(!selectedMaterials.isEmpty()); + m_widget->materialBrowserModel()->setHasModelSelection(!selectedModels.isEmpty()); m_widget->materialBrowserTexturesModel()->notifySelectionChanges(selectedTextures, deselectedTextures); diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp index 7bf78f4b129..332e943ec03 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorview.cpp @@ -8,12 +8,13 @@ #include "propertyeditorvalue.h" #include "propertyeditorwidget.h" +#include "qmldesignerplugin.h" #include #include #include +#include #include #include -#include "qmldesignerplugin.h" #include #include @@ -863,11 +864,16 @@ void PropertyEditorView::nodeAboutToBeRemoved(const ModelNode &removedNode) const ModelNodes &allRemovedNodes = removedNode.allSubModelNodesAndThisNode(); - if (Utils::contains(allRemovedNodes, model()->qtQuick3DTextureMetaInfo(), &ModelNode::metaInfo)) + using SL = ModelTracing::SourceLocation; + if (Utils::contains(allRemovedNodes, + model()->qtQuick3DTextureMetaInfo(), + bind_back(&ModelNode::metaInfo, SL{}))) m_textureAboutToBeRemoved = true; if (m_qmlBackEndForCurrentType) { - if (Utils::contains(allRemovedNodes, QLatin1String{Constants::MATERIAL_LIB_ID}, &ModelNode::id)) + if (Utils::contains(allRemovedNodes, + QLatin1String{Constants::MATERIAL_LIB_ID}, + bind_back(&ModelNode::id, SL{}))) m_qmlBackEndForCurrentType->contextObject()->setHasMaterialLibrary(false); } } @@ -890,6 +896,7 @@ void PropertyEditorView::modelAttached(Model *model) if (debug) qDebug() << Q_FUNC_INFO; + resetSelectionLocked(); resetView(); } @@ -1261,12 +1268,17 @@ void PropertyEditorView::nodeReparented(const ModelNode &node, if (node == activeNode()) m_qmlBackEndForCurrentType->backendAnchorBinding().setup(QmlItemNode(activeNode())); + using SL = const ModelTracing::SourceLocation; const ModelNodes &allNodes = node.allSubModelNodesAndThisNode(); - if (Utils::contains(allNodes, model()->qtQuick3DTextureMetaInfo(), &ModelNode::metaInfo)) + if (Utils::contains(allNodes, + model()->qtQuick3DTextureMetaInfo(), + bind_back(&ModelNode::metaInfo, SL{}))) m_qmlBackEndForCurrentType->refreshBackendModel(); if (m_qmlBackEndForCurrentType) { - if (Utils::contains(allNodes, QLatin1String{Constants::MATERIAL_LIB_ID}, &ModelNode::id)) + if (Utils::contains(allNodes, + QLatin1String{Constants::MATERIAL_LIB_ID}, + bind_back(&ModelNode::id, SL{}))) m_qmlBackEndForCurrentType->contextObject()->setHasMaterialLibrary(true); } } diff --git a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp index 07c7537c852..1f51e37ec7e 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/qmlmodelnodeproxy.cpp @@ -120,7 +120,7 @@ QString QmlModelNodeProxy::simplifiedTypeName() const static QList toInternalIdList(const QList &nodes) { - return Utils::transform(nodes, &ModelNode::internalId); + return Utils::transform(nodes, [](const ModelNode &node) { return node.internalId(); }); } QList QmlModelNodeProxy::allChildren(int internalId) const diff --git a/src/plugins/qmldesigner/components/scripteditor/propertytreemodel.cpp b/src/plugins/qmldesigner/components/scripteditor/propertytreemodel.cpp index cb9ddfe9602..78d0373430c 100644 --- a/src/plugins/qmldesigner/components/scripteditor/propertytreemodel.cpp +++ b/src/plugins/qmldesigner/components/scripteditor/propertytreemodel.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -904,7 +905,8 @@ void PropertyTreeModelDelegate::setPropertyType(PropertyTreeModel::PropertyTypes void PropertyTreeModelDelegate::setup(const QString &id, const QString &name, bool *nameExists) { m_model.resetModel(); - QStringList idLists = Utils::transform(m_model.nodeList(), &ModelNode::id); + using SL = ModelTracing::SourceLocation; + QStringList idLists = Utils::transform(m_model.nodeList(), bind_back(&ModelNode::id, SL{})); if (!idLists.contains(id)) idLists.prepend(id); diff --git a/src/plugins/qmldesigner/components/scripteditor/scripteditorbackend.cpp b/src/plugins/qmldesigner/components/scripteditor/scripteditorbackend.cpp index 3bf324336b6..ae232fc8262 100644 --- a/src/plugins/qmldesigner/components/scripteditor/scripteditorbackend.cpp +++ b/src/plugins/qmldesigner/components/scripteditor/scripteditorbackend.cpp @@ -6,6 +6,7 @@ #include "scripteditorutils.h" #include +#include #include #include #include @@ -842,13 +843,14 @@ void StatementDelegate::setupChangeState() && !item.allStateNames().isEmpty(); }); - QStringList itemIds = Utils::transform(items, &ModelNode::id); + using SL = ModelTracing::SourceLocation; + QStringList itemIds = Utils::transform(items, bind_back(&ModelNode::id, SL{})); const auto groups = m_view->allModelNodesOfType(model->qtQuickStateGroupMetaInfo()); const auto rootId = m_view->rootModelNode().id(); itemIds.removeAll(rootId); - QStringList groupIds = Utils::transform(groups, &ModelNode::id); + QStringList groupIds = Utils::transform(groups, bind_back(&ModelNode::id, SL{})); Utils::sort(itemIds); Utils::sort(groupIds); diff --git a/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp b/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp index df969197d9a..680082b5419 100644 --- a/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp +++ b/src/plugins/qmldesigner/components/stateseditor/stateseditormodel.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -276,8 +277,9 @@ QStringList StatesEditorModel::stateGroups() const const auto groupMetaInfo = m_statesEditorView->model()->qtQuickStateGroupMetaInfo(); + using SL = ModelTracing::SourceLocation; auto stateGroups = Utils::transform(m_statesEditorView->allModelNodesOfType(groupMetaInfo), - &ModelNode::displayName); + bind_back(&ModelNode::displayName, SL{})); stateGroups.prepend(tr("Default")); return stateGroups; } diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp index e204c0ad4a0..b680572b740 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinetoolbar.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #include "timelinetoolbar.h" +#include #include "timelineconstants.h" #include "timelinegraphicsscene.h" @@ -132,7 +133,7 @@ QString TimelineToolBar::currentTimelineId() const void TimelineToolBar::setCurrentState(const QString &name) { if (name.isEmpty()) - m_stateLabel->setText(tr("Base State")); + m_stateLabel->setText(Tr::tr("Base State")); else m_stateLabel->setText(name); } @@ -191,9 +192,9 @@ void TimelineToolBar::setIsMcu(bool isMcu) { m_curvePicker->setDisabled(isMcu); if (isMcu) - m_curvePicker->setText(tr("Not Supported for MCUs")); + m_curvePicker->setText(Tr::tr("Not Supported for MCUs")); else - m_curvePicker->setText(tr(m_curveEditorName)); + m_curvePicker->setText(Tr::tr(m_curveEditorName)); } void TimelineToolBar::setActionEnabled(const QString &name, bool enabled) @@ -232,7 +233,7 @@ void TimelineToolBar::createLeftControls() auto *settingsAction = createAction(TimelineConstants::C_SETTINGS, Theme::iconFromName(Theme::Icon::settings_medium), - tr("Timeline Settings"), + Tr::tr("Timeline Settings"), QKeySequence(Qt::Key_S)); connect(settingsAction, &QAction::triggered, this, &TimelineToolBar::settingDialogClicked); @@ -267,7 +268,7 @@ void TimelineToolBar::createCenterControls() auto *toStart = createAction(TimelineConstants::C_TO_START, Theme::iconFromName(Theme::Icon::toStartFrame_medium), - tr("To Start"), + Tr::tr("Start Frame"), QKeySequence(Qt::Key_Home)); connect(toStart, &QAction::triggered, this, &TimelineToolBar::toFirstFrameTriggered); @@ -277,7 +278,7 @@ void TimelineToolBar::createCenterControls() auto *previous = createAction(TimelineConstants::C_PREVIOUS, Theme::iconFromName(Theme::Icon::toPrevFrame_medium), - tr("Previous"), + Tr::tr("Previous Frame"), QKeySequence(Qt::Key_Comma)); connect(previous, &QAction::triggered, this, &TimelineToolBar::previousFrameTriggered); @@ -292,7 +293,7 @@ void TimelineToolBar::createCenterControls() m_playing = createAction(TimelineConstants::C_PLAY, playbackIcon, - tr("Play"), + Tr::tr("Play"), QKeySequence(Qt::Key_Space)); m_playing->setCheckable(true); connect(m_playing, &QAction::triggered, this, &TimelineToolBar::playTriggered); @@ -302,7 +303,7 @@ void TimelineToolBar::createCenterControls() auto *next = createAction(TimelineConstants::C_NEXT, Theme::iconFromName(Theme::Icon::toNextFrame_medium), - tr("Next"), + Tr::tr("Next Frame"), QKeySequence(Qt::Key_Period)); connect(next, &QAction::triggered, this, &TimelineToolBar::nextFrameTriggered); @@ -312,7 +313,7 @@ void TimelineToolBar::createCenterControls() auto *toEnd = createAction(TimelineConstants::C_TO_END, Theme::iconFromName(Theme::Icon::toEndFrame_medium), - tr("To End"), + Tr::tr("End Frame"), QKeySequence(Qt::Key_End)); connect(toEnd, &QAction::triggered, this, &TimelineToolBar::toLastFrameTriggered); @@ -327,7 +328,7 @@ void TimelineToolBar::createCenterControls() // TODO: Toggles looping. Select shortcut for this QDS-4941 auto *loopAnimation = createAction(TimelineConstants::C_LOOP_PLAYBACK, Theme::iconFromName(Theme::Icon::loopPlayback_medium), - tr("Loop Playback"), + Tr::tr("Loop Playback"), Qt::ControlModifier | Qt::ShiftModifier | Qt::Key_Space); loopAnimation->setCheckable(true); @@ -340,7 +341,7 @@ void TimelineToolBar::createCenterControls() m_animationPlaybackSpeed = createToolBarLineEdit(this); LineEditDoubleValidator *validator = new LineEditDoubleValidator(0.1, 100.0, 1, m_animationPlaybackSpeed); m_animationPlaybackSpeed->setValidator(validator); - m_animationPlaybackSpeed->setToolTip(tr("Playback Speed")); + m_animationPlaybackSpeed->setToolTip(Tr::tr("Playback Speed")); addWidget(m_animationPlaybackSpeed); auto emitPlaybackSpeedChanged = [this, validator]() { @@ -356,6 +357,7 @@ void TimelineToolBar::createCenterControls() addSeparator(); m_currentFrame = createToolBarLineEdit(this); + m_currentFrame->setToolTip(Tr::tr("Timeline Current Frame")); addWidget(m_currentFrame); auto emitCurrentChanged = [this] { emit currentFrameChanged(m_currentFrame->text().toInt()); }; @@ -372,7 +374,7 @@ void TimelineToolBar::createCenterControls() m_recording = createAction(TimelineConstants::C_AUTO_KEYFRAME, autoKeyIcon, - tr("Auto Key"), + Tr::tr("Auto Key"), QKeySequence(Qt::Key_K)); m_recording->setCheckable(true); @@ -387,9 +389,9 @@ void TimelineToolBar::createCenterControls() addSpacing(10); m_curvePicker = createAction(TimelineConstants::C_CURVE_PICKER, - Theme::iconFromName(Theme::Icon::curveDesigner_medium), - tr(m_curveEditorName), - QKeySequence(Qt::Key_C)); + Theme::iconFromName(Theme::Icon::curveDesigner_medium), + Tr::tr(m_curveEditorName), + QKeySequence(Qt::Key_C)); m_curvePicker->setObjectName("Easing Curve Editor"); connect(m_curvePicker, &QAction::triggered, this, &TimelineToolBar::openEasingCurveEditor); @@ -416,6 +418,7 @@ void TimelineToolBar::createRightControls() addSeparator(); m_firstFrame = createToolBarLineEdit(this); + m_firstFrame->setToolTip(Tr::tr("Timeline First Frame")); addWidget(m_firstFrame); auto emitStartChanged = [this] { emit startFrameChanged(m_firstFrame->text().toInt()); }; @@ -427,7 +430,7 @@ void TimelineToolBar::createRightControls() auto *zoomOut = createAction(TimelineConstants::C_ZOOM_OUT, Theme::iconFromName(Theme::Icon::zoomOut_medium), - tr("Zoom Out"), + Tr::tr("Zoom Out"), QKeySequence(QKeySequence::ZoomOut)); connect(zoomOut, &QAction::triggered, [this] { @@ -454,7 +457,7 @@ void TimelineToolBar::createRightControls() auto *zoomIn = createAction(TimelineConstants::C_ZOOM_IN, Theme::iconFromName(Theme::Icon::zoomIn_medium), - tr("Zoom In"), + Tr::tr("Zoom In"), QKeySequence(QKeySequence::ZoomIn)); connect(zoomIn, &QAction::triggered, [this] { @@ -467,6 +470,7 @@ void TimelineToolBar::createRightControls() addSeparator(); m_lastFrame = createToolBarLineEdit(this); + m_lastFrame->setToolTip(Tr::tr("Timeline Last Frame")); addWidget(m_lastFrame); auto emitEndChanged = [this] { emit endFrameChanged(m_lastFrame->text().toInt()); }; diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp index 1569e4df949..822783144c4 100644 --- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp +++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp @@ -853,6 +853,8 @@ int ToolBarBackend::currentStyle() const QStringList ToolBarBackend::kits() const { + if (!ProjectExplorer::KitManager::isLoaded()) + return {}; auto kits = Utils::filtered(ProjectExplorer::KitManager::kits(), [](ProjectExplorer::Kit *kit) { const auto qtVersion = QtSupport::QtKitAspect::qtVersion(kit); const auto dev = ProjectExplorer::RunDeviceKitAspect::device(kit); diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorsettingsdialog.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorsettingsdialog.cpp index b57a2b4e6de..375eb974f63 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorsettingsdialog.cpp +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorsettingsdialog.cpp @@ -132,8 +132,10 @@ void TransitionEditorSettingsDialog::setupTransitions(const ModelNode &newTransi return; } - for (const auto &transition : transitions) + for (const auto &transition : transitions) { + transition.ensureIdExists(); addTransitionTab(transition); + } if (newTransition.isValid()) { m_currentTransition = newTransition; @@ -146,8 +148,10 @@ void TransitionEditorSettingsDialog::setupTransitions(const ModelNode &newTransi void TransitionEditorSettingsDialog::addTransitionTab(const QmlTimeline &node) { + QTC_ASSERT(node.modelNode().hasId(), return); + auto transitionForm = new TransitionForm(this); - ui->timelineTab->addTab(transitionForm, node.modelNode().displayName()); + ui->timelineTab->addTab(transitionForm, node.modelNode().id()); transitionForm->setTransition(node); connect(transitionForm, &TransitionForm::stateGroupChanged, this, [this](const ModelNode &transition, const ModelNode &stateGroup){ diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitionform.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitionform.cpp index 683cdd8cfe1..120cfee28e1 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitionform.cpp +++ b/src/plugins/qmldesigner/components/transitioneditor/transitionform.cpp @@ -7,13 +7,14 @@ #include #include +#include #include +#include #include #include +#include #include #include -#include -#include #include @@ -220,8 +221,9 @@ void TransitionForm::setupStateGroups() const auto groupMetaInfo = view->model()->qtQuickStateGroupMetaInfo(); + using SL = ModelTracing::SourceLocation; auto stateGroups = Utils::transform(view->allModelNodesOfType(groupMetaInfo), - &ModelNode::displayName); + bind_back(&ModelNode::displayName, SL{})); stateGroups.prepend(tr("Default")); bool block = ui->stateGroupComboBox->blockSignals(true); diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp index b7835ed5688..64f88509f69 100644 --- a/src/plugins/qmldesigner/designmodewidget.cpp +++ b/src/plugins/qmldesigner/designmodewidget.cpp @@ -331,6 +331,8 @@ void DesignModeWidget::setup() viewCommands.append(command); } + viewManager().initializeWidgetInfos(); + // Afterwards get all the other widgets for (const auto &view : viewManager().views()) { if (!view->hasWidget()) diff --git a/src/plugins/qmldesigner/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/instances/nodeinstanceview.cpp index 6a16f65d83a..776541ec5ca 100644 --- a/src/plugins/qmldesigner/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/instances/nodeinstanceview.cpp @@ -1811,12 +1811,12 @@ void NodeInstanceView::handlePuppetToCreatorCommand(const PuppetToCreatorCommand const auto sceneState = qvariant_cast(command.data()); if (isAttached()) model()->emitUpdateActiveScene3D(this, sceneState); - } else if (command.type() == PuppetToCreatorCommand::ActiveSplitChanged) { - // Active split change is a special case of active scene change - QVariantMap splitState; - splitState.insert("activeSplit", command.data()); + } else if (command.type() == PuppetToCreatorCommand::ActiveViewportChanged) { + // Active viewport change is a special case of active scene change + QVariantMap viewportState; + viewportState.insert("activeViewport", command.data()); if (isAttached()) - model()->emitUpdateActiveScene3D(this, splitState); + model()->emitUpdateActiveScene3D(this, viewportState); } else if (command.type() == PuppetToCreatorCommand::RenderModelNodePreviewImage) { ImageContainer container = qvariant_cast(command.data()); QImage image = container.image(); diff --git a/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt b/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt index 1d749ad697b..3a7196d412a 100644 --- a/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt +++ b/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt @@ -243,6 +243,8 @@ extend_qtc_library(QmlDesignerCore stringutils.h synchronousimagecache.h variantproperty.h + widgetregistration.h + widgetinfo.h ) extend_qtc_library(QmlDesignerCore @@ -392,6 +394,7 @@ extend_qtc_library(QmlDesignerCore projectstorageinfotypes.h projectstorageobserver.h projectstoragepathwatcher.h + projectstoragetriggerupdateinterface.h projectstoragepathwatcherinterface.h projectstoragepathwatchernotifierinterface.h projectstoragepathwatcher.h diff --git a/src/plugins/qmldesigner/libs/designercore/designercoreutils/functional.h b/src/plugins/qmldesigner/libs/designercore/designercoreutils/functional.h index 66a0485c2f4..2c7d52738b1 100644 --- a/src/plugins/qmldesigner/libs/designercore/designercoreutils/functional.h +++ b/src/plugins/qmldesigner/libs/designercore/designercoreutils/functional.h @@ -29,4 +29,9 @@ inline constexpr auto makeEqual = [](auto... projections) { }; }; +template +inline constexpr auto bind_back(Function &&function, Argument &&argument) +{ + return std::bind(function, std::placeholders::_1, std::forward(argument)); +} } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/libs/designercore/filemanager/addobjectvisitor.cpp b/src/plugins/qmldesigner/libs/designercore/filemanager/addobjectvisitor.cpp index 2edb8d8fcab..873a77f8cff 100644 --- a/src/plugins/qmldesigner/libs/designercore/filemanager/addobjectvisitor.cpp +++ b/src/plugins/qmldesigner/libs/designercore/filemanager/addobjectvisitor.cpp @@ -10,9 +10,9 @@ using namespace QmlDesigner::Internal; AddObjectVisitor::AddObjectVisitor(QmlDesigner::TextModifier &modifier, quint32 parentLocation, - quint32 nodeLocation, + std::optional nodeLocation, const QString &content, - const PropertyNameList &propertyOrder) + Utils::span propertyOrder) : QMLRewriter(modifier) , m_parentLocation(parentLocation) , m_nodeLocation(nodeLocation) @@ -46,9 +46,11 @@ bool AddObjectVisitor::visit(QmlJS::AST::UiObjectDefinition *ast) // FIXME: duplicate code in the QmlJS::Rewriter class, remove this void AddObjectVisitor::insertInto(QmlJS::AST::UiObjectInitializer *ast) { - QmlJS::AST::UiObjectMemberList *insertAfter = searchChildrenToInsertAfter(ast->members, - m_propertyOrder, - m_nodeLocation - 1); + QmlJS::AST::UiObjectMemberList *insertAfter; + if (m_nodeLocation.has_value()) + insertAfter = searchChildrenToInsertAfter(ast->members, m_propertyOrder, *m_nodeLocation - 1); + else + insertAfter = searchMemberToInsertAfter(ast->members, m_propertyOrder); int insertionPoint; int depth; diff --git a/src/plugins/qmldesigner/libs/designercore/filemanager/addobjectvisitor.h b/src/plugins/qmldesigner/libs/designercore/filemanager/addobjectvisitor.h index b74a7c7d5bb..02b3dffc870 100644 --- a/src/plugins/qmldesigner/libs/designercore/filemanager/addobjectvisitor.h +++ b/src/plugins/qmldesigner/libs/designercore/filemanager/addobjectvisitor.h @@ -13,9 +13,9 @@ class AddObjectVisitor: public QMLRewriter public: AddObjectVisitor(QmlDesigner::TextModifier &modifier, quint32 parentLocation, - quint32 nodeLocation, + std::optional nodeLocation, const QString &content, - const PropertyNameList &propertyOrder); + Utils::span propertyOrder); protected: bool visit(QmlJS::AST::UiObjectBinding *ast) override; @@ -26,9 +26,9 @@ private: private: quint32 m_parentLocation; - quint32 m_nodeLocation; + std::optional m_nodeLocation; QString m_content; - PropertyNameList m_propertyOrder; + Utils::span m_propertyOrder; }; } // namespace Internal diff --git a/src/plugins/qmldesigner/libs/designercore/filemanager/addpropertyvisitor.cpp b/src/plugins/qmldesigner/libs/designercore/filemanager/addpropertyvisitor.cpp index 76b36d16cd6..17ae83d782f 100644 --- a/src/plugins/qmldesigner/libs/designercore/filemanager/addpropertyvisitor.cpp +++ b/src/plugins/qmldesigner/libs/designercore/filemanager/addpropertyvisitor.cpp @@ -13,7 +13,7 @@ AddPropertyVisitor::AddPropertyVisitor(TextModifier &modifier, PropertyNameView name, const QString &value, QmlRefactoring::PropertyType propertyType, - const PropertyNameList &propertyOrder, + Utils::span propertyOrder, const TypeName &dynamicTypeName) : QMLRewriter(modifier) , m_parentLocation(parentLocation) diff --git a/src/plugins/qmldesigner/libs/designercore/filemanager/addpropertyvisitor.h b/src/plugins/qmldesigner/libs/designercore/filemanager/addpropertyvisitor.h index 4710ecfb54d..8a1ca4158d3 100644 --- a/src/plugins/qmldesigner/libs/designercore/filemanager/addpropertyvisitor.h +++ b/src/plugins/qmldesigner/libs/designercore/filemanager/addpropertyvisitor.h @@ -18,7 +18,7 @@ public: PropertyNameView name, const QString &value, QmlRefactoring::PropertyType propertyType, - const PropertyNameList &propertyOrder, + Utils::span propertyOrder, const TypeName &dynamicTypeName); protected: @@ -33,7 +33,7 @@ private: PropertyNameView m_name; QString m_value; QmlRefactoring::PropertyType m_propertyType; - PropertyNameList m_propertyOrder; + Utils::span m_propertyOrder; TypeName m_dynamicTypeName; }; diff --git a/src/plugins/qmldesigner/libs/designercore/filemanager/moveobjectvisitor.cpp b/src/plugins/qmldesigner/libs/designercore/filemanager/moveobjectvisitor.cpp index 73165b3f14f..c3ac04a64bb 100644 --- a/src/plugins/qmldesigner/libs/designercore/filemanager/moveobjectvisitor.cpp +++ b/src/plugins/qmldesigner/libs/designercore/filemanager/moveobjectvisitor.cpp @@ -21,7 +21,7 @@ public: PropertyNameView targetPropertyName, bool targetIsArrayBinding, TextModifier::MoveInfo moveInfo, - const PropertyNameList &propertyOrder) + Utils::span propertyOrder) : QMLRewriter(modifier) , targetParentObjectLocation(targetParentObjectLocation) , targetPropertyName(targetPropertyName) @@ -127,7 +127,7 @@ private: PropertyNameView targetPropertyName; bool targetIsArrayBinding; TextModifier::MoveInfo moveInfo; - PropertyNameList propertyOrder; + Utils::span propertyOrder; }; MoveObjectVisitor::MoveObjectVisitor(TextModifier &modifier, @@ -135,7 +135,7 @@ MoveObjectVisitor::MoveObjectVisitor(TextModifier &modifier, PropertyNameView targetPropertyName, bool targetIsArrayBinding, quint32 targetParentObjectLocation, - const PropertyNameList &propertyOrder) + Utils::span propertyOrder) : QMLRewriter(modifier) , objectLocation(objectLocation) , targetPropertyName(targetPropertyName) diff --git a/src/plugins/qmldesigner/libs/designercore/filemanager/moveobjectvisitor.h b/src/plugins/qmldesigner/libs/designercore/filemanager/moveobjectvisitor.h index 5619261b540..68f61b5342f 100644 --- a/src/plugins/qmldesigner/libs/designercore/filemanager/moveobjectvisitor.h +++ b/src/plugins/qmldesigner/libs/designercore/filemanager/moveobjectvisitor.h @@ -16,7 +16,7 @@ public: PropertyNameView targetPropertyName, bool targetIsArrayBinding, quint32 targetParentObjectLocation, - const PropertyNameList &propertyOrder); + Utils::span propertyOrder); bool operator ()(QmlJS::AST::UiProgram *ast) override; @@ -34,7 +34,7 @@ private: PropertyNameView targetPropertyName; bool targetIsArrayBinding; quint32 targetParentObjectLocation; - PropertyNameList propertyOrder; + Utils::span propertyOrder; QmlJS::AST::UiProgram *program; }; diff --git a/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrefactoring.cpp b/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrefactoring.cpp index d71cf854e67..cf80b3d0e01 100644 --- a/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrefactoring.cpp +++ b/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrefactoring.cpp @@ -20,10 +20,12 @@ using namespace QmlJS; using namespace QmlDesigner; using namespace QmlDesigner::Internal; -QmlRefactoring::QmlRefactoring(const Document::Ptr &doc, TextModifier &modifier, const PropertyNameList &propertyOrder): - qmlDocument(doc), - textModifier(&modifier), - m_propertyOrder(propertyOrder) +QmlRefactoring::QmlRefactoring(const Document::Ptr &doc, + TextModifier &modifier, + Utils::span propertyOrder) + : qmlDocument(doc) + , textModifier(&modifier) + , m_propertyOrder(propertyOrder) { } @@ -75,7 +77,9 @@ bool QmlRefactoring::addToArrayMemberList(int parentLocation, return visit(qmlDocument->qmlProgram()); } -bool QmlRefactoring::addToObjectMemberList(int parentLocation, int nodeLocation, const QString &content) +bool QmlRefactoring::addToObjectMemberList(int parentLocation, + std::optional nodeLocation, + const QString &content) { if (parentLocation < 0) return false; diff --git a/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrefactoring.h b/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrefactoring.h index 34894eb76f8..7d6bae12cc0 100644 --- a/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrefactoring.h +++ b/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrefactoring.h @@ -25,7 +25,9 @@ public: }; public: - QmlRefactoring(const QmlJS::Document::Ptr &doc, QmlDesigner::TextModifier &modifier, const PropertyNameList &propertyOrder); + QmlRefactoring(const QmlJS::Document::Ptr &doc, + QmlDesigner::TextModifier &modifier, + Utils::span propertyOrder); bool reparseDocument(); @@ -33,7 +35,9 @@ public: bool removeImport(const Import &import); bool addToArrayMemberList(int parentLocation, PropertyNameView propertyName, const QString &content); - bool addToObjectMemberList(int parentLocation, int nodeLocation, const QString &content); + bool addToObjectMemberList(int parentLocation, + std::optional nodeLocation, + const QString &content); bool addProperty(int parentLocation, PropertyNameView name, const QString &value, @@ -57,7 +61,7 @@ public: private: QmlJS::Document::Ptr qmlDocument; TextModifier *textModifier; - PropertyNameList m_propertyOrder; + Utils::span m_propertyOrder; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrewriter.cpp b/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrewriter.cpp index 77021f02324..43345537685 100644 --- a/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrewriter.cpp +++ b/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrewriter.cpp @@ -197,10 +197,23 @@ void QMLRewriter::includeLeadingEmptyLine(int &start) const start = prevBlock.position(); } -// FIXME: duplicate code in the QmlJS::Rewriter class, remove this -QmlJS::AST::UiObjectMemberList *QMLRewriter::searchMemberToInsertAfter(QmlJS::AST::UiObjectMemberList *members, const QmlDesigner::PropertyNameList &propertyOrder) +namespace { +int indexOf(Utils::span properties, + QmlDesigner::PropertyNameView name) { - const int objectDefinitionInsertionPoint = propertyOrder.indexOf(PropertyName()); // XXX ???? + auto found = std::ranges::find(properties, name); + if (found == properties.end()) + return -1; + + return static_cast(std::distance(properties.begin(), found)); +} +} // namespace + +// FIXME: duplicate code in the QmlJS::Rewriter class, remove this +QmlJS::AST::UiObjectMemberList *QMLRewriter::searchMemberToInsertAfter( + QmlJS::AST::UiObjectMemberList *members, Utils::span propertyOrder) +{ + const int objectDefinitionInsertionPoint = indexOf(propertyOrder, ""); // XXX ???? QmlJS::AST::UiObjectMemberList *lastObjectDef = nullptr; QmlJS::AST::UiObjectMemberList *lastNonObjectDef = nullptr; @@ -212,13 +225,13 @@ QmlJS::AST::UiObjectMemberList *QMLRewriter::searchMemberToInsertAfter(QmlJS::AS if (QmlJS::AST::cast(member)) lastObjectDef = iter; else if (auto arrayBinding = QmlJS::AST::cast(member)) - idx = propertyOrder.indexOf(toString(arrayBinding->qualifiedId).toUtf8()); + idx = indexOf(propertyOrder, toString(arrayBinding->qualifiedId).toUtf8()); else if (auto objectBinding = QmlJS::AST::cast(member)) - idx = propertyOrder.indexOf(toString(objectBinding->qualifiedId).toUtf8()); + idx = indexOf(propertyOrder, toString(objectBinding->qualifiedId).toUtf8()); else if (auto scriptBinding = QmlJS::AST::cast(member)) - idx = propertyOrder.indexOf(toString(scriptBinding->qualifiedId).toUtf8()); + idx = indexOf(propertyOrder, toString(scriptBinding->qualifiedId).toUtf8()); else if (QmlJS::AST::cast(member)) - idx = propertyOrder.indexOf("property"); + idx = indexOf(propertyOrder, "property"); if (idx < objectDefinitionInsertionPoint) lastNonObjectDef = iter; @@ -234,7 +247,7 @@ QmlJS::AST::UiObjectMemberList *QMLRewriter::searchMemberToInsertAfter(QmlJS::AS QmlJS::AST::UiObjectMemberList *QMLRewriter::searchMemberToInsertAfter( QmlJS::AST::UiObjectMemberList *members, PropertyNameView propertyName, - const QmlDesigner::PropertyNameList &propertyOrder) + Utils::span propertyOrder) { if (!members) return nullptr; // empty members @@ -256,15 +269,15 @@ QmlJS::AST::UiObjectMemberList *QMLRewriter::searchMemberToInsertAfter( orderedMembers[QStringLiteral("property")] = iter; } - int idx = propertyOrder.indexOf(propertyName); + int idx = indexOf(propertyOrder, propertyName); if (idx == -1) - idx = propertyOrder.indexOf(PropertyName()); + idx = indexOf(propertyOrder, ""); if (idx == -1) - idx = propertyOrder.size() - 1; + idx = static_cast(propertyOrder.size()) - 1; for (; idx > 0; --idx) { - const QString prop = QString::fromLatin1(propertyOrder.at(idx - 1)); - QmlJS::AST::UiObjectMemberList *candidate = orderedMembers.value(prop, 0); + const QString prop = QString::fromLatin1(propertyOrder[static_cast(idx - 1)]); + QmlJS::AST::UiObjectMemberList *candidate = orderedMembers.value(prop, nullptr); if (candidate != nullptr) return candidate; } @@ -273,14 +286,11 @@ QmlJS::AST::UiObjectMemberList *QMLRewriter::searchMemberToInsertAfter( } QmlJS::AST::UiObjectMemberList *QMLRewriter::searchChildrenToInsertAfter( - QmlJS::AST::UiObjectMemberList *members, const PropertyNameList &propertyOrder, int pos) + QmlJS::AST::UiObjectMemberList *members, Utils::span propertyOrder, int pos) { - if (pos < 0) - return searchMemberToInsertAfter(members, propertyOrder); - // An empty property name should be available in the propertyOrder List, which is the right place // to define the objects there. - const int objectDefinitionInsertionPoint = propertyOrder.indexOf(PropertyName()); + const int objectDefinitionInsertionPoint = indexOf(propertyOrder, ""); QmlJS::AST::UiObjectMemberList *lastObjectDef = nullptr; QmlJS::AST::UiObjectMemberList *lastNonObjectDef = nullptr; @@ -291,17 +301,19 @@ QmlJS::AST::UiObjectMemberList *QMLRewriter::searchChildrenToInsertAfter( int idx = -1; if (QmlJS::AST::cast(member)) { + if (pos < 0) + break; lastObjectDef = iter; if (objectPos++ == pos) break; } else if (auto arrayBinding = QmlJS::AST::cast(member)) - idx = propertyOrder.indexOf(toString(arrayBinding->qualifiedId).toUtf8()); + idx = indexOf(propertyOrder, toString(arrayBinding->qualifiedId).toUtf8()); else if (auto objectBinding = QmlJS::AST::cast(member)) - idx = propertyOrder.indexOf(toString(objectBinding->qualifiedId).toUtf8()); + idx = indexOf(propertyOrder, toString(objectBinding->qualifiedId).toUtf8()); else if (auto scriptBinding = QmlJS::AST::cast(member)) - idx = propertyOrder.indexOf(toString(scriptBinding->qualifiedId).toUtf8()); + idx = indexOf(propertyOrder, toString(scriptBinding->qualifiedId).toUtf8()); else if (QmlJS::AST::cast(member)) - idx = propertyOrder.indexOf("property"); + idx = indexOf(propertyOrder, "property"); if (idx < objectDefinitionInsertionPoint) lastNonObjectDef = iter; diff --git a/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrewriter.h b/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrewriter.h index e8486d2eddb..7f860ea3a2e 100644 --- a/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrewriter.h +++ b/src/plugins/qmldesigner/libs/designercore/filemanager/qmlrewriter.h @@ -51,13 +51,16 @@ protected: bool includeSurroundingWhitespace(int &start, int &end) const; void includeLeadingEmptyLine(int &start) const; - static QmlJS::AST::UiObjectMemberList *searchMemberToInsertAfter(QmlJS::AST::UiObjectMemberList *members, const PropertyNameList &propertyOrder); + static QmlJS::AST::UiObjectMemberList *searchMemberToInsertAfter( + QmlJS::AST::UiObjectMemberList *members, Utils::span propertyOrder); static QmlJS::AST::UiObjectMemberList *searchMemberToInsertAfter( QmlJS::AST::UiObjectMemberList *members, PropertyNameView propertyName, - const PropertyNameList &propertyOrder); + Utils::span propertyOrder); static QmlJS::AST::UiObjectMemberList *searchChildrenToInsertAfter( - QmlJS::AST::UiObjectMemberList *members, const PropertyNameList &propertyOrder, int pos = -1); + QmlJS::AST::UiObjectMemberList *members, + Utils::span propertyOrder, + int pos = -1); protected: bool didRewriting() const diff --git a/src/plugins/qmldesigner/libs/designercore/include/abstractview.h b/src/plugins/qmldesigner/libs/designercore/include/abstractview.h index 79f6267162a..0a684162f4d 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/libs/designercore/include/abstractview.h @@ -6,6 +6,8 @@ #include "model.h" #include "modelnode.h" #include "qmldesignercorelib_global.h" +#include "widgetregistration.h" + #include #include @@ -37,30 +39,6 @@ class InternalNode; using InternalNodePointer = std::shared_ptr; } -enum DesignerWidgetFlags { - DisableOnError, - IgnoreErrors -}; - -class WidgetInfo { -public: - enum PlacementHint { - NoPane, - LeftPane, - RightPane, - BottomPane, - TopPane, // not used - CentralPane - }; - - QString uniqueId; - QString tabName; - QString feedbackDisplayName; - QWidget *widget = nullptr; - PlacementHint placementHint; - DesignerWidgetFlags widgetFlags = DesignerWidgetFlags::DisableOnError; -}; - class QMLDESIGNERCORE_EXPORT AbstractViewAction : public QAction { Q_OBJECT @@ -94,6 +72,8 @@ public: , m_action{Utils::makeUniqueObjectPtr(*this)} {} + void setWidgetRegistration(WidgetRegistrationInterface *interface); + virtual void registerWidgetInfo(); ~AbstractView() override; Model *model() const { return m_model.data(); } @@ -245,11 +225,11 @@ public: void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion); void emitCustomNotification(const QString &identifier, - const QList &nodeList = {}, + Utils::span nodes = {}, const QList &data = {}) { if (isAttached()) - model()->emitCustomNotification(this, identifier, nodeList, data); + model()->emitCustomNotification(this, identifier, nodes, data); } const AbstractView *nodeInstanceView() const; @@ -310,6 +290,7 @@ public: protected: void setModel(Model *model); void removeModel(); + static WidgetInfo createWidgetInfo( QWidget *widget = nullptr, const QString &uniqueId = QString(), @@ -319,7 +300,6 @@ protected: DesignerWidgetFlags widgetFlags = DesignerWidgetFlags::DisableOnError); void setKind(Kind kind) { m_kind = kind; } - private: QList toModelNodeList(Utils::span nodeList) const; @@ -329,6 +309,7 @@ private: bool m_visible = true; bool m_isBlockingNotifications = false; Kind m_kind = Kind::Other; + WidgetRegistrationInterface *m_widgetRegistration = nullptr; }; QMLDESIGNERCORE_EXPORT QList toModelNodeList( diff --git a/src/plugins/qmldesigner/libs/designercore/include/import.h b/src/plugins/qmldesigner/libs/designercore/include/import.h index ca9bd010192..ae415e51923 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/import.h +++ b/src/plugins/qmldesigner/libs/designercore/include/import.h @@ -59,7 +59,7 @@ public: || second.m_version.isEmpty()); } - friend auto operator<=>(const Import &first, const Import &second) + friend std::weak_ordering operator<=>(const Import &first, const Import &second) { return std::tie(first.m_url, first.m_type) <=> std::tie(second.m_url, second.m_type); } diff --git a/src/plugins/qmldesigner/libs/designercore/include/model.h b/src/plugins/qmldesigner/libs/designercore/include/model.h index 9ee93be5b09..fe4c5b74a55 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/model.h +++ b/src/plugins/qmldesigner/libs/designercore/include/model.h @@ -148,6 +148,8 @@ public: #endif Module module(Utils::SmallStringView moduleName, Storage::ModuleKind moduleKind); + SmallModuleIds<128> moduleIdsStartsWith(Utils::SmallStringView startsWith, + Storage::ModuleKind kind) const; NodeMetaInfo metaInfo(const TypeName &typeName, int majorVersion = -1, int minorVersion = -1) const; NodeMetaInfo metaInfo(Module module, Utils::SmallStringView typeName, @@ -170,6 +172,7 @@ public: NodeMetaInfo qtQuick3DBakedLightmapMetaInfo() const; NodeMetaInfo qtQuick3DDefaultMaterialMetaInfo() const; NodeMetaInfo qtQuick3DDirectionalLightMetaInfo() const; + NodeMetaInfo qtQuick3DLightMetaInfo() const; NodeMetaInfo qtQuick3DMaterialMetaInfo() const; NodeMetaInfo qtQuick3DModelMetaInfo() const; NodeMetaInfo qtQuick3DNodeMetaInfo() const; @@ -209,6 +212,8 @@ public: #endif QList itemLibraryEntries() const; + QList directoryImportsItemLibraryEntries() const; + QList allItemLibraryEntries() const; void attachView(AbstractView *view); void detachView(AbstractView *view, ViewNotification emitDetachNotify = NotifyView); @@ -261,7 +266,7 @@ public: const QList &warnings); QList selectedNodes(AbstractView *view) const; - void setSelectedModelNodes(const QList &selectedNodeList); + void setSelectedModelNodes(Utils::span selectedNodes); void clearMetaInfoCache(); @@ -281,16 +286,19 @@ public: NotNullPointer projectStorage() const; const PathCacheType &pathCache() const; PathCacheType &pathCache(); + ProjectStorageTriggerUpdateInterface &projectStorageTriggerUpdate() const; + + ProjectStorageDependencies projectStorageDependencies() const; void emitInstancePropertyChange(AbstractView *view, - const QList> &propertyList); - void emitInstanceErrorChange(AbstractView *view, const QVector &instanceIds); - void emitInstancesCompleted(AbstractView *view, const QVector &nodeList); + Utils::span> properties); + void emitInstanceErrorChange(AbstractView *view, Utils::span instanceIds); + void emitInstancesCompleted(AbstractView *view, Utils::span nodes); void emitInstanceInformationsChange( AbstractView *view, const QMultiHash &informationChangeHash); - void emitInstancesRenderImageChanged(AbstractView *view, const QVector &nodeList); - void emitInstancesPreviewImageChanged(AbstractView *view, const QVector &nodeList); - void emitInstancesChildrenChanged(AbstractView *view, const QVector &nodeList); + void emitInstancesRenderImageChanged(AbstractView *view, Utils::span nodes); + void emitInstancesPreviewImageChanged(AbstractView *view, Utils::span nodes); + void emitInstancesChildrenChanged(AbstractView *view, Utils::span nodes); void emitInstanceToken(AbstractView *view, const QString &token, int number, @@ -310,7 +318,7 @@ public: void emitDocumentMessage(const QString &error); void emitCustomNotification(AbstractView *view, const QString &identifier, - const QList &nodeList = {}, + Utils::span nodes = {}, const QList &data = {}); void sendCustomNotificationTo(AbstractView *to, const CustomNotificationPackage &package); diff --git a/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h b/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h index a58e91a838c..a886e2bb9dd 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h +++ b/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h @@ -9,6 +9,8 @@ #include #include +#include + namespace QmlDesigner { using PropertyName = QByteArray; using PropertyNameView = QByteArrayView; @@ -40,7 +42,8 @@ constexpr bool useProjectStorage() #endif } class SourcePathStorage; -using PathCache = SourcePathCache; +class ProjectStorageTriggerUpdateInterface; +using PathCache = SourcePathCache; #ifdef QDS_MODEL_USE_PROJECTSTORAGEINTERFACE using ProjectStorageType = ProjectStorageInterface; @@ -48,13 +51,13 @@ class SourcePathCacheInterface; using PathCacheType = SourcePathCacheInterface; #else using ProjectStorageType = ProjectStorage; -using PathCacheType = SourcePathCache; +using PathCacheType = SourcePathCache; #endif - struct ProjectStorageDependencies { ProjectStorageType &storage; PathCacheType &cache; + ProjectStorageTriggerUpdateInterface &triggerUpdate; }; enum class PropertyType { diff --git a/src/plugins/qmldesigner/libs/designercore/include/modelnode.h b/src/plugins/qmldesigner/libs/designercore/include/modelnode.h index 91f05a4d5ca..5e0661b79bf 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/modelnode.h +++ b/src/plugins/qmldesigner/libs/designercore/include/modelnode.h @@ -3,17 +3,10 @@ #pragma once -#include "auxiliarydata.h" #include "abstractproperty.h" -#include "qmldesignercorelib_global.h" +#include "auxiliarydata.h" -#include -#include -#include -#include - -#include -#include +#include QT_BEGIN_NAMESPACE class QTextStream; @@ -75,6 +68,8 @@ class QMLDESIGNERCORE_EXPORT ModelNode friend NodeAbstractProperty; friend NodeProperty; + using SL = ModelTracing::SourceLocation; + public: enum NodeSourceType { NodeWithoutSource = 0, @@ -91,161 +86,172 @@ public: ModelNode &operator=(ModelNode &&) noexcept = default; ~ModelNode() = default; - TypeName type() const; - QString simplifiedTypeName() const; - QString displayName() const; - int minorVersion() const; - int majorVersion() const; + TypeName type(SL sl = {}) const; + QString simplifiedTypeName(SL sl = {}) const; + QString displayName(SL sl = {}) const; + int minorVersion(SL sl = {}) const; + int majorVersion(SL sl = {}) const; bool isValid() const; + explicit operator bool() const { return isValid(); } - bool isInHierarchy() const; + bool isInHierarchy(SL sl = {}) const; - NodeAbstractProperty parentProperty() const; - void setParentProperty(NodeAbstractProperty parent); - void changeType(const TypeName &typeName, int majorVersion, int minorVersion); - void setParentProperty(const ModelNode &newParentNode, const PropertyName &propertyName); - bool hasParentProperty() const; + NodeAbstractProperty parentProperty(SL sl = {}) const; + void setParentProperty(NodeAbstractProperty parent, SL sl = {}); + void changeType(const TypeName &typeName, int majorVersion = -1, int minorVersion = -1, SL sl = {}); + void setParentProperty(const ModelNode &newParentNode, + const PropertyName &propertyName, + SL sl = {}); + bool hasParentProperty(SL sl = {}) const; - QList directSubModelNodes() const; - QList directSubModelNodesOfType(const NodeMetaInfo &type) const; - QList subModelNodesOfType(const NodeMetaInfo &type) const; + QList directSubModelNodes(SL sl = {}) const; + QList directSubModelNodesOfType(const NodeMetaInfo &type, SL sl = {}) const; + QList subModelNodesOfType(const NodeMetaInfo &type, SL sl = {}) const; - QList allSubModelNodes() const; - QList allSubModelNodesAndThisNode() const; - bool hasAnySubModelNodes() const; + QList allSubModelNodes(SL sl = {}) const; + QList allSubModelNodesAndThisNode(SL sl = {}) const; + bool hasAnySubModelNodes(SL sl = {}) const; //### - AbstractProperty property(PropertyNameView name) const; - VariantProperty variantProperty(PropertyNameView name) const; - BindingProperty bindingProperty(PropertyNameView name) const; - SignalHandlerProperty signalHandlerProperty(PropertyNameView name) const; - SignalDeclarationProperty signalDeclarationProperty(PropertyNameView name) const; - NodeListProperty nodeListProperty(PropertyNameView name) const; - NodeProperty nodeProperty(PropertyNameView name) const; - NodeAbstractProperty nodeAbstractProperty(PropertyNameView name) const; - NodeAbstractProperty defaultNodeAbstractProperty() const; - NodeListProperty defaultNodeListProperty() const; - NodeProperty defaultNodeProperty() const; + AbstractProperty property(PropertyNameView name, SL sl = {}) const; + VariantProperty variantProperty(PropertyNameView name, SL sl = {}) const; + BindingProperty bindingProperty(PropertyNameView name, SL sl = {}) const; + SignalHandlerProperty signalHandlerProperty(PropertyNameView name, SL sl = {}) const; + SignalDeclarationProperty signalDeclarationProperty(PropertyNameView name, SL sl = {}) const; + NodeListProperty nodeListProperty(PropertyNameView name, SL sl = {}) const; + NodeProperty nodeProperty(PropertyNameView name, SL sl = {}) const; + NodeAbstractProperty nodeAbstractProperty(PropertyNameView name, SL sl = {}) const; + NodeAbstractProperty defaultNodeAbstractProperty(SL sl = {}) const; + NodeListProperty defaultNodeListProperty(SL sl = {}) const; + NodeProperty defaultNodeProperty(SL sl = {}) const; - void removeProperty(PropertyNameView name) const; //### also implement in AbstractProperty - QList properties() const; - QList variantProperties() const; - QList nodeAbstractProperties() const; - QList nodeProperties() const; - QList nodeListProperties() const; - QList bindingProperties() const; - QList signalProperties() const; - QList dynamicProperties() const; - PropertyNameList propertyNames() const; + void removeProperty(PropertyNameView name, SL sl = {}) const; //### also implement in AbstractProperty + QList properties(SL sl = {}) const; + QList variantProperties(SL sl = {}) const; + QList nodeAbstractProperties(SL sl = {}) const; + QList nodeProperties(SL sl = {}) const; + QList nodeListProperties(SL sl = {}) const; + QList bindingProperties(SL sl = {}) const; + QList signalProperties(SL sl = {}) const; + QList dynamicProperties(SL sl = {}) const; + PropertyNameList propertyNames(SL sl = {}) const; - bool hasProperty(PropertyNameView name) const; - bool hasVariantProperty(PropertyNameView name) const; - bool hasBindingProperty(PropertyNameView name) const; - bool hasSignalHandlerProperty(PropertyNameView name) const; - bool hasNodeAbstractProperty(PropertyNameView name) const; - bool hasDefaultNodeAbstractProperty() const; - bool hasDefaultNodeListProperty() const; - bool hasDefaultNodeProperty() const; - bool hasNodeProperty(PropertyNameView name) const; - bool hasNodeListProperty(PropertyNameView name) const; - bool hasProperty(PropertyNameView name, PropertyType propertyType) const; + bool hasProperty(PropertyNameView name, SL sl = {}) const; + bool hasVariantProperty(PropertyNameView name, SL sl = {}) const; + bool hasBindingProperty(PropertyNameView name, SL sl = {}) const; + bool hasSignalHandlerProperty(PropertyNameView name, SL sl = {}) const; + bool hasNodeAbstractProperty(PropertyNameView name, SL sl = {}) const; + bool hasDefaultNodeAbstractProperty(SL sl = {}) const; + bool hasDefaultNodeListProperty(SL sl = {}) const; + bool hasDefaultNodeProperty(SL sl = {}) const; + bool hasNodeProperty(PropertyNameView name, SL sl = {}) const; + bool hasNodeListProperty(PropertyNameView name, SL sl = {}) const; + bool hasProperty(PropertyNameView name, PropertyType propertyType, SL sl = {}) const; - void setScriptFunctions(const QStringList &scriptFunctionList); - QStringList scriptFunctions() const; + void setScriptFunctions(const QStringList &scriptFunctionList, SL sl = {}); + QStringList scriptFunctions(SL sl = {}) const; //### - void destroy(); + void destroy(SL sl = {}); - QString id() const; - void ensureIdExists() const; - [[nodiscard]] QString validId() const; - void setIdWithRefactoring(const QString &id) const; - void setIdWithoutRefactoring(const QString &id) const; + QString id(SL sl = {}) const; + void ensureIdExists(SL sl = {}) const; + [[nodiscard]] QString validId(SL sl = {}) const; + void setIdWithRefactoring(const QString &id, SL sl = {}) const; + void setIdWithoutRefactoring(const QString &id, SL sl = {}) const; static bool isValidId(const QString &id); static QString getIdValidityErrorMessage(const QString &id); - bool hasId() const; + bool hasId(SL sl = {}) const; Model *model() const; AbstractView *view() const; - NodeMetaInfo metaInfo() const; - bool hasMetaInfo() const; + NodeMetaInfo metaInfo(SL sl = {}) const; + bool hasMetaInfo(SL sl = {}) const; - bool isSelected() const; - bool isRootNode() const; + bool isSelected(SL sl = {}) const; + bool isRootNode(SL sl = {}) const; - bool isAncestorOf(const ModelNode &node) const; - void selectNode(); - void deselectNode(); + bool isAncestorOf(const ModelNode &node, SL sl = {}) const; + void selectNode(SL sl = {}); + void deselectNode(SL sl = {}); static int variantTypeId(); - QVariant toVariant() const; + QVariant toVariant(SL sl = {}) const; - std::optional auxiliaryData(AuxiliaryDataKeyView key) const; - std::optional auxiliaryData(AuxiliaryDataType type, Utils::SmallStringView name) const; - QVariant auxiliaryDataWithDefault(AuxiliaryDataType type, Utils::SmallStringView name) const; - QVariant auxiliaryDataWithDefault(AuxiliaryDataKeyView key) const; - QVariant auxiliaryDataWithDefault(AuxiliaryDataKeyDefaultValue key) const; - void setAuxiliaryData(AuxiliaryDataKeyView key, const QVariant &data) const; - void setAuxiliaryDataWithoutLock(AuxiliaryDataKeyView key, const QVariant &data) const; - void setAuxiliaryData(AuxiliaryDataType type, Utils::SmallStringView name, const QVariant &data) const; + std::optional auxiliaryData(AuxiliaryDataKeyView key, SL sl = {}) const; + std::optional auxiliaryData(AuxiliaryDataType type, + Utils::SmallStringView name, + SL sl = {}) const; + QVariant auxiliaryDataWithDefault(AuxiliaryDataType type, + Utils::SmallStringView name, + SL sl = {}) const; + QVariant auxiliaryDataWithDefault(AuxiliaryDataKeyView key, SL sl = {}) const; + QVariant auxiliaryDataWithDefault(AuxiliaryDataKeyDefaultValue key, SL sl = {}) const; + void setAuxiliaryData(AuxiliaryDataKeyView key, const QVariant &data, SL sl = {}) const; + void setAuxiliaryDataWithoutLock(AuxiliaryDataKeyView key, const QVariant &data, SL sl = {}) const; + void setAuxiliaryData(AuxiliaryDataType type, + Utils::SmallStringView name, + const QVariant &data, + SL sl = {}) const; void setAuxiliaryDataWithoutLock(AuxiliaryDataType type, Utils::SmallStringView name, - const QVariant &data) const; - void removeAuxiliaryData(AuxiliaryDataKeyView key) const; - void removeAuxiliaryData(AuxiliaryDataType type, Utils::SmallStringView name) const; - bool hasAuxiliaryData(AuxiliaryDataKeyView key) const; - bool hasAuxiliaryData(AuxiliaryDataType type, Utils::SmallStringView name) const; + const QVariant &data, + SL sl = {}) const; + void removeAuxiliaryData(AuxiliaryDataKeyView key, SL sl = {}) const; + void removeAuxiliaryData(AuxiliaryDataType type, Utils::SmallStringView name, SL sl = {}) const; + bool hasAuxiliaryData(AuxiliaryDataKeyView key, SL sl = {}) const; + bool hasAuxiliaryData(AuxiliaryDataType type, Utils::SmallStringView name, SL sl = {}) const; bool hasAuxiliaryData(AuxiliaryDataType type) const; - AuxiliaryDatasForType auxiliaryData(AuxiliaryDataType type) const; - AuxiliaryDatasView auxiliaryData() const; + AuxiliaryDatasForType auxiliaryData(AuxiliaryDataType type, SL sl = {}) const; + AuxiliaryDatasView auxiliaryData(SL sl = {}) const; - QString customId() const; - bool hasCustomId() const; - void setCustomId(const QString &str); - void removeCustomId(); + QString customId(SL sl = {}) const; + bool hasCustomId(SL sl = {}) const; + void setCustomId(const QString &str, SL sl = {}); + void removeCustomId(SL sl = {}); - QVector comments() const; - bool hasComments() const; - void setComments(const QVector &coms); - void addComment(const Comment &com); - bool updateComment(const Comment &com, int position); + QVector comments(SL sl = {}) const; + bool hasComments(SL sl = {}) const; + void setComments(const QVector &coms, SL sl = {}); + void addComment(const Comment &com, SL sl = {}); + bool updateComment(const Comment &com, int position, SL sl = {}); - Annotation annotation() const; - bool hasAnnotation() const; - void setAnnotation(const Annotation &annotation); - void removeAnnotation(); + Annotation annotation(SL sl = {}) const; + bool hasAnnotation(SL sl = {}) const; + void setAnnotation(const Annotation &annotation, SL sl = {}); + void removeAnnotation(SL sl = {}); - Annotation globalAnnotation() const; - bool hasGlobalAnnotation() const; - void setGlobalAnnotation(const Annotation &annotation); - void removeGlobalAnnotation(); + Annotation globalAnnotation(SL sl = {}) const; + bool hasGlobalAnnotation(SL sl = {}) const; + void setGlobalAnnotation(const Annotation &annotation, SL sl = {}); + void removeGlobalAnnotation(SL sl = {}); - GlobalAnnotationStatus globalStatus() const; - bool hasGlobalStatus() const; - void setGlobalStatus(const GlobalAnnotationStatus &status); - void removeGlobalStatus(); + GlobalAnnotationStatus globalStatus(SL sl = {}) const; + bool hasGlobalStatus(SL sl = {}) const; + void setGlobalStatus(const GlobalAnnotationStatus &status, SL sl = {}); + void removeGlobalStatus(SL sl = {}); - bool locked() const; - void setLocked(bool value); + bool locked(SL sl = {}) const; + void setLocked(bool value, SL sl = {}); - qint32 internalId() const; + qint32 internalId(SL sl = {}) const; - void setNodeSource(const QString&); - void setNodeSource(const QString &newNodeSource, NodeSourceType type); - QString nodeSource() const; + void setNodeSource(const QString &str, SL sl = {}); + void setNodeSource(const QString &newNodeSource, NodeSourceType type, SL sl = {}); + QString nodeSource(SL sl = {}) const; - QString convertTypeToImportAlias() const; + QString convertTypeToImportAlias(SL sl = {}) const; - NodeSourceType nodeSourceType() const; + NodeSourceType nodeSourceType(SL sl = {}) const; - bool isComponent() const; - QIcon typeIcon() const; - QString behaviorPropertyName() const; + bool isComponent(SL sl = {}) const; + QIcon typeIcon(SL sl = {}) const; + QString behaviorPropertyName(SL sl = {}) const; friend void swap(ModelNode &first, ModelNode &second) noexcept { @@ -263,7 +269,7 @@ public: return firstNode.m_internalNode == secondNode.m_internalNode; } - friend auto operator<=>(const ModelNode &firstNode, const ModelNode &secondNode) + friend std::weak_ordering operator<=>(const ModelNode &firstNode, const ModelNode &secondNode) { return firstNode.m_internalNode <=> secondNode.m_internalNode; } @@ -273,7 +279,7 @@ private: // functions template QList properties(PropertyType... type) const; - bool hasLocked() const; + bool hasLocked(SL sl = {}) const; private: // variables Internal::InternalNodePointer m_internalNode; diff --git a/src/plugins/qmldesigner/libs/designercore/include/projectstorageids.h b/src/plugins/qmldesigner/libs/designercore/include/projectstorageids.h index a5f8ad35a9d..fb6c56a5407 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/projectstorageids.h +++ b/src/plugins/qmldesigner/libs/designercore/include/projectstorageids.h @@ -11,8 +11,8 @@ enum class ProjectStorageIdType { Type, PropertyType, PropertyDeclaration, - SourceName, - SourceContext, + FileName, + DirectoryPath, StorageCacheIndex, FunctionDeclaration, SignalDeclaration, @@ -45,6 +45,8 @@ using EnumerationDeclarationIds = std::vector; using ModuleId = Sqlite::BasicId; using ModuleIds = std::vector; using ModuleIdSpan = Utils::span; +template +using SmallModuleIds = QVarLengthArray; using ProjectPartId = Sqlite::BasicId; using ProjectPartIds = std::vector; diff --git a/src/plugins/qmldesigner/libs/designercore/include/rewriterview.h b/src/plugins/qmldesigner/libs/designercore/include/rewriterview.h index 9672fdc35d2..ac64b97cd3f 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/rewriterview.h +++ b/src/plugins/qmldesigner/libs/designercore/include/rewriterview.h @@ -179,6 +179,8 @@ public: void setIsDocumentRewriterView(bool b); #endif + void setRemoveImports(bool removeImports); + signals: void modelInterfaceProjectUpdated(); diff --git a/src/plugins/qmldesigner/libs/designercore/include/sourcepathids.h b/src/plugins/qmldesigner/libs/designercore/include/sourcepathids.h index 7bac16dcd50..8cf22df5a10 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/sourcepathids.h +++ b/src/plugins/qmldesigner/libs/designercore/include/sourcepathids.h @@ -12,22 +12,95 @@ namespace QmlDesigner { enum class SourcePathIdType { - SourceName, - SourceContext, + FileName, + DirectoryPath, }; -using SourceContextId = Sqlite::BasicId; -using SourceContextIds = std::vector; +using DirectoryPathId = Sqlite::BasicId; +using DirectoryPathIds = std::vector; template -using SmallSourceContextIds = QVarLengthArray; +using SmallDirectoryPathIds = QVarLengthArray; -using SourceNameId = Sqlite::BasicId; -using SourceNameIds = std::vector; +using FileNameId = Sqlite::BasicId; +using FileNameIds = std::vector; template -using SmallSourceNameIds = QVarLengthArray; +using SmallFileNameIds = QVarLengthArray; + +class SourceId + +{ +public: + using IsBasicId = std::true_type; + using DatabaseType = long long; + + constexpr explicit SourceId() = default; + + static constexpr SourceId create(DirectoryPathId directoryPathId, FileNameId fileNameId) + { + SourceId compoundId; + compoundId.id = (static_cast(directoryPathId.internalId()) << 32) + | static_cast(fileNameId.internalId()); + + return compoundId; + } + + static constexpr SourceId create(long long idNumber) + { + SourceId id; + id.id = idNumber; + + return id; + } + + constexpr FileNameId fileNameId() const { return FileNameId::create(static_cast(id)); } + + constexpr DirectoryPathId directoryPathId() const { return DirectoryPathId::create(id >> 32); } + + friend constexpr bool compareInvalidAreTrue(SourceId first, SourceId second) + { + return first.id == second.id; + } + + friend constexpr bool operator==(SourceId first, SourceId second) + { + return first.id == second.id && first.isValid(); + } + + friend constexpr auto operator<=>(SourceId first, SourceId second) = default; + + constexpr bool isValid() const { return id != 0; } + + constexpr bool isNull() const { return id == 0; } + + explicit operator bool() const { return isValid(); } + + long long internalId() const { return id; } + + explicit operator std::size_t() const { return static_cast(id) | 0xFFFFFFFFULL; } + + template + friend void convertToString(String &string, SourceId id) + { + using NanotraceHR::dictonary; + using NanotraceHR::keyValue; + + int fileNameId = static_cast(id.id); + int directoryPathId = id.id >> 32; + + auto dict = dictonary(keyValue("directory path id", directoryPathId), + keyValue("source name id", fileNameId), + keyValue("source id", id.id)); + + convertToString(string, dict); + } + + friend bool compareId(SourceId first, SourceId second) { return first.id == second.id; } + +private: + long long id = 0; +}; -using SourceId = Sqlite::CompoundBasicId; using SourceIds = std::vector; template using SmallSourceIds = QVarLengthArray; diff --git a/src/plugins/qmldesigner/libs/designercore/include/widgetinfo.h b/src/plugins/qmldesigner/libs/designercore/include/widgetinfo.h new file mode 100644 index 00000000000..a73fbc6ee29 --- /dev/null +++ b/src/plugins/qmldesigner/libs/designercore/include/widgetinfo.h @@ -0,0 +1,32 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +namespace QmlDesigner { + +enum DesignerWidgetFlags { DisableOnError, IgnoreErrors }; + +class WidgetInfo +{ +public: + enum PlacementHint { + NoPane, + LeftPane, + RightPane, + BottomPane, + TopPane, // not used + CentralPane + }; + + QString uniqueId; + QString tabName; + QString feedbackDisplayName; + QWidget *widget = nullptr; + PlacementHint placementHint = PlacementHint::NoPane; + DesignerWidgetFlags widgetFlags = DesignerWidgetFlags::DisableOnError; +}; + +} // namespace QmlDesigner + +Q_DECLARE_METATYPE(QmlDesigner::WidgetInfo) diff --git a/src/plugins/qmldesigner/libs/designercore/include/widgetregistration.h b/src/plugins/qmldesigner/libs/designercore/include/widgetregistration.h new file mode 100644 index 00000000000..ea4ad010190 --- /dev/null +++ b/src/plugins/qmldesigner/libs/designercore/include/widgetregistration.h @@ -0,0 +1,20 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "widgetinfo.h" + +namespace QmlDesigner { + +class WidgetRegistrationInterface +{ +public: + virtual void registerWidgetInfo(WidgetInfo) = 0; + virtual void deregisterWidgetInfo(WidgetInfo) = 0; + +protected: + ~WidgetRegistrationInterface() = default; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/libs/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/libs/designercore/model/abstractview.cpp index c19ff88219e..c0a39e5879c 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/libs/designercore/model/abstractview.cpp @@ -59,6 +59,16 @@ void AbstractView::setModel(Model *model) m_model = model; } +void AbstractView::setWidgetRegistration(WidgetRegistrationInterface *interface) +{ + m_widgetRegistration = interface; +} + +void AbstractView::registerWidgetInfo() +{ + if (m_widgetRegistration) + m_widgetRegistration->registerWidgetInfo(widgetInfo()); +} RewriterTransaction AbstractView::beginRewriterTransaction(const QByteArray &identifier) { return RewriterTransaction(this, identifier); diff --git a/src/plugins/qmldesigner/libs/designercore/model/model.cpp b/src/plugins/qmldesigner/libs/designercore/model/model.cpp index b0636a9f0ca..31ae2875df6 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/libs/designercore/model/model.cpp @@ -85,6 +85,7 @@ ModelPrivate::ModelPrivate(Model *model, std::unique_ptr resourceManagement) : projectStorage{&projectStorageDependencies.storage} , pathCache{&projectStorageDependencies.cache} + , projectStorageTriggerUpdate{&projectStorageDependencies.triggerUpdate} , m_model{model} , m_resourceManagement{std::move(resourceManagement)} { @@ -110,6 +111,7 @@ ModelPrivate::ModelPrivate(Model *model, std::unique_ptr resourceManagement) : projectStorage{&projectStorageDependencies.storage} , pathCache{&projectStorageDependencies.cache} + , projectStorageTriggerUpdate{&projectStorageDependencies.triggerUpdate} , m_model{model} , m_resourceManagement{std::move(resourceManagement)} { @@ -301,6 +303,7 @@ void ModelPrivate::changeNodeType(const InternalNodePointer &node, const TypeNam node->typeName = typeName; node->majorVersion = majorVersion; node->minorVersion = minorVersion; + setTypeId(node.get(), typeName); try { notifyNodeTypeChanged(node, typeName, majorVersion, minorVersion); @@ -661,12 +664,12 @@ void ModelPrivate::notifyRootNodeTypeChanged(const QString &type, int majorVersi [&](AbstractView *view) { view->rootNodeTypeChanged(type, majorVersion, minorVersion); }); } -void ModelPrivate::notifyInstancePropertyChange(const QList> &propertyPairList) +void ModelPrivate::notifyInstancePropertyChange(Utils::span> properties) { notifyInstanceChanges([&](AbstractView *view) { using ModelNodePropertyPair = QPair; QList> adaptedPropertyList; - for (const ModelNodePropertyPair &propertyPair : propertyPairList) { + for (const ModelNodePropertyPair &propertyPair : properties) { ModelNodePropertyPair newPair(ModelNode{propertyPair.first.internalNode(), m_model, view}, propertyPair.second); adaptedPropertyList.append(newPair); } @@ -674,20 +677,20 @@ void ModelPrivate::notifyInstancePropertyChange(const QList &instanceIds) +void ModelPrivate::notifyInstanceErrorChange(Utils::span instanceIds) { notifyInstanceChanges([&](AbstractView *view) { QVector errorNodeList; - errorNodeList.reserve(instanceIds.size()); + errorNodeList.reserve(std::ssize(instanceIds)); for (qint32 instanceId : instanceIds) errorNodeList.emplace_back(m_model->d->nodeForInternalId(instanceId), m_model, view); view->instanceErrorChanged(errorNodeList); }); } -void ModelPrivate::notifyInstancesCompleted(const QVector &modelNodeVector) +void ModelPrivate::notifyInstancesCompleted(Utils::span modelNodes) { - auto internalNodes = toInternalNodeList(modelNodeVector); + auto internalNodes = toInternalNodeList(modelNodes); notifyInstanceChanges([&](AbstractView *view) { view->instancesCompleted(toModelNodeList(internalNodes, view)); @@ -715,27 +718,27 @@ void ModelPrivate::notifyInstancesInformationsChange( }); } -void ModelPrivate::notifyInstancesRenderImageChanged(const QVector &modelNodeVector) +void ModelPrivate::notifyInstancesRenderImageChanged(Utils::span nodes) { - auto internalNodes = toInternalNodeList(modelNodeVector); + auto internalNodes = toInternalNodeList(nodes); notifyInstanceChanges([&](AbstractView *view) { view->instancesRenderImageChanged(toModelNodeList(internalNodes, view)); }); } -void ModelPrivate::notifyInstancesPreviewImageChanged(const QVector &modelNodeVector) +void ModelPrivate::notifyInstancesPreviewImageChanged(Utils::span nodes) { - auto internalNodes = toInternalNodeList(modelNodeVector); + auto internalNodes = toInternalNodeList(nodes); notifyInstanceChanges([&](AbstractView *view) { view->instancesPreviewImageChanged(toModelNodeList(internalNodes, view)); }); } -void ModelPrivate::notifyInstancesChildrenChanged(const QVector &modelNodeVector) +void ModelPrivate::notifyInstancesChildrenChanged(Utils::span nodes) { - auto internalNodes = toInternalNodeList(modelNodeVector); + auto internalNodes = toInternalNodeList(nodes); notifyInstanceChanges([&](AbstractView *view) { view->instancesChildrenChanged(toModelNodeList(internalNodes, view)); @@ -809,10 +812,11 @@ void ModelPrivate::notifyRewriterEndTransaction() notifyNodeInstanceViewLast([&](AbstractView *view) { view->rewriterEndTransaction(); }); } -void ModelPrivate::notifyInstanceToken(const QString &token, int number, - const QVector &modelNodeVector) +void ModelPrivate::notifyInstanceToken(const QString &token, + int number, + Utils::span nodes) { - auto internalNodes = toInternalNodeList(modelNodeVector); + auto internalNodes = toInternalNodeList(nodes); notifyInstanceChanges([&](AbstractView *view) { view->instancesToken(token, number, toModelNodeList(internalNodes, view)); @@ -821,10 +825,10 @@ void ModelPrivate::notifyInstanceToken(const QString &token, int number, void ModelPrivate::notifyCustomNotification(const AbstractView *senderView, const QString &identifier, - const QList &modelNodeList, + Utils::span nodes, const QList &data) { - auto internalList = toInternalNodeList(modelNodeList); + auto internalList = toInternalNodeList(nodes); notifyNodeInstanceViewLast([&](AbstractView *view) { view->customNotification(senderView, identifier, toModelNodeList(internalList, view), data); }); @@ -1226,22 +1230,22 @@ void ModelPrivate::removeAuxiliaryData(const InternalNodePointer &node, const Au notifyAuxiliaryDataChanged(node, key, QVariant()); } -QList ModelPrivate::toModelNodeList(Utils::span nodeList, +QList ModelPrivate::toModelNodeList(Utils::span nodes, AbstractView *view) const { QList modelNodeList; - modelNodeList.reserve(nodeList.size()); - for (const InternalNodePointer &node : nodeList) + modelNodeList.reserve(std::ssize(nodes)); + for (const InternalNodePointer &node : nodes) modelNodeList.emplace_back(node, m_model, view); return modelNodeList; } -ModelPrivate::ManyNodes ModelPrivate::toInternalNodeList(const QList &modelNodeList) const +ModelPrivate::ManyNodes ModelPrivate::toInternalNodeList(Utils::span modelNodes) const { ManyNodes newNodeList; - newNodeList.reserve(modelNodeList.size()); - for (const ModelNode &modelNode : modelNodeList) + newNodeList.reserve(std::ssize(modelNodes)); + for (const ModelNode &modelNode : modelNodes) newNodeList.append(modelNode.internalNode()); return newNodeList; @@ -1771,7 +1775,7 @@ Model::Model(const TypeName &typeName, ModelPointer Model::createModel(const TypeName &typeName, std::unique_ptr resourceManagement) { - return Model::create({*d->projectStorage, *d->pathCache}, + return Model::create({*d->projectStorage, *d->pathCache, *d->projectStorageTriggerUpdate}, typeName, imports(), fileUrl(), @@ -1799,6 +1803,31 @@ Storage::Info::ExportedTypeName Model::exportedTypeNameForMetaInfo(const NodeMet namespace { +QmlDesigner::Imports createPossibleFileImports(const Utils::FilePath &path) +{ + auto folder = path.parentDir(); + QmlDesigner::Imports imports; + + /* Creates imports for all sub folder that contain a qml file. */ + folder.iterateDirectory( + [&](const Utils::FilePath &item) { + bool append = false; + + item.iterateDirectory( + [&](const Utils::FilePath &) { + append = true; + return Utils::IterationPolicy::Stop; + }, + {{"*.qml"}, QDir::Files}); + if (append) + imports.append(QmlDesigner::Import::createFileImport(item.fileName())); + return Utils::IterationPolicy::Continue; + }, + {{}, QDir::Dirs | QDir::NoDotAndDotDot}); + + return imports; +} + QmlDesigner::Imports createQt6ModulesForProjectStorage() { QmlDesigner::Imports imports = { @@ -1852,7 +1881,10 @@ QmlDesigner::Imports createQt6ModulesForProjectStorage() Imports Model::possibleImports() const { #ifdef QDS_USE_PROJECTSTORAGE - static auto imports = createQt6ModulesForProjectStorage(); + static auto qt6Imports = createQt6ModulesForProjectStorage(); + auto imports = createPossibleFileImports(Utils::FilePath::fromUrl(fileUrl())); + imports.append(qt6Imports); + return imports; #else return d->m_possibleImportList; @@ -2018,23 +2050,35 @@ PathCacheType &Model::pathCache() return *d->pathCache; } -void Model::emitInstancePropertyChange(AbstractView *view, - const QList> &propertyList) +ProjectStorageTriggerUpdateInterface &Model::projectStorageTriggerUpdate() const { - if (d->nodeInstanceView() == view) // never remove check - d->notifyInstancePropertyChange(propertyList); + return *d->projectStorageTriggerUpdate; } -void Model::emitInstanceErrorChange(AbstractView *view, const QVector &instanceIds) +ProjectStorageDependencies Model::projectStorageDependencies() const +{ + return ProjectStorageDependencies{*d->projectStorage, + *d->pathCache, + *d->projectStorageTriggerUpdate}; +} + +void Model::emitInstancePropertyChange(AbstractView *view, + Utils::span> properties) +{ + if (d->nodeInstanceView() == view) // never remove check + d->notifyInstancePropertyChange(properties); +} + +void Model::emitInstanceErrorChange(AbstractView *view, Utils::span instanceIds) { if (d->nodeInstanceView() == view) // never remove check d->notifyInstanceErrorChange(instanceIds); } -void Model::emitInstancesCompleted(AbstractView *view, const QVector &nodeVector) +void Model::emitInstancesCompleted(AbstractView *view, Utils::span nodes) { if (d->nodeInstanceView() == view) // never remove check - d->notifyInstancesCompleted(nodeVector); + d->notifyInstancesCompleted(nodes); } void Model::emitInstanceInformationsChange( @@ -2044,22 +2088,22 @@ void Model::emitInstanceInformationsChange( d->notifyInstancesInformationsChange(informationChangeHash); } -void Model::emitInstancesRenderImageChanged(AbstractView *view, const QVector &nodeVector) +void Model::emitInstancesRenderImageChanged(AbstractView *view, Utils::span nodes) { if (d->nodeInstanceView() == view) // never remove check - d->notifyInstancesRenderImageChanged(nodeVector); + d->notifyInstancesRenderImageChanged(nodes); } -void Model::emitInstancesPreviewImageChanged(AbstractView *view, const QVector &nodeVector) +void Model::emitInstancesPreviewImageChanged(AbstractView *view, Utils::span nodes) { if (d->nodeInstanceView() == view) // never remove check - d->notifyInstancesPreviewImageChanged(nodeVector); + d->notifyInstancesPreviewImageChanged(nodes); } -void Model::emitInstancesChildrenChanged(AbstractView *view, const QVector &nodeVector) +void Model::emitInstancesChildrenChanged(AbstractView *view, Utils::span nodes) { if (d->nodeInstanceView() == view) // never remove check - d->notifyInstancesChildrenChanged(nodeVector); + d->notifyInstancesChildrenChanged(nodes); } void Model::emitInstanceToken(AbstractView *view, @@ -2122,10 +2166,10 @@ void Model::emitDocumentMessage(const QList &errors, void Model::emitCustomNotification(AbstractView *view, const QString &identifier, - const QList &nodeList, + Utils::span nodes, const QList &data) { - d->notifyCustomNotification(view, identifier, nodeList, data); + d->notifyCustomNotification(view, identifier, nodes, data); } void Model::sendCustomNotificationTo(AbstractView *to, const CustomNotificationPackage &package) @@ -2257,11 +2301,11 @@ QList Model::selectedNodes(AbstractView *view) const return d->toModelNodeList(d->selectedNodes(), view); } -void Model::setSelectedModelNodes(const QList &selectedNodeList) +void Model::setSelectedModelNodes(Utils::span selectedNodes) { QList unlockedNodes; - for (const auto &modelNode : selectedNodeList) { + for (const auto &modelNode : selectedNodes) { if (!ModelUtils::isThisOrAncestorLocked(modelNode)) unlockedNodes.push_back(modelNode); } @@ -2681,6 +2725,16 @@ NodeMetaInfo Model::qtQuick3DDefaultMaterialMetaInfo() const } } +NodeMetaInfo Model::qtQuick3DLightMetaInfo() const +{ + if constexpr (useProjectStorage()) { + using namespace Storage::Info; + return createNodeMetaInfo(); + } else { + return metaInfo("QtQuick3D.Light"); + } +} + NodeMetaInfo Model::qtQuick3DDirectionalLightMetaInfo() const { if constexpr (useProjectStorage()) { @@ -2812,6 +2866,27 @@ QList Model::itemLibraryEntries() const #endif } +QList Model::directoryImportsItemLibraryEntries() const +{ +#ifdef QDS_USE_PROJECTSTORAGE + using namespace Storage::Info; + return toItemLibraryEntries(*d->pathCache, + d->projectStorage->directoryImportsItemLibraryEntries(d->m_sourceId)); +#else + return {}; +#endif +} + +QList Model::allItemLibraryEntries() const +{ +#ifdef QDS_USE_PROJECTSTORAGE + using namespace Storage::Info; + return toItemLibraryEntries(*d->pathCache, d->projectStorage->allItemLibraryEntries()); +#else + return d->metaInfo().itemLibraryInfo()->entries(); +#endif +} + NodeMetaInfo Model::qtQuickTimelineKeyframeGroupMetaInfo() const { if constexpr (useProjectStorage()) { @@ -2882,6 +2957,15 @@ Module Model::module(Utils::SmallStringView moduleName, Storage::ModuleKind modu return {}; } +SmallModuleIds<128> Model::moduleIdsStartsWith(Utils::SmallStringView startsWith, + Storage::ModuleKind kind) const +{ + if constexpr (useProjectStorage()) + return d->projectStorage->moduleIdsStartsWith(startsWith, kind); + + return {}; +} + /*! \name View related functions */ //\{ diff --git a/src/plugins/qmldesigner/libs/designercore/model/model_p.h b/src/plugins/qmldesigner/libs/designercore/model/model_p.h index d9591ccbf9e..1dc8c0de2ab 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/libs/designercore/model/model_p.h @@ -195,17 +195,17 @@ public: void notifyCustomNotification(const AbstractView *senderView, const QString &identifier, - const QList &modelNodeList, + Utils::span nodes, const QList &data); void notifyCustomNotificationTo(AbstractView *view, const CustomNotificationPackage &package); - void notifyInstancePropertyChange(const QList> &propertyList); - void notifyInstanceErrorChange(const QVector &instanceIds); - void notifyInstancesCompleted(const QVector &modelNodeVector); + void notifyInstancePropertyChange(Utils::span> properties); + void notifyInstanceErrorChange(Utils::span instanceIds); + void notifyInstancesCompleted(Utils::span modelNodes); void notifyInstancesInformationsChange(const QMultiHash &informationChangeHash); - void notifyInstancesRenderImageChanged(const QVector &modelNodeVector); - void notifyInstancesPreviewImageChanged(const QVector &modelNodeVector); - void notifyInstancesChildrenChanged(const QVector &modelNodeVector); - void notifyInstanceToken(const QString &token, int number, const QVector &modelNodeVector); + void notifyInstancesRenderImageChanged(Utils::span nodes); + void notifyInstancesPreviewImageChanged(Utils::span nodes); + void notifyInstancesChildrenChanged(Utils::span nodes); + void notifyInstanceToken(const QString &token, int number, Utils::span nodes); void notifyCurrentStateChanged(const ModelNode &node); void notifyCurrentTimelineChanged(const ModelNode &node); @@ -334,7 +334,7 @@ private: void removePropertyWithoutNotification(InternalProperty *property); void removeAllSubNodes(const InternalNodePointer &node); void removeNodeFromModel(const InternalNodePointer &node); - ManyNodes toInternalNodeList(const QList &modelNodeList) const; + ManyNodes toInternalNodeList(Utils::span modelNodes) const; QList toModelNodeList(Utils::span nodeList, AbstractView *view) const; static QList toInternalProperties(const AbstractProperties &properties); @@ -347,6 +347,7 @@ private: public: NotNullPointer projectStorage = nullptr; NotNullPointer pathCache = nullptr; + NotNullPointer projectStorageTriggerUpdate = nullptr; ModelTracing::AsynchronousToken traceToken = ModelTracing::category().beginAsynchronous("Model"); private: diff --git a/src/plugins/qmldesigner/libs/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/libs/designercore/model/modelnode.cpp index ae8c2c6f33c..b7a968fae92 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/modelnode.cpp +++ b/src/plugins/qmldesigner/libs/designercore/model/modelnode.cpp @@ -4,35 +4,25 @@ #include "modelnode.h" #include "annotation.h" -#include "bindingproperty.h" #include "designercoretr.h" #include "internalnode_p.h" #include "model_p.h" -#include "nodeabstractproperty.h" #include "nodelistproperty.h" #include "nodeproperty.h" #include "signalhandlerproperty.h" #include "variantproperty.h" #include -#include #include -#include #include #include -#include - -#include -#include -#include -#include - -#include namespace QmlDesigner { using namespace QmlDesigner::Internal; +auto category = ModelTracing::category; + /*! \class QmlDesigner::ModelNode \ingroup CoreModel @@ -73,23 +63,39 @@ ModelNode::ModelNode(const ModelNode &modelNode, AbstractView *view) /*! \brief returns the name of node which is a short cut to a property like objectName \return name of the node */ -QString ModelNode::id() const +QString ModelNode::id(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node id", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_internalNode->id; } -void ModelNode::ensureIdExists() const +void ModelNode::ensureIdExists(SL sl) const { if (!hasId()) setIdWithoutRefactoring(model()->generateNewId(simplifiedTypeName())); + + NanotraceHR::Tracer tracer{"model node ensure id exists", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; } -QString ModelNode::validId() const +QString ModelNode::validId(SL sl) const { - ensureIdExists(); + NanotraceHR::Tracer tracer{"model node valid id", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + + ensureIdExists(sl); return id(); } @@ -126,32 +132,51 @@ QString ModelNode::getIdValidityErrorMessage(const QString &id) return DesignerCore::Tr::tr("ID includes invalid characters (%1).").arg(id); } -bool ModelNode::hasId() const +bool ModelNode::hasId(SL sl) const { if (!isValid()) return false; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has id", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return !m_internalNode->id.isEmpty(); } -void ModelNode::setIdWithRefactoring(const QString &id) const +void ModelNode::setIdWithRefactoring(const QString &id, SL sl) const { - if (isValid()) { - if (model()->rewriterView() && !id.isEmpty() - && !m_internalNode->id.isEmpty()) { // refactor the id if they are not empty - model()->rewriterView()->renameId(m_internalNode->id, id); - } else { - setIdWithoutRefactoring(id); - } + if (!isValid()) + return; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set id with refactoring", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + + if (model()->rewriterView() && !id.isEmpty() + && !m_internalNode->id.isEmpty()) { // refactor the id if they are not empty + model()->rewriterView()->renameId(m_internalNode->id, id); + } else { + setIdWithoutRefactoring(id); } } -void ModelNode::setIdWithoutRefactoring(const QString &id) const +void ModelNode::setIdWithoutRefactoring(const QString &id, SL sl) const { Internal::WriteLocker locker(m_model.data()); if (!isValid()) return; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set id without refactoring", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (!isValidId(id)) return; @@ -167,50 +192,77 @@ void ModelNode::setIdWithoutRefactoring(const QString &id) const /*! \brief the fully-qualified type name of the node is represented as string \return type of the node as a string */ -TypeName ModelNode::type() const +TypeName ModelNode::type(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node type", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_internalNode->typeName; } /*! \brief minor number of the QML type \return minor number */ -int ModelNode::minorVersion() const +int ModelNode::minorVersion(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node minor version", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_internalNode->minorVersion; } /*! \brief major number of the QML type \return major number */ -int ModelNode::majorVersion() const +int ModelNode::majorVersion(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node major version", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_internalNode->majorVersion; } /*! \return the short-hand type name of the node. */ -QString ModelNode::simplifiedTypeName() const +QString ModelNode::simplifiedTypeName(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node simplified type name", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return QString::fromUtf8(type().split('.').constLast()); } -QString ModelNode::displayName() const +QString ModelNode::displayName(SL sl) const { - if (hasId()) - return id(); - return simplifiedTypeName(); + NanotraceHR::Tracer tracer{"model node display name", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + + return hasId() ? id() : simplifiedTypeName(); } /*! \brief Returns whether the node is valid @@ -232,15 +284,22 @@ bool ModelNode::isValid() const Will return true also for the root node itself. */ -bool ModelNode::isInHierarchy() const +bool ModelNode::isInHierarchy(SL sl) const { if (!isValid()) return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node is in hierarchy", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (isRootNode()) return true; if (!hasParentProperty()) return false; - return parentProperty().parentModelNode().isInHierarchy(); + return parentProperty().parentModelNode().isInHierarchy(sl); } /*! @@ -252,11 +311,17 @@ bool ModelNode::isInHierarchy() const \return the property containing this ModelNode */ -NodeAbstractProperty ModelNode::parentProperty() const +NodeAbstractProperty ModelNode::parentProperty(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node parent property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (!m_internalNode->parentProperty()) return {}; @@ -284,11 +349,17 @@ parentNode4 == parentNode1; -> true */ -void ModelNode::setParentProperty(NodeAbstractProperty parent) +void ModelNode::setParentProperty(NodeAbstractProperty parent, SL sl) { if (!isValid()) return; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set parent property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (!parent.parentModelNode().isValid()) return; @@ -301,28 +372,45 @@ void ModelNode::setParentProperty(NodeAbstractProperty parent) parent.reparentHere(*this); } -void ModelNode::changeType(const TypeName &typeName, int majorVersion, int minorVersion) +void ModelNode::changeType(const TypeName &typeName, int majorVersion, int minorVersion, SL sl) { if (!isValid()) return; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node change type", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + model()->d->changeNodeType(m_internalNode, typeName, majorVersion, minorVersion); } -void ModelNode::setParentProperty(const ModelNode &newParentNode, const PropertyName &propertyName) +void ModelNode::setParentProperty(const ModelNode &newParentNode, const PropertyName &propertyName, SL sl) { - setParentProperty(newParentNode.nodeAbstractProperty(propertyName)); + NanotraceHR::Tracer tracer{"model node set parent property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + + setParentProperty(newParentNode.nodeAbstractProperty(propertyName), sl); } /*! \brief test if there is a parent for this node \return true is this node has a parent \see childNodes parentNode setParentNode hasChildNodes Model::undo */ -bool ModelNode::hasParentProperty() const +bool ModelNode::hasParentProperty(SL sl) const { if (!isValid()) return false; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has parent property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (!m_internalNode->parentProperty()) return false; @@ -339,27 +427,44 @@ bool ModelNode::hasParentProperty() const \return BindingProperty named name */ -BindingProperty ModelNode::bindingProperty(PropertyNameView name) const +BindingProperty ModelNode::bindingProperty(PropertyNameView name, SL sl) const { if (!isValid()) return {}; + NanotraceHR::Tracer tracer{"model node binding property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return BindingProperty(name, m_internalNode, model(), view()); } -SignalHandlerProperty ModelNode::signalHandlerProperty(PropertyNameView name) const +SignalHandlerProperty ModelNode::signalHandlerProperty(PropertyNameView name, SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node signal handler property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return SignalHandlerProperty(name, m_internalNode, model(), view()); } -SignalDeclarationProperty ModelNode::signalDeclarationProperty(PropertyNameView name) const +SignalDeclarationProperty ModelNode::signalDeclarationProperty(PropertyNameView name, SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node signal declaration property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return SignalDeclarationProperty(name, m_internalNode, model(), view()); } @@ -373,11 +478,17 @@ SignalDeclarationProperty ModelNode::signalDeclarationProperty(PropertyNameView \return NodeProperty named name */ -NodeProperty ModelNode::nodeProperty(PropertyNameView name) const +NodeProperty ModelNode::nodeProperty(PropertyNameView name, SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node node property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return NodeProperty(name, m_internalNode, model(), view()); } @@ -391,34 +502,61 @@ NodeProperty ModelNode::nodeProperty(PropertyNameView name) const \return NodeListProperty named name */ -NodeListProperty ModelNode::nodeListProperty(PropertyNameView name) const +NodeListProperty ModelNode::nodeListProperty(PropertyNameView name, SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node node list property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return NodeListProperty(name, m_internalNode, model(), view()); } -NodeAbstractProperty ModelNode::nodeAbstractProperty(PropertyNameView name) const +NodeAbstractProperty ModelNode::nodeAbstractProperty(PropertyNameView name, SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node node abstract property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return NodeAbstractProperty(name, m_internalNode, model(), view()); } -NodeAbstractProperty ModelNode::defaultNodeAbstractProperty() const +NodeAbstractProperty ModelNode::defaultNodeAbstractProperty(SL sl) const { + NanotraceHR::Tracer tracer{"model node default node abstract property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return nodeAbstractProperty(metaInfo().defaultPropertyName()); } -NodeListProperty ModelNode::defaultNodeListProperty() const +NodeListProperty ModelNode::defaultNodeListProperty(SL sl) const { + NanotraceHR::Tracer tracer{"model node default node list property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return nodeListProperty(metaInfo().defaultPropertyName()); } -NodeProperty ModelNode::defaultNodeProperty() const +NodeProperty ModelNode::defaultNodeProperty(SL sl) const { + NanotraceHR::Tracer tracer{"model node default node property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return nodeProperty(metaInfo().defaultPropertyName()); } @@ -432,19 +570,30 @@ NodeProperty ModelNode::defaultNodeProperty() const \return VariantProperty named name */ -VariantProperty ModelNode::variantProperty(PropertyNameView name) const +VariantProperty ModelNode::variantProperty(PropertyNameView name, SL sl) const { if (!isValid()) return {}; + NanotraceHR::Tracer tracer{"model node variant property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return VariantProperty(name, m_internalNode, model(), view()); } -AbstractProperty ModelNode::property(PropertyNameView name) const +AbstractProperty ModelNode::property(PropertyNameView name, SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return AbstractProperty(name, m_internalNode, model(), view()); } @@ -463,11 +612,17 @@ It is searching only in the local Property. The list of properties */ -QList ModelNode::properties() const +QList ModelNode::properties(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node properties", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + QList propertyList; const QList propertyNames = m_internalNode->propertyNameList(); @@ -485,23 +640,47 @@ QList ModelNode::properties() const The list of all properties containing just an atomic value. */ -QList ModelNode::variantProperties() const +QList ModelNode::variantProperties(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node variant property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return properties(PropertyType::Variant); } -QList ModelNode::nodeAbstractProperties() const +QList ModelNode::nodeAbstractProperties(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node node abstract property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return properties(PropertyType::Node, PropertyType::NodeList); } -QList ModelNode::nodeProperties() const +QList ModelNode::nodeProperties(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node node property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return properties(PropertyType::Node); } -QList ModelNode::nodeListProperties() const +QList ModelNode::nodeListProperties(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node node list property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return properties(PropertyType::NodeList); } @@ -511,21 +690,39 @@ QList ModelNode::nodeListProperties() const The list of all properties containing an expression. */ -QList ModelNode::bindingProperties() const +QList ModelNode::bindingProperties(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node binding property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return properties(PropertyType::Binding); } -QList ModelNode::signalProperties() const +QList ModelNode::signalProperties(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node signal handler property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return properties(PropertyType::SignalHandler); } -QList ModelNode::dynamicProperties() const +QList ModelNode::dynamicProperties(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node dynamic property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + QList properties; for (const auto &propertyEntry : *m_internalNode.get()) { @@ -546,11 +743,17 @@ Does nothing if the node state does not set this property. \see addProperty property properties hasProperties */ -void ModelNode::removeProperty(PropertyNameView name) const +void ModelNode::removeProperty(PropertyNameView name, SL sl) const { if (!isValid()) return; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node remove property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (!model()->d->propertyNameIsValid(name)) return; @@ -587,11 +790,17 @@ static void removeModelNodeFromSelection(const ModelNode &node) /*! \brief complete removes this ModelNode from the Model */ -void ModelNode::destroy() +void ModelNode::destroy(SL sl) { if (!isValid()) return; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node destroy", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (isRootNode()) return; @@ -626,23 +835,41 @@ The list contains every ModelNode that belongs to one of this ModelNodes properties. \return a list of all ModelNodes that are direct children */ -QList ModelNode::directSubModelNodes() const +QList ModelNode::directSubModelNodes(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node direct sub model nodes", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return toModelNodeList(m_internalNode->allDirectSubNodes(), model(), view()); } -QList ModelNode::directSubModelNodesOfType(const NodeMetaInfo &type) const +QList ModelNode::directSubModelNodesOfType(const NodeMetaInfo &type, SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node direct sub model nodes of type", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return Utils::filtered(directSubModelNodes(), [&](const ModelNode &node) { return node.metaInfo().isValid() && node.metaInfo().isBasedOn(type); }); } -QList ModelNode::subModelNodesOfType(const NodeMetaInfo &type) const +QList ModelNode::subModelNodesOfType(const NodeMetaInfo &type, SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node sub model nodes of type", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return Utils::filtered(allSubModelNodes(), [&](const ModelNode &node) { return node.metaInfo().isValid() && node.metaInfo().isBasedOn(type); }); @@ -655,16 +882,28 @@ All children in this list will be implicitly removed if this ModelNode is destro \return a list of all ModelNodes that are direct or indirect children */ -QList ModelNode::allSubModelNodes() const +QList ModelNode::allSubModelNodes(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node all sub model nodes", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return toModelNodeList(internalNode()->allSubNodes(), model(), view()); } -QList ModelNode::allSubModelNodesAndThisNode() const +QList ModelNode::allSubModelNodesAndThisNode(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node all sub model nodes and this node", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + QList modelNodeList; modelNodeList.append(*this); modelNodeList.append(allSubModelNodes()); @@ -678,17 +917,29 @@ QList ModelNode::allSubModelNodesAndThisNode() const \return if this ModelNode has any child ModelNodes */ -bool ModelNode::hasAnySubModelNodes() const +bool ModelNode::hasAnySubModelNodes(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has any sub model nodes", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return !nodeAbstractProperties().isEmpty(); } -NodeMetaInfo ModelNode::metaInfo() const +NodeMetaInfo ModelNode::metaInfo([[maybe_unused]] SL sl) const { if (!isValid()) return {}; #ifdef QDS_USE_PROJECTSTORAGE + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node meta info", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return NodeMetaInfo(m_internalNode->typeId, m_model->projectStorage()); #else return NodeMetaInfo(m_model->metaInfoProxyModel(), @@ -698,33 +949,51 @@ NodeMetaInfo ModelNode::metaInfo() const #endif } -bool ModelNode::hasMetaInfo() const +bool ModelNode::hasMetaInfo(SL sl) const { if (!isValid()) return false; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has meta info", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return model()->hasNodeMetaInfo(type(), majorVersion(), minorVersion()); } /*! \brief has a node the selection of the model \return true if the node his selection */ -bool ModelNode::isSelected() const +bool ModelNode::isSelected(SL sl) const { if (!isValid()) return false; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node is selected", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return model()->d->selectedNodes().contains(internalNode()); } /*! \briefis this node the root node of the model \return true if it is the root node */ -bool ModelNode::isRootNode() const +bool ModelNode::isRootNode(SL sl) const { if (!isValid()) return false; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node is root node", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_model->d->rootNode() == m_internalNode; } @@ -735,11 +1004,17 @@ The list of properties set in this state. \see addProperty property changePropertyValue removeProperty hasProperties */ -PropertyNameList ModelNode::propertyNames() const +PropertyNameList ModelNode::propertyNames(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node property names", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_internalNode->propertyNameList(); } @@ -765,33 +1040,63 @@ QList ModelNode::properties(PropertyType... type) const return properties; } -/*! \brief test a if a property is set for this node -\return true if property a property ins this or a ancestor state exists +/*! \brief test if a property is set for this node +\return true if property a property in this or a ancestor state exists */ -bool ModelNode::hasProperty(PropertyNameView name) const +bool ModelNode::hasProperty(PropertyNameView name, SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return isValid() && m_internalNode->property(name); } -bool ModelNode::hasVariantProperty(PropertyNameView name) const +bool ModelNode::hasVariantProperty(PropertyNameView name, SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has variant property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return hasProperty(name, PropertyType::Variant); } -bool ModelNode::hasBindingProperty(PropertyNameView name) const +bool ModelNode::hasBindingProperty(PropertyNameView name, SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has binding property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return hasProperty(name, PropertyType::Binding); } -bool ModelNode::hasSignalHandlerProperty(PropertyNameView name) const +bool ModelNode::hasSignalHandlerProperty(PropertyNameView name, SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has signal handler property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return hasProperty(name, PropertyType::SignalHandler); } -bool ModelNode::hasNodeAbstractProperty(PropertyNameView name) const +bool ModelNode::hasNodeAbstractProperty(PropertyNameView name, SL sl) const { if (!isValid()) - return false; + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has node abstract property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; if (auto property = m_internalNode->property(name)) return property->isNodeAbstractProperty(); @@ -799,38 +1104,74 @@ bool ModelNode::hasNodeAbstractProperty(PropertyNameView name) const return false; } -bool ModelNode::hasDefaultNodeAbstractProperty() const +bool ModelNode::hasDefaultNodeAbstractProperty(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has default node abstract property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + auto defaultPropertyName = metaInfo().defaultPropertyName(); return hasNodeAbstractProperty(defaultPropertyName); } -bool ModelNode::hasDefaultNodeListProperty() const +bool ModelNode::hasDefaultNodeListProperty(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has default node list property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + auto defaultPropertyName = metaInfo().defaultPropertyName(); return hasNodeListProperty(defaultPropertyName); } -bool ModelNode::hasDefaultNodeProperty() const +bool ModelNode::hasDefaultNodeProperty(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has default node property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + auto defaultPropertyName = metaInfo().defaultPropertyName(); return hasNodeProperty(defaultPropertyName); } -bool ModelNode::hasNodeProperty(PropertyNameView name) const +bool ModelNode::hasNodeProperty(PropertyNameView name, SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has node property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return hasProperty(name, PropertyType::Node); } -bool ModelNode::hasNodeListProperty(PropertyNameView name) const +bool ModelNode::hasNodeListProperty(PropertyNameView name, SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has node list property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return hasProperty(name, PropertyType::NodeList); } -bool ModelNode::hasProperty(PropertyNameView name, PropertyType propertyType) const +bool ModelNode::hasProperty(PropertyNameView name, PropertyType propertyType, SL sl) const { if (!isValid()) - return false; + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has property", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; if (auto property = m_internalNode->property(name)) return property->type() == propertyType; @@ -852,8 +1193,14 @@ static bool recursiveAncestor(const ModelNode &possibleAncestor, const ModelNode return false; } -bool ModelNode::isAncestorOf(const ModelNode &node) const +bool ModelNode::isAncestorOf(const ModelNode &node, SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node is ancestor of", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return recursiveAncestor(*this, node); } @@ -882,22 +1229,34 @@ QTextStream &operator<<(QTextStream &stream, const ModelNode &modelNode) return stream; } -void ModelNode::selectNode() +void ModelNode::selectNode(SL sl) { if (!isValid()) return; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node select node", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + QList selectedNodeList; selectedNodeList.append(*this); model()->setSelectedModelNodes(selectedNodeList); } -void ModelNode::deselectNode() +void ModelNode::deselectNode(SL sl) { if (!isValid()) return; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node deselect node", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + auto selectedNodes = model()->d->selectedNodes(); selectedNodes.removeAll(internalNode()); model()->d->setSelectedNodes(selectedNodes); @@ -908,34 +1267,74 @@ int ModelNode::variantTypeId() return qMetaTypeId(); } -QVariant ModelNode::toVariant() const +QVariant ModelNode::toVariant(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node to variant", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return QVariant::fromValue(*this); } -std::optional ModelNode::auxiliaryData(AuxiliaryDataKeyView key) const +std::optional ModelNode::auxiliaryData(AuxiliaryDataKeyView key, SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node auxiliary data", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_internalNode->auxiliaryData(key); } -std::optional ModelNode::auxiliaryData(AuxiliaryDataType type, Utils::SmallStringView name) const -{ - return auxiliaryData({type, name}); -} - -QVariant ModelNode::auxiliaryDataWithDefault(AuxiliaryDataType type, Utils::SmallStringView name) const -{ - return auxiliaryDataWithDefault({type, name}); -} - -QVariant ModelNode::auxiliaryDataWithDefault(AuxiliaryDataKeyView key) const +std::optional ModelNode::auxiliaryData(AuxiliaryDataType type, + Utils::SmallStringView name, + SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node auxiliary data with name", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + + return auxiliaryData({type, name}); +} + +QVariant ModelNode::auxiliaryDataWithDefault(AuxiliaryDataType type, + Utils::SmallStringView name, + SL sl) const +{ + if (!isValid()) + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node auxiliary data with default 1", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + + return auxiliaryDataWithDefault({type, name}); +} + +QVariant ModelNode::auxiliaryDataWithDefault(AuxiliaryDataKeyView key, SL sl) const +{ + if (!isValid()) + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node auxiliary data with default 2", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + auto data = m_internalNode->auxiliaryData(key); if (data) @@ -944,11 +1343,17 @@ QVariant ModelNode::auxiliaryDataWithDefault(AuxiliaryDataKeyView key) const return {}; } -QVariant ModelNode::auxiliaryDataWithDefault(AuxiliaryDataKeyDefaultValue key) const +QVariant ModelNode::auxiliaryDataWithDefault(AuxiliaryDataKeyDefaultValue key, SL sl) const { if (!isValid()) return toQVariant(key.defaultValue); + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node auxiliary data with default 3", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + auto data = m_internalNode->auxiliaryData(key); if (data) @@ -959,69 +1364,123 @@ QVariant ModelNode::auxiliaryDataWithDefault(AuxiliaryDataKeyDefaultValue key) c void ModelNode::setAuxiliaryData(AuxiliaryDataType type, Utils::SmallStringView name, - const QVariant &data) const + const QVariant &data, + SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set auxiliary data with type", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + setAuxiliaryData({type, name}, data); } -void ModelNode::setAuxiliaryData(AuxiliaryDataKeyView key, const QVariant &data) const +void ModelNode::setAuxiliaryData(AuxiliaryDataKeyView key, const QVariant &data, SL sl) const { - if (isValid()) { - if (key.type == AuxiliaryDataType::Persistent) - ensureIdExists(); - Internal::WriteLocker locker(m_model.data()); - m_model->d->setAuxiliaryData(internalNode(), key, data); - } + if (!isValid()) + return; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set auxiliary data with key", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + + if (key.type == AuxiliaryDataType::Persistent) + ensureIdExists(); + Internal::WriteLocker locker(m_model.data()); + m_model->d->setAuxiliaryData(internalNode(), key, data); } -void ModelNode::setAuxiliaryDataWithoutLock(AuxiliaryDataKeyView key, const QVariant &data) const +void ModelNode::setAuxiliaryDataWithoutLock(AuxiliaryDataKeyView key, const QVariant &data, SL sl) const { - if (isValid()) { - if (key.type == AuxiliaryDataType::Persistent) - ensureIdExists(); + if (!isValid()) + return; - m_model->d->setAuxiliaryData(internalNode(), key, data); - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set auxiliary data without lock with key", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + + if (key.type == AuxiliaryDataType::Persistent) + ensureIdExists(); + + m_model->d->setAuxiliaryData(internalNode(), key, data); } void ModelNode::setAuxiliaryDataWithoutLock(AuxiliaryDataType type, Utils::SmallStringView name, - const QVariant &data) const + const QVariant &data, + SL sl) const { - if (isValid()) { - if (type == AuxiliaryDataType::Persistent) - ensureIdExists(); + if (!isValid()) + return; - m_model->d->setAuxiliaryData(internalNode(), {type, name}, data); - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set auxiliary data without lock with type", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + + if (type == AuxiliaryDataType::Persistent) + ensureIdExists(); + + m_model->d->setAuxiliaryData(internalNode(), {type, name}, data); } -void ModelNode::removeAuxiliaryData(AuxiliaryDataKeyView key) const +void ModelNode::removeAuxiliaryData(AuxiliaryDataKeyView key, SL sl) const { - if (isValid()) { - if (key.type == AuxiliaryDataType::Persistent) - ensureIdExists(); + if (!isValid()) + return; - Internal::WriteLocker locker(m_model.data()); - m_model->d->removeAuxiliaryData(internalNode(), key); - } + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node remove auxiliary data with key", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + + if (key.type == AuxiliaryDataType::Persistent) + ensureIdExists(); + + Internal::WriteLocker locker(m_model.data()); + m_model->d->removeAuxiliaryData(internalNode(), key); } -void ModelNode::removeAuxiliaryData(AuxiliaryDataType type, Utils::SmallStringView name) const +void ModelNode::removeAuxiliaryData(AuxiliaryDataType type, Utils::SmallStringView name, SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node remove auxiliary data with type", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + removeAuxiliaryData({type, name}); } -bool ModelNode::hasAuxiliaryData(AuxiliaryDataKeyView key) const +bool ModelNode::hasAuxiliaryData(AuxiliaryDataKeyView key, SL sl) const { if (!isValid()) return false; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has auxiliary data with key", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_internalNode->hasAuxiliaryData(key); } -bool ModelNode::hasAuxiliaryData(AuxiliaryDataType type, Utils::SmallStringView name) const +bool ModelNode::hasAuxiliaryData(AuxiliaryDataType type, Utils::SmallStringView name, SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has auxiliary data with type", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return hasAuxiliaryData({type, name}); } @@ -1030,78 +1489,150 @@ bool ModelNode::hasAuxiliaryData(AuxiliaryDataType type) const if (!isValid()) return false; + // using NanotraceHR::keyValue; + // NanotraceHR::Tracer tracer{"model node has auxiliary data with type", + // category(), + // keyValue("type id", m_internalNode->typeId), + // keyValue("caller location", sl)}; + return m_internalNode->hasAuxiliaryData(type); } -AuxiliaryDatasForType ModelNode::auxiliaryData(AuxiliaryDataType type) const +AuxiliaryDatasForType ModelNode::auxiliaryData(AuxiliaryDataType type, SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node auxiliary data with type", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_internalNode->auxiliaryData(type); } -AuxiliaryDatasView ModelNode::auxiliaryData() const +AuxiliaryDatasView ModelNode::auxiliaryData(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node auxiliary data with sl", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_internalNode->auxiliaryData(); } -QString ModelNode::customId() const +QString ModelNode::customId(SL sl) const { auto data = auxiliaryData(customIdProperty); + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node custom id", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (data) return data->toString(); return {}; } -bool ModelNode::hasCustomId() const +bool ModelNode::hasCustomId(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has custom id", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return hasAuxiliaryData(customIdProperty); } -void ModelNode::setCustomId(const QString &str) +void ModelNode::setCustomId(const QString &str, SL sl) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set custom id", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + setAuxiliaryData(customIdProperty, QVariant::fromValue(str)); } -void ModelNode::removeCustomId() +void ModelNode::removeCustomId(SL sl) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node remove custom id", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + removeAuxiliaryData(customIdProperty); } -QVector ModelNode::comments() const +QVector ModelNode::comments(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node comments", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return annotation().comments(); } -bool ModelNode::hasComments() const +bool ModelNode::hasComments(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has comments", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return annotation().hasComments(); } -void ModelNode::setComments(const QVector &coms) +void ModelNode::setComments(const QVector &coms, SL sl) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set comments", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + Annotation anno = annotation(); anno.setComments(coms); setAnnotation(anno); } -void ModelNode::addComment(const Comment &com) +void ModelNode::addComment(const Comment &com, SL sl) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node add comment", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + Annotation anno = annotation(); anno.addComment(com); setAnnotation(anno); } -bool ModelNode::updateComment(const Comment &com, int position) +bool ModelNode::updateComment(const Comment &com, int position, SL sl) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node update comment", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + bool result = false; if (hasAnnotation()) { Annotation anno = annotation(); @@ -1115,8 +1646,14 @@ bool ModelNode::updateComment(const Comment &com, int position) return result; } -Annotation ModelNode::annotation() const +Annotation ModelNode::annotation(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node annotation", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + auto data = auxiliaryData(annotationProperty); if (data) @@ -1125,23 +1662,47 @@ Annotation ModelNode::annotation() const return {}; } -bool ModelNode::hasAnnotation() const +bool ModelNode::hasAnnotation(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has annotation", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return hasAuxiliaryData(annotationProperty); } -void ModelNode::setAnnotation(const Annotation &annotation) +void ModelNode::setAnnotation(const Annotation &annotation, SL sl) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set annotation", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + setAuxiliaryData(annotationProperty, QVariant::fromValue(annotation.toQString())); } -void ModelNode::removeAnnotation() +void ModelNode::removeAnnotation(SL sl) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node remove annotation", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + removeAuxiliaryData(annotationProperty); } -Annotation ModelNode::globalAnnotation() const +Annotation ModelNode::globalAnnotation(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node global annotation", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + Annotation result; ModelNode root = m_model->rootModelNode(); @@ -1153,24 +1714,47 @@ Annotation ModelNode::globalAnnotation() const return {}; } -bool ModelNode::hasGlobalAnnotation() const +bool ModelNode::hasGlobalAnnotation(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has global annotation", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_model->rootModelNode().hasAuxiliaryData(globalAnnotationProperty); } -void ModelNode::setGlobalAnnotation(const Annotation &annotation) +void ModelNode::setGlobalAnnotation(const Annotation &annotation, SL sl) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set global annotation", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; m_model->rootModelNode().setAuxiliaryData(globalAnnotationProperty, QVariant::fromValue(annotation.toQString())); } -void ModelNode::removeGlobalAnnotation() +void ModelNode::removeGlobalAnnotation(SL sl) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node remove global annotation", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + m_model->rootModelNode().removeAuxiliaryData(globalAnnotationProperty); } -GlobalAnnotationStatus ModelNode::globalStatus() const +GlobalAnnotationStatus ModelNode::globalStatus(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node global status", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + GlobalAnnotationStatus result; ModelNode root = m_model->rootModelNode(); @@ -1182,26 +1766,50 @@ GlobalAnnotationStatus ModelNode::globalStatus() const return result; } -bool ModelNode::hasGlobalStatus() const +bool ModelNode::hasGlobalStatus(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has global status", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_model->rootModelNode().hasAuxiliaryData(globalAnnotationStatus); } -void ModelNode::setGlobalStatus(const GlobalAnnotationStatus &status) +void ModelNode::setGlobalStatus(const GlobalAnnotationStatus &status, SL sl) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set global status", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + m_model->rootModelNode().setAuxiliaryData(globalAnnotationStatus, QVariant::fromValue(status.toQString())); } -void ModelNode::removeGlobalStatus() +void ModelNode::removeGlobalStatus(SL sl) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node remove global status", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (hasGlobalStatus()) { m_model->rootModelNode().removeAuxiliaryData(globalAnnotationStatus); } } -bool ModelNode::locked() const +bool ModelNode::locked(SL sl) const { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node locked", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + auto data = auxiliaryData(lockedProperty); if (data) @@ -1210,13 +1818,25 @@ bool ModelNode::locked() const return false; } -bool ModelNode::hasLocked() const +bool ModelNode::hasLocked(SL sl) const { - return hasAuxiliaryData(lockedProperty); + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node has locked", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + + return hasAuxiliaryData(lockedProperty, sl); } -void ModelNode::setLocked(bool value) +void ModelNode::setLocked(bool value, SL sl) { + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set locked", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (value) { setAuxiliaryData(lockedProperty, true); // Remove newly locked node and all its descendants from potential selection @@ -1230,50 +1850,80 @@ void ModelNode::setLocked(bool value) } } -void ModelNode::setScriptFunctions(const QStringList &scriptFunctionList) +void ModelNode::setScriptFunctions(const QStringList &scriptFunctionList, SL sl) { if (!isValid()) return; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set script functions", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + model()->d->setScriptFunctions(m_internalNode, scriptFunctionList); } -QStringList ModelNode::scriptFunctions() const +QStringList ModelNode::scriptFunctions(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node script functions", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_internalNode->scriptFunctions; } -qint32 ModelNode::internalId() const +qint32 ModelNode::internalId(SL sl) const { if (!m_internalNode) return -1; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node internal id", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_internalNode->internalId; } -void ModelNode::setNodeSource(const QString &newNodeSource) +void ModelNode::setNodeSource(const QString &newNodeSource, SL sl) { Internal::WriteLocker locker(m_model.data()); if (!isValid()) return; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set node source", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (m_internalNode->nodeSource == newNodeSource) return; m_model.data()->d->setNodeSource(m_internalNode, newNodeSource); } -void ModelNode::setNodeSource(const QString &newNodeSource, NodeSourceType type) +void ModelNode::setNodeSource(const QString &newNodeSource, NodeSourceType type, SL sl) { Internal::WriteLocker locker(m_model.data()); if (!isValid()) return; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node set node source with type", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (m_internalNode->nodeSourceType == type && m_internalNode->nodeSource == newNodeSource) return; @@ -1281,37 +1931,61 @@ void ModelNode::setNodeSource(const QString &newNodeSource, NodeSourceType type) m_model.data()->d->setNodeSource(m_internalNode, newNodeSource); } -QString ModelNode::nodeSource() const +QString ModelNode::nodeSource(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node node source", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_internalNode->nodeSource; } -QString ModelNode::convertTypeToImportAlias() const +QString ModelNode::convertTypeToImportAlias(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node convert type to import alias", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (model()->rewriterView()) return model()->rewriterView()->convertTypeToImportAlias(QString::fromLatin1(type())); return QString::fromLatin1(type()); } -ModelNode::NodeSourceType ModelNode::nodeSourceType() const +ModelNode::NodeSourceType ModelNode::nodeSourceType(SL sl) const { if (!isValid()) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node node source type", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return static_cast(m_internalNode->nodeSourceType); } -bool ModelNode::isComponent() const +bool ModelNode::isComponent(SL sl) const { if (!isValid()) - return false; + return {}; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node is component", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; if (!metaInfo().isValid()) return false; @@ -1364,12 +2038,18 @@ bool ModelNode::isComponent() const return false; } -QIcon ModelNode::typeIcon() const +QIcon ModelNode::typeIcon([[maybe_unused]] SL sl) const { #ifdef QDS_USE_PROJECTSTORAGE if (!isValid()) return QIcon(QStringLiteral(":/ItemLibrary/images/item-invalid-icon.png")); + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node type icon", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + if (auto iconPath = metaInfo().iconPath(); iconPath.size()) return QIcon(iconPath.toQString()); else @@ -1391,11 +2071,17 @@ QIcon ModelNode::typeIcon() const #endif } -QString ModelNode::behaviorPropertyName() const +QString ModelNode::behaviorPropertyName(SL sl) const { if (!m_internalNode) return {}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"model node behavior property name", + category(), + keyValue("type id", m_internalNode->typeId), + keyValue("caller location", sl)}; + return m_internalNode->behaviorPropertyName; } diff --git a/src/plugins/qmldesigner/libs/designercore/model/nodelistproperty.cpp b/src/plugins/qmldesigner/libs/designercore/model/nodelistproperty.cpp index c77771a52da..2428c6542ca 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/nodelistproperty.cpp +++ b/src/plugins/qmldesigner/libs/designercore/model/nodelistproperty.cpp @@ -67,7 +67,8 @@ void NodeListProperty::slide(int from, int to) const if (!isValid()) return; - if (to < 0 || to > count() - 1 || from < 0 || from > count() - 1) + const int count = this->count(); + if (to < 0 || to > count - 1 || from < 0 || from > count - 1) return; privateModel()->changeNodeOrder(internalNodeSharedPointer(), name(), from, to); diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/directorypathcompressor.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/directorypathcompressor.h index a13debc8326..f4b581caa76 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/directorypathcompressor.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/directorypathcompressor.h @@ -22,28 +22,26 @@ public: ~DirectoryPathCompressor() = default; - void addSourceContextId(SourceContextId sourceContextId) + void addDirectoryPathId(DirectoryPathId directoryPathId) { - auto found = std::lower_bound(m_sourceContextIds.begin(), - m_sourceContextIds.end(), - sourceContextId); + auto found = std::ranges::lower_bound(m_directoryPathIds, directoryPathId); - if (found == m_sourceContextIds.end() || *found != sourceContextId) - m_sourceContextIds.insert(found, sourceContextId); + if (found == m_directoryPathIds.end() || *found != directoryPathId) + m_directoryPathIds.insert(found, directoryPathId); restartTimer(); } - const SourceContextIds &sourceContextIds() { return m_sourceContextIds; } + const DirectoryPathIds &directoryPathIds() { return m_directoryPathIds; } - virtual void setCallback(std::function &&callback) + virtual void setCallback(std::function &&callback) { if (connection) QObject::disconnect(connection); connection = QObject::connect(&m_timer, &Timer::timeout, [this, callback = std::move(callback)] { try { - callback(m_sourceContextIds); - m_sourceContextIds.clear(); + callback(m_directoryPathIds); + m_directoryPathIds.clear(); } catch (const std::exception &) { } }); @@ -72,7 +70,7 @@ private: }; private: - SourceContextIds m_sourceContextIds; + DirectoryPathIds m_directoryPathIds; QMetaObject::Connection connection; ConnectionGuard connectionGuard{connection}; Timer m_timer; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/filestatus.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/filestatus.h index 289f8fd0394..1a29f957f6a 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/filestatus.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/filestatus.h @@ -25,24 +25,9 @@ public: && first.lastModified == second.lastModified; } - friend bool operator!=(const FileStatus &first, const FileStatus &second) + friend std::weak_ordering operator<=>(const FileStatus &first, const FileStatus &second) { - return !(first == second); - } - - friend bool operator<(const FileStatus &first, const FileStatus &second) - { - return first.sourceId < second.sourceId; - } - - friend bool operator<(SourceId first, const FileStatus &second) - { - return first < second.sourceId; - } - - friend bool operator<(const FileStatus &first, SourceId second) - { - return first.sourceId < second; + return first.sourceId <=> second.sourceId; } bool isExisting() const { return sourceId && size >= 0 && lastModified >= 0; } diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/filestatuscache.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/filestatuscache.cpp index 211ba40dc72..2629bebf181 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/filestatuscache.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/filestatuscache.cpp @@ -24,12 +24,7 @@ long long FileStatusCache::fileSize(SourceId sourceId) const void FileStatusCache::update(SourceId sourceId) { - auto found = std::lower_bound(m_cacheEntries.begin(), - m_cacheEntries.end(), - sourceId, - [](const auto &first, const auto &second) { - return first < second; - }); + auto found = std::ranges::lower_bound(m_cacheEntries, sourceId, {}, &FileStatus::sourceId); if (found != m_cacheEntries.end() && found->sourceId == sourceId) *found = m_fileSystem.fileStatus(sourceId); @@ -37,13 +32,12 @@ void FileStatusCache::update(SourceId sourceId) void FileStatusCache::update(SourceIds sourceIds) { - std::set_intersection(m_cacheEntries.begin(), - m_cacheEntries.end(), - sourceIds.begin(), - sourceIds.end(), - Utils::make_iterator([&](auto &entry) { - entry = m_fileSystem.fileStatus(entry.sourceId); - })); + Utils::set_greedy_intersection( + m_cacheEntries, + sourceIds, + [&](auto &entry) { entry = m_fileSystem.fileStatus(entry.sourceId); }, + {}, + &FileStatus::sourceId); } SourceIds FileStatusCache::modified(SourceIds sourceIds) const @@ -51,44 +45,43 @@ SourceIds FileStatusCache::modified(SourceIds sourceIds) const SourceIds modifiedSourceIds; modifiedSourceIds.reserve(sourceIds.size()); - std::set_intersection(m_cacheEntries.begin(), - m_cacheEntries.end(), - sourceIds.begin(), - sourceIds.end(), - Utils::make_iterator([&](auto &entry) { - auto fileStatus = m_fileSystem.fileStatus(entry.sourceId); - if (fileStatus != entry) { - modifiedSourceIds.push_back(entry.sourceId); - entry = fileStatus; - } - })); + Utils::set_greedy_intersection( + m_cacheEntries, + sourceIds, + [&](auto &entry) { + auto fileStatus = m_fileSystem.fileStatus(entry.sourceId); + if (fileStatus != entry) { + modifiedSourceIds.push_back(entry.sourceId); + entry = fileStatus; + } + }, + {}, + &FileStatus::sourceId); FileStatuses newEntries; newEntries.reserve(sourceIds.size()); - std::set_difference(sourceIds.begin(), - sourceIds.end(), - m_cacheEntries.begin(), - m_cacheEntries.end(), - Utils::make_iterator([&](SourceId newSourceId) { - newEntries.push_back(m_fileSystem.fileStatus(newSourceId)); - modifiedSourceIds.push_back(newSourceId); - })); + Utils::set_greedy_difference( + sourceIds, + m_cacheEntries, + [&](SourceId newSourceId) { + newEntries.push_back(m_fileSystem.fileStatus(newSourceId)); + modifiedSourceIds.push_back(newSourceId); + }, + {}, + {}, + &FileStatus::sourceId); if (newEntries.size()) { FileStatuses mergedEntries; mergedEntries.reserve(m_cacheEntries.size() + newEntries.size()); - std::set_union(newEntries.begin(), - newEntries.end(), - m_cacheEntries.begin(), - m_cacheEntries.end(), - std::back_inserter(mergedEntries)); + std::ranges::set_union(newEntries, m_cacheEntries, std::back_inserter(mergedEntries)); m_cacheEntries = std::move(mergedEntries); } - std::sort(modifiedSourceIds.begin(), modifiedSourceIds.end()); + std::ranges::sort(modifiedSourceIds); return modifiedSourceIds; } @@ -100,12 +93,7 @@ FileStatusCache::size_type FileStatusCache::size() const const FileStatus &FileStatusCache::find(SourceId sourceId) const { - auto found = std::lower_bound(m_cacheEntries.begin(), - m_cacheEntries.end(), - sourceId, - [](const auto &first, const auto &second) { - return first < second; - }); + auto found = std::ranges::lower_bound(m_cacheEntries, sourceId, {}, &FileStatus::sourceId); if (found != m_cacheEntries.end() && found->sourceId == sourceId) return *found; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.cpp index a06c2d527ff..feef28c5a35 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.cpp @@ -50,8 +50,8 @@ long long FileSystem::lastModified(SourceId sourceId) const FileStatus FileSystem::fileStatus(SourceId sourceId) const { - auto path = sourceId.mainId() ? m_sourcePathCache.sourcePath(sourceId) - : m_sourcePathCache.sourceContextPath(sourceId.contextId()); + auto path = sourceId.fileNameId() ? m_sourcePathCache.sourcePath(sourceId) + : m_sourcePathCache.directoryPath(sourceId.directoryPathId()); QFileInfo fileInfo(QString{path}); fileInfo.refresh(); diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp index f7dfa4bcaac..c342d5667a1 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.cpp @@ -870,7 +870,7 @@ struct ProjectStorage::Statements " USING(moduleId) " " WHERE di.sourceId=?)", database}; - mutable Sqlite::ReadStatement<4, 2> selectLocalFileItemLibraryEntriesBySourceIdStatement{ + mutable Sqlite::ReadStatement<4, 2> selectDirectoryImportsItemLibraryEntriesBySourceIdStatement{ "SELECT typeId, etn.name, m.name, t.sourceId " "FROM documentImports AS di " " JOIN exportedTypeNames AS etn USING(moduleId) " @@ -1424,7 +1424,8 @@ ModuleId ProjectStorage::moduleId(Utils::SmallStringView moduleName, Storage::Mo using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"get module id", projectStorageCategory(), - keyValue("module name", moduleName)}; + keyValue("module name", moduleName), + keyValue("module kind", kind)}; if (moduleName.empty()) return ModuleId{}; @@ -1436,6 +1437,27 @@ ModuleId ProjectStorage::moduleId(Utils::SmallStringView moduleName, Storage::Mo return moduleId; } +SmallModuleIds<128> ProjectStorage::moduleIdsStartsWith(Utils::SmallStringView startsWith, + Storage::ModuleKind kind) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get module ids that starts with", + projectStorageCategory(), + keyValue("module name starts with", startsWith), + keyValue("module kind", kind)}; + + if (startsWith.isEmpty()) + return {}; + + auto projection = [&](ModuleView view) -> ModuleView { + return {view.name.substr(0, startsWith.size()), view.kind}; + }; + + auto moduleIds = moduleCache.ids<128>({startsWith, kind}, projection); + + return moduleIds; +} + Storage::Module ProjectStorage::module(ModuleId moduleId) const { using NanotraceHR::keyValue; @@ -1762,7 +1784,7 @@ Storage::Info::TypeHints ProjectStorage::typeHints(TypeId typeId) const return typeHints; } -SmallSourceIds<4> ProjectStorage::typeAnnotationSourceIds(SourceContextId directoryId) const +SmallSourceIds<4> ProjectStorage::typeAnnotationSourceIds(DirectoryPathId directoryId) const { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"get type annotaion source ids", @@ -1777,13 +1799,13 @@ SmallSourceIds<4> ProjectStorage::typeAnnotationSourceIds(SourceContextId direct return sourceIds; } -SmallSourceContextIds<64> ProjectStorage::typeAnnotationDirectoryIds() const +SmallDirectoryPathIds<64> ProjectStorage::typeAnnotationDirectoryIds() const { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"get type annotaion source ids", projectStorageCategory()}; auto sourceIds = s->selectTypeAnnotationDirectoryIdsStatement - .valuesWithTransaction>(); + .valuesWithTransaction>(); tracer.end(keyValue("source ids", sourceIds)); @@ -1877,16 +1899,16 @@ Storage::Info::ItemLibraryEntries ProjectStorage::itemLibraryEntries(SourceId so using Storage::Info::ItemLibraryProperties; Storage::Info::ItemLibraryEntries entries; - auto typeAnnotationCallback = [&](TypeId typeId, - Utils::SmallStringView typeName, - Utils::SmallStringView name, - Utils::SmallStringView iconPath, - Utils::SmallStringView category, - Utils::SmallStringView import, - Utils::SmallStringView toolTip, - Utils::SmallStringView properties, - Utils::SmallStringView extraFilePaths, - Utils::SmallStringView templatePath) { + auto callback = [&](TypeId typeId, + Utils::SmallStringView typeName, + Utils::SmallStringView name, + Utils::SmallStringView iconPath, + Utils::SmallStringView category, + Utils::SmallStringView import, + Utils::SmallStringView toolTip, + Utils::SmallStringView properties, + Utils::SmallStringView extraFilePaths, + Utils::SmallStringView templatePath) { auto &last = entries.emplace_back( typeId, typeName, name, iconPath, category, import, toolTip, templatePath); if (properties.size()) @@ -1895,23 +1917,7 @@ Storage::Info::ItemLibraryEntries ProjectStorage::itemLibraryEntries(SourceId so s->selectItemLibraryExtraFilePathsStatement.readTo(last.extraFilePaths, extraFilePaths); }; - s->selectItemLibraryEntriesBySourceIdStatement.readCallbackWithTransaction(typeAnnotationCallback, - sourceId); - - auto fileComponentCallback = [&](TypeId typeId, - Utils::SmallStringView typeName, - Utils::SmallStringView import, - SourceId componentSourceId) { - if (!isCapitalLetter(typeName.front())) - return; - - auto &last = entries.emplace_back(typeId, typeName, typeName, "My Components", import); - last.moduleKind = Storage::ModuleKind::PathLibrary; - last.componentSourceId = componentSourceId; - }; - - s->selectLocalFileItemLibraryEntriesBySourceIdStatement.readCallbackWithTransaction( - fileComponentCallback, sourceId, Storage::ModuleKind::PathLibrary); + s->selectItemLibraryEntriesBySourceIdStatement.readCallbackWithTransaction(callback, sourceId); tracer.end(keyValue("item library entries", entries)); @@ -1951,6 +1957,36 @@ Storage::Info::ItemLibraryEntries ProjectStorage::allItemLibraryEntries() const return entries; } +Storage::Info::ItemLibraryEntries ProjectStorage::directoryImportsItemLibraryEntries(SourceId sourceId) const +{ + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get directory import item library entries", + projectStorageCategory(), + keyValue("source id", sourceId)}; + + using Storage::Info::ItemLibraryProperties; + Storage::Info::ItemLibraryEntries entries; + + auto callback = [&](TypeId typeId, + Utils::SmallStringView typeName, + Utils::SmallStringView import, + SourceId componentSourceId) { + if (!isCapitalLetter(typeName.front())) + return; + + auto &last = entries.emplace_back(typeId, typeName, typeName, "My Components", import); + last.moduleKind = Storage::ModuleKind::PathLibrary; + last.componentSourceId = componentSourceId; + }; + + s->selectDirectoryImportsItemLibraryEntriesBySourceIdStatement + .readCallbackWithTransaction(callback, sourceId, Storage::ModuleKind::PathLibrary); + + tracer.end(keyValue("item library entries", entries)); + + return entries; +} + std::vector ProjectStorage::signalDeclarationNames(TypeId typeId) const { using NanotraceHR::keyValue; @@ -2212,7 +2248,7 @@ std::optional ProjectStorage::fetchDire return directoryInfo; } -Storage::Synchronization::DirectoryInfos ProjectStorage::fetchDirectoryInfos(SourceContextId directoryId) const +Storage::Synchronization::DirectoryInfos ProjectStorage::fetchDirectoryInfos(DirectoryPathId directoryId) const { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"fetch directory infos by directory id", @@ -2229,7 +2265,7 @@ Storage::Synchronization::DirectoryInfos ProjectStorage::fetchDirectoryInfos(Sou } Storage::Synchronization::DirectoryInfos ProjectStorage::fetchDirectoryInfos( - SourceContextId directoryId, Storage::Synchronization::FileType fileType) const + DirectoryPathId directoryId, Storage::Synchronization::FileType fileType) const { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"fetch directory infos by source id and file type", @@ -2247,7 +2283,7 @@ Storage::Synchronization::DirectoryInfos ProjectStorage::fetchDirectoryInfos( } Storage::Synchronization::DirectoryInfos ProjectStorage::fetchDirectoryInfos( - const SourceContextIds &directoryIds) const + const DirectoryPathIds &directoryIds) const { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"fetch directory infos by source ids", @@ -2256,14 +2292,14 @@ Storage::Synchronization::DirectoryInfos ProjectStorage::fetchDirectoryInfos( auto directoryInfos = s->selectDirectoryInfosForDirectoryIdsStatement .valuesWithTransaction( - toIntegers(directoryIds)); + Sqlite::toIntegers(directoryIds)); tracer.end(keyValue("directory infos", directoryInfos)); return directoryInfos; } -SmallSourceContextIds<32> ProjectStorage::fetchSubdirectoryIds(SourceContextId directoryId) const +SmallDirectoryPathIds<32> ProjectStorage::fetchSubdirectoryIds(DirectoryPathId directoryId) const { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"fetch subdirectory source ids", @@ -2274,9 +2310,9 @@ SmallSourceContextIds<32> ProjectStorage::fetchSubdirectoryIds(SourceContextId d .rangeWithTransaction(directoryId, Storage::Synchronization::FileType::Directory); - SmallSourceContextIds<32> directoryIds; + SmallDirectoryPathIds<32> directoryIds; for (SourceId sourceId : sourceIds) - directoryIds.push_back(sourceId.contextId()); + directoryIds.push_back(sourceId.directoryPathId()); tracer.end(keyValue("directory ids", directoryIds)); @@ -2408,7 +2444,7 @@ TypeIds ProjectStorage::fetchTypeIds(const SourceIds &sourceIds) projectStorageCategory(), keyValue("source ids", sourceIds)}; - return s->selectTypeIdsForSourceIdsStatement.values(toIntegers(sourceIds)); + return s->selectTypeIdsForSourceIdsStatement.values(Sqlite::toIntegers(sourceIds)); } void ProjectStorage::unique(SourceIds &sourceIds) @@ -2453,7 +2489,7 @@ void ProjectStorage::synchronizeTypeAnnotations(Storage::Synchronization::TypeAn std::ranges::sort(typeAnnotations, {}, &TypeAnnotation::typeId); auto range = s->selectTypeAnnotationsForSourceIdsStatement.range( - toIntegers(updatedTypeAnnotationSourceIds)); + Sqlite::toIntegers(updatedTypeAnnotationSourceIds)); auto insert = [&](const TypeAnnotation &annotation) { if (!annotation.sourceId) @@ -2595,7 +2631,7 @@ void ProjectStorage::synchronizeTypes(Storage::Synchronization::Types &types, } void ProjectStorage::synchronizeDirectoryInfos(Storage::Synchronization::DirectoryInfos &directoryInfos, - const SourceContextIds &updatedDirectoryInfoDirectoryIds) + const DirectoryPathIds &updatedDirectoryInfoDirectoryIds) { NanotraceHR::Tracer tracer{"synchronize directory infos", projectStorageCategory()}; @@ -2611,7 +2647,7 @@ void ProjectStorage::synchronizeDirectoryInfos(Storage::Synchronization::Directo auto range = s->selectDirectoryInfosForDirectoryIdsStatement .range( - toIntegers(updatedDirectoryInfoDirectoryIds)); + Sqlite::toIntegers(updatedDirectoryInfoDirectoryIds)); auto insert = [&](const Storage::Synchronization::DirectoryInfo &directoryInfo) { using NanotraceHR::keyValue; @@ -2673,7 +2709,7 @@ void ProjectStorage::synchronizeFileStatuses(FileStatuses &fileStatuses, std::ranges::sort(fileStatuses, {}, &FileStatus::sourceId); auto range = s->selectFileStatusesForSourceIdsStatement.range( - toIntegers(updatedSourceIds)); + Sqlite::toIntegers(updatedSourceIds)); auto insert = [&](const FileStatus &fileStatus) { using NanotraceHR::keyValue; @@ -2761,7 +2797,7 @@ void ProjectStorage::synchromizeModuleExportedImports( auto range = s->selectModuleExportedImportsForSourceIdStatement .range( - toIntegers(updatedModuleIds)); + Sqlite::toIntegers(updatedModuleIds)); auto compareKey = [](const Storage::Synchronization::ModuleExportedImportView &view, const Storage::Synchronization::ModuleExportedImport &import) { @@ -3179,8 +3215,8 @@ void ProjectStorage::deleteNotUpdatedTypes(const TypeIds &updatedTypeIds, }; s->selectNotUpdatedTypesInSourcesStatement.readCallback(callback, - toIntegers(updatedSourceIds), - toIntegers(updatedTypeIds)); + Sqlite::toIntegers(updatedSourceIds), + Sqlite::toIntegers(updatedTypeIds)); for (TypeId typeIdToBeDeleted : typeIdsToBeDeleted) callback(typeIdToBeDeleted); } @@ -3354,7 +3390,8 @@ void ProjectStorage::synchronizeExportedTypes( }); auto range = s->selectExportedTypesForSourceIdsStatement - .range(toIntegers(updatedTypeIds)); + .range( + Sqlite::toIntegers(updatedTypeIds)); auto compareKey = [](const Storage::Synchronization::ExportedTypeView &view, const Storage::Synchronization::ExportedType &type) { @@ -3901,7 +3938,7 @@ void ProjectStorage::synchronizeDocumentImports(Storage::Imports &imports, }); auto range = s->selectDocumentImportForSourceIdStatement - .range(toIntegers(updatedSourceIds), + .range(Sqlite::toIntegers(updatedSourceIds), importKind); auto compareKey = [](const Storage::Synchronization::ImportView &view, @@ -4043,13 +4080,13 @@ void ProjectStorage::addTypeIdToPropertyEditorQmlPaths( void ProjectStorage::synchronizePropertyEditorPaths( Storage::Synchronization::PropertyEditorQmlPaths &paths, - SourceContextIds updatedPropertyEditorQmlPathsSourceContextIds) + DirectoryPathIds updatedPropertyEditorQmlPathsDirectoryPathIds) { using Storage::Synchronization::PropertyEditorQmlPath; std::ranges::sort(paths, {}, &PropertyEditorQmlPath::typeId); auto range = s->selectPropertyEditorPathsForForSourceIdsStatement.range( - toIntegers(updatedPropertyEditorQmlPathsSourceContextIds)); + Sqlite::toIntegers(updatedPropertyEditorQmlPathsDirectoryPathIds)); auto compareKey = [](const PropertyEditorQmlPathView &view, const PropertyEditorQmlPath &value) { return view.typeId <=> value.typeId; @@ -4096,7 +4133,7 @@ void ProjectStorage::synchronizePropertyEditorPaths( void ProjectStorage::synchronizePropertyEditorQmlPaths( Storage::Synchronization::PropertyEditorQmlPaths &paths, - SourceContextIds updatedPropertyEditorQmlPathsSourceIds) + DirectoryPathIds updatedPropertyEditorQmlPathsSourceIds) { NanotraceHR::Tracer tracer{"synchronize property editor qml paths", projectStorageCategory()}; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.h index 1e6d287abe2..ba09dac0ca5 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorage.h @@ -62,6 +62,9 @@ public: ModuleId moduleId(Utils::SmallStringView moduleName, Storage::ModuleKind kind) const override; + SmallModuleIds<128> moduleIdsStartsWith(Utils::SmallStringView startsWith, + Storage::ModuleKind kind) const override; + Storage::Module module(ModuleId moduleId) const override; TypeId typeId(ModuleId moduleId, @@ -105,17 +108,15 @@ public: Storage::Info::TypeHints typeHints(TypeId typeId) const override; - SmallSourceIds<4> typeAnnotationSourceIds(SourceContextId directoryId) const override; + SmallSourceIds<4> typeAnnotationSourceIds(DirectoryPathId directoryId) const override; - SmallSourceContextIds<64> typeAnnotationDirectoryIds() const override; + SmallDirectoryPathIds<64> typeAnnotationDirectoryIds() const override; Storage::Info::ItemLibraryEntries itemLibraryEntries(TypeId typeId) const override; - Storage::Info::ItemLibraryEntries itemLibraryEntries(ImportId importId) const; - Storage::Info::ItemLibraryEntries itemLibraryEntries(SourceId sourceId) const override; - Storage::Info::ItemLibraryEntries allItemLibraryEntries() const override; + Storage::Info::ItemLibraryEntries directoryImportsItemLibraryEntries(SourceId sourceId) const override; std::vector signalDeclarationNames(TypeId typeId) const override; @@ -222,11 +223,11 @@ public: std::optional fetchDirectoryInfo(SourceId sourceId) const override; - Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(SourceContextId directoryId) const override; + Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(DirectoryPathId directoryId) const override; Storage::Synchronization::DirectoryInfos fetchDirectoryInfos( - SourceContextId directoryId, Storage::Synchronization::FileType fileType) const override; - Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(const SourceContextIds &directoryIds) const; - SmallSourceContextIds<32> fetchSubdirectoryIds(SourceContextId directoryId) const override; + DirectoryPathId directoryId, Storage::Synchronization::FileType fileType) const override; + Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(const DirectoryPathIds &directoryIds) const; + SmallDirectoryPathIds<32> fetchSubdirectoryIds(DirectoryPathId directoryId) const override; void setPropertyEditorPathId(TypeId typeId, SourceId pathId); @@ -254,9 +255,9 @@ private: Utils::SmallStringView name; Storage::ModuleKind kind; - friend bool operator<(ModuleView first, ModuleView second) + friend std::strong_ordering operator<=>(ModuleView first, ModuleView second) { - return std::tie(first.kind, first.name) < std::tie(second.kind, second.name); + return std::tie(first.kind, first.name) <=> std::tie(second.kind, second.name); } friend bool operator==(const Storage::Module &first, ModuleView second) @@ -284,10 +285,13 @@ private: friend ModuleStorageAdapter; - static bool moduleNameLess(ModuleView first, ModuleView second) noexcept + struct ModuleNameLess { - return first < second; - } + bool operator()(ModuleView first, ModuleView second) const noexcept + { + return first < second; + } + }; class ModuleCacheEntry : public StorageCacheEntry { @@ -314,7 +318,7 @@ private: using ModuleCacheEntries = std::vector; using ModuleCache - = StorageCache; + = StorageCache; ModuleId fetchModuleId(Utils::SmallStringView moduleName, Storage::ModuleKind moduleKind); @@ -363,8 +367,8 @@ private: , sourceId{sourceId} {} - friend auto operator<=>(const AliasPropertyDeclaration &first, - const AliasPropertyDeclaration &second) + friend std::weak_ordering operator<=>(const AliasPropertyDeclaration &first, + const AliasPropertyDeclaration &second) { return std::tie(first.typeId, first.propertyDeclarationId) <=> std::tie(second.typeId, second.propertyDeclarationId); @@ -433,7 +437,8 @@ private: == std::tie(second.typeId, second.propertyDeclarationId); } - friend auto operator<=>(const PropertyDeclaration &first, const PropertyDeclaration &second) + friend std::weak_ordering operator<=>(const PropertyDeclaration &first, + const PropertyDeclaration &second) { return std::tie(first.typeId, first.propertyDeclarationId) <=> std::tie(second.typeId, second.propertyDeclarationId); @@ -469,7 +474,7 @@ private: , prototypeNameId{std::move(prototypeNameId)} {} - friend auto operator<=>(Prototype first, Prototype second) + friend std::weak_ordering operator<=>(Prototype first, Prototype second) { return first.typeId <=> second.typeId; } @@ -572,7 +577,7 @@ private: const SourceIds &updatedSourceIds); void synchronizeDirectoryInfos(Storage::Synchronization::DirectoryInfos &directoryInfos, - const SourceContextIds &updatedDirectoryInfoDirectoryIds); + const DirectoryPathIds &updatedDirectoryInfoDirectoryIds); void synchronizeFileStatuses(FileStatuses &fileStatuses, const SourceIds &updatedSourceIds); @@ -787,7 +792,7 @@ private: class PropertyEditorQmlPathView { public: - PropertyEditorQmlPathView(TypeId typeId, SourceId pathId, SourceContextId directoryId) + PropertyEditorQmlPathView(TypeId typeId, SourceId pathId, DirectoryPathId directoryId) : typeId{typeId} , pathId{pathId} , directoryId{directoryId} @@ -809,14 +814,14 @@ private: public: TypeId typeId; SourceId pathId; - SourceContextId directoryId; + DirectoryPathId directoryId; }; void synchronizePropertyEditorPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths, - SourceContextIds updatedPropertyEditorQmlPathsSourceContextIds); + DirectoryPathIds updatedPropertyEditorQmlPathsDirectoryPathIds); void synchronizePropertyEditorQmlPaths(Storage::Synchronization::PropertyEditorQmlPaths &paths, - SourceContextIds updatedPropertyEditorQmlPathsSourceIds); + DirectoryPathIds updatedPropertyEditorQmlPathsSourceIds); void synchronizeFunctionDeclarations( TypeId typeId, Storage::Synchronization::FunctionDeclarations &functionsDeclarations); diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageerrornotifierinterface.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageerrornotifierinterface.h index 34cb1638d66..df4efdc89b6 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageerrornotifierinterface.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageerrornotifierinterface.h @@ -31,6 +31,8 @@ public: SourceId qmldirSourceId) = 0; + virtual void qmltypesFileMissing(QStringView qmltypesPath) = 0; + protected: ~ProjectStorageErrorNotifierInterface() = default; }; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h index cc04ca19f18..947bcf73980 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h @@ -32,6 +32,8 @@ public: virtual void removeObserver(ProjectStorageObserver *observer) = 0; virtual ModuleId moduleId(::Utils::SmallStringView name, Storage::ModuleKind kind) const = 0; + virtual SmallModuleIds<128> + moduleIdsStartsWith(Utils::SmallStringView startsWith, Storage::ModuleKind kind) const = 0; virtual QmlDesigner::Storage::Module module(ModuleId moduleId) const = 0; virtual std::optional propertyDeclaration(PropertyDeclarationId propertyDeclarationId) const = 0; @@ -58,13 +60,14 @@ public: = 0; virtual PropertyDeclarationId defaultPropertyDeclarationId(TypeId typeId) const = 0; virtual std::optional type(TypeId typeId) const = 0; - virtual SmallSourceIds<4> typeAnnotationSourceIds(SourceContextId directoryId) const = 0; - virtual SmallSourceContextIds<64> typeAnnotationDirectoryIds() const = 0; + virtual SmallSourceIds<4> typeAnnotationSourceIds(DirectoryPathId directoryId) const = 0; + virtual SmallDirectoryPathIds<64> typeAnnotationDirectoryIds() const = 0; virtual Utils::PathString typeIconPath(TypeId typeId) const = 0; virtual Storage::Info::TypeHints typeHints(TypeId typeId) const = 0; virtual Storage::Info::ItemLibraryEntries itemLibraryEntries(TypeId typeId) const = 0; virtual Storage::Info::ItemLibraryEntries itemLibraryEntries(SourceId sourceId) const = 0; virtual Storage::Info::ItemLibraryEntries allItemLibraryEntries() const = 0; + virtual Storage::Info::ItemLibraryEntries directoryImportsItemLibraryEntries(SourceId sourceId) const = 0; virtual std::vector<::Utils::SmallString> signalDeclarationNames(TypeId typeId) const = 0; virtual std::vector<::Utils::SmallString> functionDeclarationNames(TypeId typeId) const = 0; virtual std::optional<::Utils::SmallString> @@ -81,13 +84,13 @@ public: virtual bool isBasedOn(TypeId, TypeId, TypeId, TypeId, TypeId, TypeId, TypeId, TypeId) const = 0; virtual FileStatus fetchFileStatus(SourceId sourceId) const = 0; - virtual Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(SourceContextId directoryId) const = 0; + virtual Storage::Synchronization::DirectoryInfos fetchDirectoryInfos(DirectoryPathId directoryId) const = 0; virtual Storage::Synchronization::DirectoryInfos fetchDirectoryInfos( - SourceContextId directoryId, Storage::Synchronization::FileType) const + DirectoryPathId directoryId, Storage::Synchronization::FileType) const = 0; virtual std::optional fetchDirectoryInfo(SourceId sourceId) const = 0; - virtual SmallSourceContextIds<32> fetchSubdirectoryIds(SourceContextId directoryId) const = 0; + virtual SmallDirectoryPathIds<32> fetchSubdirectoryIds(DirectoryPathId directoryId) const = 0; virtual SourceId propertyEditorPathId(TypeId typeId) const = 0; virtual const Storage::Info::CommonTypeCache &commonTypeCache() const = 0; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcher.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcher.h index 8fe2ba60e0a..cb01fefcb10 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcher.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcher.h @@ -8,33 +8,20 @@ #include "projectstoragepathwatcherinterface.h" #include "projectstoragepathwatchernotifierinterface.h" #include "projectstoragepathwatchertypes.h" +#include "projectstoragetriggerupdateinterface.h" #include #include +#include #include namespace QmlDesigner { -template -void set_greedy_intersection_call( - InputIt1 first1, InputIt1 last1, InputIt2 first2, InputIt2 last2, Callable callable) -{ - while (first1 != last1 && first2 != last2) { - if (*first1 < *first2) { - ++first1; - } else { - if (*first2 < *first1) - ++first2; - else - callable(*first1++); - } - } -} - template -class ProjectStoragePathWatcher : public ProjectStoragePathWatcherInterface +class ProjectStoragePathWatcher : public ProjectStoragePathWatcherInterface, + public ProjectStorageTriggerUpdateInterface { public: ProjectStoragePathWatcher(SourcePathCache &pathCache, @@ -49,8 +36,8 @@ public: [&](const QString &path) { compressChangedDirectoryPath(path); }); m_directoryPathCompressor.setCallback( - [&](const QmlDesigner::SourceContextIds &sourceContextIds) { - addChangedPathForFilePath(sourceContextIds); + [&](const QmlDesigner::DirectoryPathIds &directoryPathIds) { + addChangedPathForFilePath(directoryPathIds); }); } @@ -61,28 +48,35 @@ public: addEntries(entires); auto notContainsdId = [&, &ids = ids](WatcherEntry entry) { - return !std::binary_search(ids.begin(), ids.end(), entry.id); + return !std::ranges::binary_search(ids, entry.id); }; removeUnusedEntries(entires, notContainsdId); } void updateContextIdPaths(const std::vector &idPaths, - const SourceContextIds &sourceContextIds) override + const DirectoryPathIds &directoryPathIds) override { const auto &[entires, ids] = convertIdPathsToWatcherEntriesAndIds(idPaths); addEntries(entires); auto notContainsId = [&, &ids = ids](WatcherEntry entry) { - return !std::binary_search(ids.begin(), ids.end(), entry.id) - || !std::binary_search(sourceContextIds.begin(), - sourceContextIds.end(), - entry.sourceContextId); + return !std::ranges::binary_search(ids, entry.id) + || !std::ranges::binary_search(directoryPathIds, entry.directoryPathId); }; removeUnusedEntries(entires, notContainsId); } + void checkForChangeInDirectory(DirectoryPathIds directoryPathIds) override + { + std::ranges::sort(directoryPathIds); + auto removed = std::ranges::unique(directoryPathIds); + directoryPathIds.erase(removed.begin(), removed.end()); + + addChangedPathForFilePath(directoryPathIds); + } + void removeIds(const ProjectPartIds &ids) override { auto removedEntries = removeIdsFromWatchedEntries(ids); @@ -115,28 +109,24 @@ public: ProjectChunkIds ids; ids.reserve(ids.size()); - auto outputIterator = std::back_inserter(entries); - for (const IdPaths &idPath : idPaths) { ProjectChunkId id = idPath.id; ids.push_back(id); - outputIterator = std::transform(idPath.sourceIds.begin(), - idPath.sourceIds.end(), - outputIterator, - [&](SourceId sourceId) { - return WatcherEntry{id, - sourceId.contextId(), - sourceId, - m_fileStatusCache.lastModifiedTime( - sourceId)}; - }); + std::ranges::transform(idPath.sourceIds, std::back_inserter(entries), [&](SourceId sourceId) { + auto fileStatus = m_fileStatusCache.find(sourceId); + return WatcherEntry{id, + sourceId.directoryPathId(), + sourceId, + fileStatus.lastModified, + fileStatus.size}; + }); } - std::sort(entries.begin(), entries.end()); - std::sort(ids.begin(), ids.end()); + std::ranges::sort(entries); + std::ranges::sort(ids); return {entries, ids}; } @@ -168,23 +158,23 @@ public: FileSystemWatcher &fileSystemWatcher() { return m_fileSystemWatcher; } - QStringList convertWatcherEntriesToDirectoryPathList(const SourceContextIds &sourceContextIds) const + QStringList convertWatcherEntriesToDirectoryPathList(const DirectoryPathIds &directoryPathIds) const { - return Utils::transform(sourceContextIds, [&](SourceContextId id) { - return QString(m_pathCache.sourceContextPath(id)); + return Utils::transform(directoryPathIds, [&](DirectoryPathId id) { + return QString(m_pathCache.directoryPath(id)); }); } QStringList convertWatcherEntriesToDirectoryPathList(const WatcherEntries &watcherEntries) const { - SourceContextIds sourceContextIds = Utils::transform( - watcherEntries, &WatcherEntry::sourceContextId); + DirectoryPathIds directoryPathIds = Utils::transform( + watcherEntries, &WatcherEntry::directoryPathId); - std::sort(sourceContextIds.begin(), sourceContextIds.end()); - sourceContextIds.erase(std::unique(sourceContextIds.begin(), sourceContextIds.end()), - sourceContextIds.end()); + std::ranges::sort(directoryPathIds); + auto removed = std::ranges::unique(directoryPathIds); + directoryPathIds.erase(removed.begin(), removed.end()); - return convertWatcherEntriesToDirectoryPathList(sourceContextIds); + return convertWatcherEntriesToDirectoryPathList(directoryPathIds); } WatcherEntries notWatchedEntries(const WatcherEntries &entries) const @@ -192,25 +182,17 @@ public: WatcherEntries notWatchedEntries; notWatchedEntries.reserve(entries.size()); - std::set_difference(entries.begin(), - entries.end(), - m_watchedEntries.cbegin(), - m_watchedEntries.cend(), - std::back_inserter(notWatchedEntries)); + std::ranges::set_difference(entries, m_watchedEntries, std::back_inserter(notWatchedEntries)); return notWatchedEntries; } - SourceContextIds notWatchedPaths(const SourceContextIds &ids) const + DirectoryPathIds notWatchedPaths(const DirectoryPathIds &ids) const { - SourceContextIds notWatchedDirectoryIds; + DirectoryPathIds notWatchedDirectoryIds; notWatchedDirectoryIds.reserve(ids.size()); - std::set_difference(ids.begin(), - ids.end(), - m_watchedEntries.cbegin(), - m_watchedEntries.cend(), - std::back_inserter(notWatchedDirectoryIds)); + std::ranges::set_difference(ids, m_watchedEntries, std::back_inserter(notWatchedDirectoryIds)); return notWatchedDirectoryIds; } @@ -221,12 +203,10 @@ public: WatcherEntries notAnymoreWatchedEntries; notAnymoreWatchedEntries.reserve(m_watchedEntries.size()); - std::set_difference(m_watchedEntries.cbegin(), - m_watchedEntries.cend(), - newEntries.begin(), - newEntries.end(), - std::back_inserter(notAnymoreWatchedEntries), - compare); + std::ranges::set_difference(m_watchedEntries, + newEntries, + std::back_inserter(notAnymoreWatchedEntries), + compare); return notAnymoreWatchedEntries; } @@ -234,11 +214,9 @@ public: template WatcherEntries notAnymoreWatchedEntriesWithIds(const WatcherEntries &newEntries, Filter filter) const { - auto oldEntries = notAnymoreWatchedEntries(newEntries, std::less()); + auto oldEntries = notAnymoreWatchedEntries(newEntries, std::ranges::less{}); - auto newEnd = std::remove_if(oldEntries.begin(), oldEntries.end(), filter); - - oldEntries.erase(newEnd, oldEntries.end()); + std::erase_if(oldEntries, filter); return oldEntries; } @@ -248,53 +226,40 @@ public: WatcherEntries newWatchedEntries; newWatchedEntries.reserve(m_watchedEntries.size() + newEntries.size()); - std::merge(m_watchedEntries.cbegin(), - m_watchedEntries.cend(), - newEntries.begin(), - newEntries.end(), - std::back_inserter(newWatchedEntries)); + std::ranges::merge(m_watchedEntries, newEntries, std::back_inserter(newWatchedEntries)); m_watchedEntries = std::move(newWatchedEntries); } - static SourceContextIds uniquePaths(const WatcherEntries &pathEntries) + static DirectoryPathIds uniquePaths(const WatcherEntries &pathEntries) { - SourceContextIds uniqueDirectoryIds; + DirectoryPathIds uniqueDirectoryIds; uniqueDirectoryIds.reserve(pathEntries.size()); - auto compare = [](WatcherEntry first, WatcherEntry second) { - return first.sourceContextId == second.sourceContextId; - }; - - std::unique_copy(pathEntries.begin(), - pathEntries.end(), - std::back_inserter(uniqueDirectoryIds), - compare); + std::ranges::unique_copy(pathEntries, + std::back_inserter(uniqueDirectoryIds), + {}, + &WatcherEntry::directoryPathId); return uniqueDirectoryIds; } - SourceContextIds filterNotWatchedPaths(const WatcherEntries &entries) const + DirectoryPathIds filterNotWatchedPaths(const WatcherEntries &entries) const { return notWatchedPaths(uniquePaths(entries)); } - const WatcherEntries &watchedEntries() const - { - return m_watchedEntries; - } + const WatcherEntries &watchedEntries() const { return m_watchedEntries; } WatcherEntries removeIdsFromWatchedEntries(const ProjectPartIds &ids) { - auto keep = [&](WatcherEntry entry) { - return !std::binary_search(ids.begin(), ids.end(), entry.id); - }; + auto keep = [&](WatcherEntry entry) { return !std::ranges::binary_search(ids, entry.id.id); }; - auto found = std::stable_partition(m_watchedEntries.begin(), m_watchedEntries.end(), keep); + auto removed = std::ranges::stable_partition(m_watchedEntries, keep); - WatcherEntries removedEntries(found, m_watchedEntries.end()); + WatcherEntries removedEntries(removed.begin(), removed.end()); - m_watchedEntries.erase(found, m_watchedEntries.end()); + m_watchedEntries.erase(removed.begin(), removed.end()); return removedEntries; } @@ -304,39 +269,38 @@ public: WatcherEntries newWatchedEntries; newWatchedEntries.reserve(m_watchedEntries.size() - oldEntries.size()); - std::set_difference(m_watchedEntries.cbegin(), - m_watchedEntries.cend(), - oldEntries.begin(), - oldEntries.end(), - std::back_inserter(newWatchedEntries)); + std::ranges::set_difference(m_watchedEntries, + oldEntries, + std::back_inserter(newWatchedEntries)); m_watchedEntries = std::move(newWatchedEntries); } void compressChangedDirectoryPath(const QString &path) { - m_directoryPathCompressor.addSourceContextId( - m_pathCache.sourceContextId(Utils::PathString{path})); + m_directoryPathCompressor.addDirectoryPathId( + m_pathCache.directoryPathId(Utils::PathString{path})); } - WatcherEntries watchedEntriesForPaths(const QmlDesigner::SourceContextIds &sourceContextIds) + WatcherEntries watchedEntriesForPaths(const QmlDesigner::DirectoryPathIds &directoryPathIds) { WatcherEntries foundEntries; foundEntries.reserve(m_watchedEntries.size()); - set_greedy_intersection_call(m_watchedEntries.begin(), - m_watchedEntries.end(), - sourceContextIds.begin(), - sourceContextIds.end(), - [&](WatcherEntry &entry) { - m_fileStatusCache.update(entry.sourceId); - auto currentLastModified = m_fileStatusCache.lastModifiedTime( - entry.sourceId); - if (entry.lastModified < currentLastModified) { - foundEntries.push_back(entry); - entry.lastModified = currentLastModified; - } - }); + Utils::set_greedy_intersection( + m_watchedEntries, + directoryPathIds, + [&](WatcherEntry &entry) { + m_fileStatusCache.update(entry.sourceId); + auto fileStatus = m_fileStatusCache.find(entry.sourceId); + if (entry.lastModified < fileStatus.lastModified || entry.size != fileStatus.size) { + foundEntries.push_back(entry); + entry.lastModified = fileStatus.lastModified; + entry.size = fileStatus.size; + } + }, + {}, + &WatcherEntry::directoryPathId); return foundEntries; } @@ -345,35 +309,40 @@ public: { auto sourceIds = Utils::transform(entries, &WatcherEntry::sourceId); - std::sort(sourceIds.begin(), sourceIds.end()); - - sourceIds.erase(std::unique(sourceIds.begin(), sourceIds.end()), sourceIds.end()); + std::ranges::sort(sourceIds); + auto removed = std::ranges::unique(sourceIds); + sourceIds.erase(removed.begin(), removed.end()); return sourceIds; } std::vector idPathsForWatcherEntries(WatcherEntries &&foundEntries) { - std::sort(foundEntries.begin(), foundEntries.end(), [](WatcherEntry first, WatcherEntry second) { - return std::tie(first.id, first.sourceId) < std::tie(second.id, second.sourceId); + std::ranges::sort(foundEntries, {}, [](const WatcherEntry &entry) { + return std::tie(entry.id, entry.sourceId); }); std::vector idPaths; idPaths.reserve(foundEntries.size()); - for (WatcherEntry entry : foundEntries) { - if (idPaths.empty() || idPaths.back().id != entry.id) - idPaths.emplace_back(entry.id, SourceIds{}); - idPaths.back().sourceIds.push_back(entry.sourceId); + if (foundEntries.size()) { + idPaths.emplace_back(foundEntries.front().id, SourceIds{}); + + for (WatcherEntry entry : foundEntries) { + if (idPaths.back().id != entry.id) + idPaths.emplace_back(entry.id, SourceIds{}); + + idPaths.back().sourceIds.push_back(entry.sourceId); + } } return idPaths; } - void addChangedPathForFilePath(const SourceContextIds &sourceContextIds) + void addChangedPathForFilePath(const DirectoryPathIds &directoryPathIds) { if (m_notifier) { - WatcherEntries foundEntries = watchedEntriesForPaths(sourceContextIds); + WatcherEntries foundEntries = watchedEntriesForPaths(directoryPathIds); SourceIds watchedSourceIds = watchedPaths(foundEntries); diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcherinterface.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcherinterface.h index 8e67b80b9a7..28b96bb6a40 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcherinterface.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatcherinterface.h @@ -20,7 +20,7 @@ public: virtual void updateIdPaths(const std::vector &idPaths) = 0; virtual void updateContextIdPaths(const std::vector &idPaths, - const SourceContextIds &sourceContextIds) + const DirectoryPathIds &directoryPathIds) = 0; virtual void removeIds(const ProjectPartIds &ids) = 0; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatchertypes.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatchertypes.h index eea6c4eef4e..addfe704d8c 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatchertypes.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragepathwatchertypes.h @@ -40,11 +40,15 @@ public: ProjectPartId id; SourceType sourceType; - auto operator<=>(const ProjectChunkId &) const = default; + auto operator==(const ProjectChunkId &other) const + { + return std::tie(id, sourceType) == std::tie(other.id, other.sourceType); + } - friend bool operator<(ProjectChunkId first, ProjectPartId second) { return first.id < second; } - - friend bool operator<(ProjectPartId first, ProjectChunkId second) { return first < second.id; } + auto operator<=>(const ProjectChunkId &other) const + { + return std::tie(id, sourceType) <=> std::tie(other.id, other.sourceType); + } template friend void convertToString(String &string, const ProjectChunkId &id) @@ -96,35 +100,26 @@ class WatcherEntry { public: ProjectChunkId id; - SourceContextId sourceContextId; + DirectoryPathId directoryPathId; SourceId sourceId; long long lastModified = -1; + long long size = -1; friend bool operator==(WatcherEntry first, WatcherEntry second) { - return first.id == second.id && first.sourceContextId == second.sourceContextId + return first.id == second.id && first.directoryPathId == second.directoryPathId && first.sourceId == second.sourceId; } - friend auto operator<=>(const WatcherEntry &first, const WatcherEntry &second) + friend std::weak_ordering operator<=>(const WatcherEntry &first, const WatcherEntry &second) { - return std::tie(first.sourceContextId, first.sourceId, first.id) - <=> std::tie(second.sourceContextId, second.sourceId, second.id); - } - - friend auto operator<=>(SourceContextId sourceContextId, WatcherEntry entry) - { - return sourceContextId <=> entry.sourceContextId; - } - - friend auto operator<=>(WatcherEntry entry, SourceContextId sourceContextId) - { - return entry.sourceContextId <=> sourceContextId; + return std::tie(first.directoryPathId, first.sourceId, first.id) + <=> std::tie(second.directoryPathId, second.sourceId, second.id); } operator SourceId() const { return sourceId; } - operator SourceContextId() const { return sourceContextId; } + operator DirectoryPathId() const { return directoryPathId; } }; using WatcherEntries = std::vector; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetriggerupdateinterface.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetriggerupdateinterface.h new file mode 100644 index 00000000000..f8e80714e24 --- /dev/null +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetriggerupdateinterface.h @@ -0,0 +1,23 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "projectstorageids.h" + +namespace QmlDesigner { + +class ProjectStorageTriggerUpdateInterface +{ +public: + ProjectStorageTriggerUpdateInterface() = default; + ProjectStorageTriggerUpdateInterface(const ProjectStorageTriggerUpdateInterface &) = delete; + ProjectStorageTriggerUpdateInterface &operator=(const ProjectStorageTriggerUpdateInterface &) = delete; + + virtual void checkForChangeInDirectory(DirectoryPathIds directoryPathIds) = 0; + +protected: + ~ProjectStorageTriggerUpdateInterface() = default; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetypes.h index 0331418568a..cc7c2a33577 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetypes.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstoragetypes.h @@ -1154,7 +1154,7 @@ public: PropertyEditorQmlPath(ModuleId moduleId, TypeNameString typeName, SourceId pathId, - SourceContextId directoryId) + DirectoryPathId directoryId) : typeName{typeName} , pathId{pathId} , directoryId{directoryId} @@ -1179,7 +1179,7 @@ public: TypeNameString typeName; TypeId typeId; SourceId pathId; - SourceContextId directoryId; + DirectoryPathId directoryId; ModuleId moduleId; }; @@ -1188,7 +1188,7 @@ using PropertyEditorQmlPaths = std::vector; class DirectoryInfo { public: - DirectoryInfo(SourceContextId directoryId, SourceId sourceId, ModuleId moduleId, FileType fileType) + DirectoryInfo(DirectoryPathId directoryId, SourceId sourceId, ModuleId moduleId, FileType fileType) : directoryId{directoryId} , sourceId{sourceId} , moduleId{moduleId} @@ -1216,7 +1216,7 @@ public: } public: - SourceContextId directoryId; + DirectoryPathId directoryId; SourceId sourceId; ModuleId moduleId; FileType fileType; @@ -1227,13 +1227,13 @@ using DirectoryInfos = std::vector; class TypeAnnotation { public: - TypeAnnotation(SourceId sourceId, SourceContextId directoryId) + TypeAnnotation(SourceId sourceId, DirectoryPathId directoryId) : sourceId{sourceId} , directoryId{directoryId} {} TypeAnnotation(SourceId sourceId, - SourceContextId directoryId, + DirectoryPathId directoryId, Utils::SmallStringView typeName, ModuleId moduleId, Utils::SmallStringView iconPath, @@ -1274,7 +1274,7 @@ public: SourceId sourceId; ModuleId moduleId; TypeTraits traits; - SourceContextId directoryId; + DirectoryPathId directoryId; }; using TypeAnnotations = std::vector; @@ -1314,7 +1314,7 @@ public: , fileStatuses(std::move(fileStatuses)) {} - SynchronizationPackage(SourceContextIds updatedDirectoryInfoDirectoryIds, + SynchronizationPackage(DirectoryPathIds updatedDirectoryInfoDirectoryIds, DirectoryInfos directoryInfos) : directoryInfos(std::move(directoryInfos)) , updatedDirectoryInfoDirectoryIds(std::move(updatedDirectoryInfoDirectoryIds)) @@ -1327,13 +1327,13 @@ public: SourceIds updatedFileStatusSourceIds; FileStatuses fileStatuses; DirectoryInfos directoryInfos; - SourceContextIds updatedDirectoryInfoDirectoryIds; + DirectoryPathIds updatedDirectoryInfoDirectoryIds; Imports moduleDependencies; SourceIds updatedModuleDependencySourceIds; ModuleExportedImports moduleExportedImports; ModuleIds updatedModuleIds; PropertyEditorQmlPaths propertyEditorQmlPaths; - SourceContextIds updatedPropertyEditorQmlPathDirectoryIds; + DirectoryPathIds updatedPropertyEditorQmlPathDirectoryIds; TypeAnnotations typeAnnotations; SourceIds updatedTypeAnnotationSourceIds; }; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.cpp index e9a26edd133..e5e0a8f2335 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.cpp @@ -417,8 +417,8 @@ void ProjectStorageUpdater::updateDirectoryChanged(Utils::SmallStringView direct FileState annotationDirectoryState, SourcePath qmldirSourcePath, SourceId qmldirSourceId, - SourceContextId directoryId, - SourceContextId annotationDirectoryId, + DirectoryPathId directoryId, + DirectoryPathId annotationDirectoryId, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIds &WatchedSourceIds, @@ -484,7 +484,7 @@ void ProjectStorageUpdater::updateDirectoryChanged(Utils::SmallStringView direct qmldirState, qmldirSourceId, isInsideProject); - tracer.tick("append updated project source id", keyValue("module id", moduleId)); + tracer.tick("append updated directory source id", keyValue("module id", moduleId)); package.updatedDirectoryInfoDirectoryIds.push_back(directoryId); if (isInsideProject == IsInsideProject::Yes) { @@ -513,9 +513,9 @@ void ProjectStorageUpdater::updateDirectories(const QStringList &directories, } void ProjectStorageUpdater::updateSubdirectories(const Utils::PathString &directoryPath, - SourceContextId directoryId, + DirectoryPathId directoryId, FileState directoryState, - const SourceContextIds &subdirectoriesToIgnore, + const DirectoryPathIds &subdirectoriesToIgnore, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIds &WatchedSourceIds, @@ -523,35 +523,35 @@ void ProjectStorageUpdater::updateSubdirectories(const Utils::PathString &direct { struct Directory { - Directory(Utils::SmallStringView path, SourceContextId sourceContextId) + Directory(Utils::SmallStringView path, DirectoryPathId directoryPathId) : path{path} - , sourceContextId{sourceContextId} + , directoryPathId{directoryPathId} {} Utils::PathString path; - SourceContextId sourceContextId; + DirectoryPathId directoryPathId; }; using Directories = QVarLengthArray; auto subdirectoryIds = m_projectStorage.fetchSubdirectoryIds(directoryId); auto subdirectories = Utils::transform( - subdirectoryIds, [&](SourceContextId sourceContextId) -> Directory { - auto subdirectoryPath = m_pathCache.sourceContextPath(sourceContextId); - return {subdirectoryPath, sourceContextId}; + subdirectoryIds, [&](DirectoryPathId directoryPathId) -> Directory { + auto subdirectoryPath = m_pathCache.directoryPath(directoryPathId); + return {subdirectoryPath, directoryPathId}; }); auto exisitingSubdirectoryPaths = m_fileSystem.subdirectories(directoryPath.toQString()); Directories existingSubdirecories; - auto skipDirectory = [&](std::string_view subdirectoryPath, SourceContextId sourceContextId) { + auto skipDirectory = [&](std::string_view subdirectoryPath, DirectoryPathId directoryPathId) { if (subdirectoryPath.ends_with("designer")) return true; if (isInsideProject == IsInsideProject::Yes) { - static SourceNameId ignoreInQdsSourceNameId = m_pathCache.sourceNameId("ignore-in-qds"); + static FileNameId ignoreInQdsFileNameId = m_pathCache.fileNameId("ignore-in-qds"); - SourceId ignoreInQdsSourceId = SourceId::create(ignoreInQdsSourceNameId, sourceContextId); + SourceId ignoreInQdsSourceId = SourceId::create(directoryPathId, ignoreInQdsFileNameId); auto ignoreInQdsState = fileState(ignoreInQdsSourceId, package, notUpdatedSourceIds); @@ -567,17 +567,17 @@ void ProjectStorageUpdater::updateSubdirectories(const Utils::PathString &direct }; for (Utils::PathString subdirectoryPath : exisitingSubdirectoryPaths) { - SourceContextId sourceContextId = m_pathCache.sourceContextId(subdirectoryPath); + DirectoryPathId directoryPathId = m_pathCache.directoryPathId(subdirectoryPath); - if (skipDirectory(subdirectoryPath, sourceContextId)) + if (skipDirectory(subdirectoryPath, directoryPathId)) continue; - subdirectories.emplace_back(subdirectoryPath, sourceContextId); - existingSubdirecories.emplace_back(subdirectoryPath, sourceContextId); + subdirectories.emplace_back(subdirectoryPath, directoryPathId); + existingSubdirecories.emplace_back(subdirectoryPath, directoryPathId); } - std::ranges::sort(subdirectories, {}, &Directory::sourceContextId); - auto removed = std::ranges::unique(subdirectories, {}, &Directory::sourceContextId); + std::ranges::sort(subdirectories, {}, &Directory::directoryPathId); + auto removed = std::ranges::unique(subdirectories, {}, &Directory::directoryPathId); subdirectories.erase(removed.begin(), removed.end()); auto updateDirectory = [&](const Directory &subdirectory) { @@ -593,12 +593,12 @@ void ProjectStorageUpdater::updateSubdirectories(const Utils::PathString &direct subdirectoriesToIgnore, updateDirectory, {}, - &Directory::sourceContextId); + &Directory::directoryPathId); - if (isChanged(directoryState)) { + if (isChangedOrAdded(directoryState)) { for (const auto &[subdirectoryPath, subdirectoryId] : existingSubdirecories) { package.directoryInfos.emplace_back(directoryId, - SourceId::create(SourceNameId{}, subdirectoryId), + SourceId::create(subdirectoryId, FileNameId{}), ModuleId{}, Storage::Synchronization::FileType::Directory); } @@ -607,8 +607,8 @@ void ProjectStorageUpdater::updateSubdirectories(const Utils::PathString &direct void ProjectStorageUpdater::annotationDirectoryChanged( Utils::SmallStringView directoryPath, - SourceContextId directoryId, - SourceContextId annotationDirectoryId, + DirectoryPathId directoryId, + DirectoryPathId annotationDirectoryId, ModuleId moduleId, Storage::Synchronization::SynchronizationPackage &package) { @@ -624,7 +624,7 @@ void ProjectStorageUpdater::annotationDirectoryChanged( void ProjectStorageUpdater::updatePropertyEditorFiles( Utils::SmallStringView directoryPath, - SourceContextId directoryId, + DirectoryPathId directoryId, ModuleId moduleId, Storage::Synchronization::SynchronizationPackage &package) { @@ -643,7 +643,7 @@ void ProjectStorageUpdater::updatePropertyEditorFiles( void ProjectStorageUpdater::updatePropertyEditorFile( const QString &fileName, - SourceContextId directoryId, + DirectoryPathId directoryId, ModuleId moduleId, Storage::Synchronization::SynchronizationPackage &package) { @@ -659,7 +659,7 @@ void ProjectStorageUpdater::updatePropertyEditorFile( } void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPath, - const SourceContextIds &subdirectoriesToIgnore, + const DirectoryPathIds &subdirectoriesToIgnore, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIds &WatchedSourceIds, @@ -669,18 +669,18 @@ void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPa SourcePath qmldirPath{directoryPath + "/qmldir"}; SourceId qmldirSourceId = m_pathCache.sourceId(qmldirPath); - SourceContextId directoryId = qmldirSourceId.contextId(); + DirectoryPathId directoryId = qmldirSourceId.directoryPathId(); auto directoryState = fileState(directoryId, package, notUpdatedSourceIds); if (isExisting(directoryState)) - WatchedSourceIds.directoryIds.push_back(SourceId::create(SourceNameId{}, directoryId)); + WatchedSourceIds.directoryIds.push_back(SourceId::create(directoryId, FileNameId{})); auto qmldirState = fileState(qmldirSourceId, package, notUpdatedSourceIds); if (isExisting(qmldirState)) WatchedSourceIds.qmldirSourceIds.push_back(qmldirSourceId); SourcePath annotationDirectoryPath{directoryPath + "/designer"}; - auto annotationDirectoryId = m_pathCache.sourceContextId(annotationDirectoryPath); + auto annotationDirectoryId = m_pathCache.directoryPathId(annotationDirectoryPath); auto annotationDirectoryState = fileState(annotationDirectoryId, package, notUpdatedSourceIds); switch (combineState(directoryState, qmldirState, annotationDirectoryState)) { @@ -765,7 +765,7 @@ void ProjectStorageUpdater::updatePropertyEditorPaths( while (dirIterator.hasNext()) { auto pathInfo = dirIterator.nextFileInfo(); - SourceContextId directoryId = m_pathCache.sourceContextId( + DirectoryPathId directoryId = m_pathCache.directoryPathId( Utils::PathString{pathInfo.filePath()}); auto state = fileState(directoryId, package, notUpdatedSourceIds); @@ -798,9 +798,9 @@ void ProjectStorageUpdater::updateTypeAnnotations(const QStringList &directoryPa { NanotraceHR::Tracer tracer("update type annotations", category()); - std::map> updatedSourceIdsDictonary; + std::map> updatedSourceIdsDictonary; - for (SourceContextId directoryId : m_projectStorage.typeAnnotationDirectoryIds()) + for (DirectoryPathId directoryId : m_projectStorage.typeAnnotationDirectoryIds()) updatedSourceIdsDictonary[directoryId] = {}; for (const auto &directoryPath : directoryPaths) @@ -813,7 +813,7 @@ void ProjectStorageUpdater::updateTypeAnnotations( const QString &rootDirectoryPath, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, - std::map> &updatedSourceIdsDictonary) + std::map> &updatedSourceIdsDictonary) { NanotraceHR::Tracer tracer("update type annotation directory", category(), @@ -834,7 +834,7 @@ void ProjectStorageUpdater::updateTypeAnnotations( auto directoryPath = fileInfo.canonicalPath(); - SourceContextId directoryId = m_pathCache.sourceContextId(Utils::PathString{directoryPath}); + DirectoryPathId directoryId = m_pathCache.directoryPathId(Utils::PathString{directoryPath}); auto state = fileState(sourceId, package, notUpdatedSourceIds); if (isChangedOrAdded(state)) @@ -848,7 +848,7 @@ void ProjectStorageUpdater::updateTypeAnnotations( void ProjectStorageUpdater::updateTypeAnnotationDirectories( Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, - std::map> &updatedSourceIdsDictonary) + std::map> &updatedSourceIdsDictonary) { for (auto &[directoryId, updatedSourceIds] : updatedSourceIdsDictonary) { auto directoryState = fileState(directoryId, package, notUpdatedSourceIds); @@ -886,7 +886,7 @@ QString contentFromFile(const QString &path) void ProjectStorageUpdater::updateTypeAnnotation(const QString &directoryPath, const QString &filePath, SourceId sourceId, - SourceContextId directoryId, + DirectoryPathId directoryId, Storage::Synchronization::SynchronizationPackage &package) { NanotraceHR::Tracer tracer{"update type annotation path", @@ -909,7 +909,7 @@ void ProjectStorageUpdater::updateTypeAnnotation(const QString &directoryPath, void ProjectStorageUpdater::updatePropertyEditorPath( const QString &directoryPath, Storage::Synchronization::SynchronizationPackage &package, - SourceContextId directoryId, + DirectoryPathId directoryId, long long pathOffset) { NanotraceHR::Tracer tracer{"update property editor path", @@ -929,7 +929,7 @@ void ProjectStorageUpdater::updatePropertyEditorPath( void ProjectStorageUpdater::updatePropertyEditorFilePath( const QString &path, Storage::Synchronization::SynchronizationPackage &package, - SourceContextId directoryId, + DirectoryPathId directoryId, long long pathOffset) { NanotraceHR::Tracer tracer{"update property editor file path", @@ -960,15 +960,15 @@ void ProjectStorageUpdater::updatePropertyEditorFilePath( } namespace { -SourceContextIds filterUniqueSourceContextIds(const SourceIds &sourceIds) +DirectoryPathIds filterUniqueDirectoryPathIds(const SourceIds &sourceIds) { - auto sourceContextIds = Utils::transform(sourceIds, &SourceId::contextId); + auto directoryPathIds = Utils::transform(sourceIds, &SourceId::directoryPathId); - std::sort(sourceContextIds.begin(), sourceContextIds.end()); - auto newEnd = std::unique(sourceContextIds.begin(), sourceContextIds.end()); - sourceContextIds.erase(newEnd, sourceContextIds.end()); + std::sort(directoryPathIds.begin(), directoryPathIds.end()); + auto newEnd = std::unique(directoryPathIds.begin(), directoryPathIds.end()); + directoryPathIds.erase(newEnd, directoryPathIds.end()); - return sourceContextIds; + return directoryPathIds; } SourceIds filterUniqueSourceIds(SourceIds sourceIds) @@ -1049,9 +1049,9 @@ void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector &chan auto updateDirectory = [&](const SourceIds &directorySourceIds, WatchedSourceIds &watchedSourceIds) { - auto directoryIds = filterUniqueSourceContextIds(directorySourceIds); + auto directoryIds = filterUniqueDirectoryPathIds(directorySourceIds); for (auto directoryId : directoryIds) { - Utils::PathString directory = m_pathCache.sourceContextPath(directoryId); + Utils::PathString directory = m_pathCache.directoryPath(directoryId); this->updateDirectory(directory, directoryIds, package, @@ -1067,10 +1067,10 @@ void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector &chan auto projectDirectoryIds = updateDirectory(project.directory, watchedProjectSourceIds); auto parseQmlComponent = [&](SourceIds qmlDocumentSourceIds, - const SourceContextIds &directoryIds, + const DirectoryPathIds &directoryIds, IsInsideProject isInsideProject) { for (SourceId sourceId : filterUniqueSourceIds(std::move(qmlDocumentSourceIds))) { - if (!contains(directoryIds, sourceId.contextId())) + if (!contains(directoryIds, sourceId.directoryPathId())) this->parseQmlComponent(sourceId, package, notUpdatedSourceIds, isInsideProject); } }; @@ -1079,10 +1079,10 @@ void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector &chan parseQmlComponent(std::move(project.qmlDocument), projectDirectoryIds, IsInsideProject::Yes); auto parseTypeInfo = [&](SourceIds qmltypesSourceIds, - const SourceContextIds &directoryIds, + const DirectoryPathIds &directoryIds, IsInsideProject isInsideProject) { for (SourceId sourceId : filterUniqueSourceIds(std::move(qmltypesSourceIds))) { - if (!contains(directoryIds, sourceId.contextId())) { + if (!contains(directoryIds, sourceId.directoryPathId())) { QString qmltypesPath{m_pathCache.sourcePath(sourceId)}; auto directoryInfo = m_projectStorage.fetchDirectoryInfo(sourceId); if (directoryInfo) @@ -1116,7 +1116,7 @@ void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector &chan auto directoryIdsSize = projectDirectoryIds.size() + qtDirectoryIds.size(); if (directoryIdsSize > 0) { - SourceContextIds directoryIds; + DirectoryPathIds directoryIds; std::vector newIdPaths; idPaths.reserve(8); appendIdPaths(std::move(watchedQtSourceIds), m_qtPartId, newIdPaths); @@ -1135,7 +1135,7 @@ void ProjectStorageUpdater::pathsChanged(const SourceIds &) {} void ProjectStorageUpdater::parseTypeInfos(const QStringList &typeInfos, const std::vector &qmldirDependencies, const std::vector &qmldirImports, - SourceContextId directoryId, + DirectoryPathId directoryId, const QString &directoryPath, ModuleId moduleId, Storage::Synchronization::SynchronizationPackage &package, @@ -1168,13 +1168,21 @@ void ProjectStorageUpdater::parseTypeInfos(const QStringList &typeInfos, tracer.tick("append module dependenct source source id", keyValue("source id", sourceId)); package.updatedModuleDependencySourceIds.push_back(sourceId); - const auto &directoryInfo = package.directoryInfos.emplace_back( - directoryId, sourceId, moduleId, Storage::Synchronization::FileType::QmlTypes); - tracer.tick("append project data", keyValue("source id", sourceId)); + const Storage::Synchronization::DirectoryInfo directoryInfo{ + directoryId, sourceId, moduleId, Storage::Synchronization::FileType::QmlTypes}; const QString qmltypesPath = directoryPath + "/" + typeInfo; - parseTypeInfo(directoryInfo, qmltypesPath, package, notUpdatedSourceIds, isInsideProject); + auto state = parseTypeInfo(directoryInfo, + qmltypesPath, + package, + notUpdatedSourceIds, + isInsideProject); + + if (isExisting(state)) { + package.directoryInfos.push_back(directoryInfo); + tracer.tick("append directory info", keyValue("source id", directoryInfo.sourceId)); + } } } @@ -1225,6 +1233,7 @@ auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::Direct const auto content = m_fileSystem.contentAsQString(qmltypesPath); m_qmlTypesParser.parse(content, package.imports, package.types, directoryInfo, isInsideProject); + break; } case FileState::Unchanged: { @@ -1235,7 +1244,10 @@ auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::Direct case FileState::Removed: case FileState::NotExists: case FileState::NotExistsUnchanged: - throw CannotParseQmlTypesFile{}; + tracer.tick("append updated source ids", keyValue("source id", directoryInfo.sourceId)); + package.updatedSourceIds.push_back(directoryInfo.sourceId); + + m_errorNotifier.qmltypesFileMissing(qmltypesPath); } tracer.end(keyValue("state", state)); @@ -1246,7 +1258,7 @@ auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::Direct void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFilePath, Utils::SmallStringView directoryPath, Storage::Synchronization::ExportedTypes exportedTypes, - SourceContextId directoryId, + DirectoryPathId directoryId, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIds &watchedSourceIds, @@ -1414,7 +1426,7 @@ Storage::Synchronization::ExportedTypes createExportedTypes(ProjectStorageUpdate } // namespace void ProjectStorageUpdater::parseQmlComponents(Components components, - SourceContextId directoryId, + DirectoryPathId directoryId, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIds &WatchedSourceIds, @@ -1430,7 +1442,7 @@ void ProjectStorageUpdater::parseQmlComponents(Components components, std::ranges::sort(components, [](auto &&first, auto &&second) { return first.fileName < second.fileName; }); - auto directoryPath = m_pathCache.sourceContextPath(directoryId); + auto directoryPath = m_pathCache.directoryPath(directoryId); auto callback = [&](ComponentRange componentsWithSameFileName) { const auto &firstComponent = *componentsWithSameFileName.begin(); @@ -1499,11 +1511,11 @@ ProjectStorageUpdater::FileState ProjectStorageUpdater::fileState( } ProjectStorageUpdater::FileState ProjectStorageUpdater::fileState( - SourceContextId sourceContextId, + DirectoryPathId directoryPathId, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds) const { - auto sourceId = SourceId::create(SourceNameId{}, sourceContextId); + auto sourceId = SourceId::create(directoryPathId, FileNameId{}); return fileState(sourceId, package, notUpdatedSourceIds); } diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h index 8d22bddd035..7dd38706d38 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h @@ -142,15 +142,15 @@ private: NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIds &WatchedSourceIds); void updateDirectory(const Utils::PathString &directory, - const SourceContextIds &subdirecoriesToIgnore, + const DirectoryPathIds &subdirecoriesToIgnore, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIds &WatchedSourceIds, IsInsideProject isInsideProject); void updateSubdirectories(const Utils::PathString &directory, - SourceContextId directoryId, + DirectoryPathId directoryId, FileState directoryFileState, - const SourceContextIds &subdirecoriesToIgnore, + const DirectoryPathIds &subdirecoriesToIgnore, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIds &WatchedSourceIds, @@ -161,24 +161,24 @@ private: FileState annotationDirectoryState, SourcePath qmldirSourcePath, SourceId qmldirSourceId, - SourceContextId directoryId, - SourceContextId annotationDirectoryId, + DirectoryPathId directoryId, + DirectoryPathId annotationDirectoryId, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIds &WatchedSourceIds, IsInsideProject isInsideProject, ProjectStorageTracing::Category::TracerType &tracer); void annotationDirectoryChanged(Utils::SmallStringView directoryPath, - SourceContextId directoryId, - SourceContextId annotationDirectoryId, + DirectoryPathId directoryId, + DirectoryPathId annotationDirectoryId, ModuleId moduleId, Storage::Synchronization::SynchronizationPackage &package); void updatePropertyEditorFiles(Utils::SmallStringView directyPath, - SourceContextId directoryId, + DirectoryPathId directoryId, ModuleId moduleId, Storage::Synchronization::SynchronizationPackage &package); void updatePropertyEditorFile(const QString &fileName, - SourceContextId directoryId, + DirectoryPathId directoryId, ModuleId moduleId, Storage::Synchronization::SynchronizationPackage &package); void updatePropertyEditorPaths(const QString &propertyEditorResourcesPath, @@ -187,31 +187,31 @@ private: void updateTypeAnnotations(const QString &directoryPath, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, - std::map> &updatedSourceIdsDictonary); + std::map> &updatedSourceIdsDictonary); void updateTypeAnnotationDirectories( Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, - std::map> &updatedSourceIdsDictonary); + std::map> &updatedSourceIdsDictonary); void updateTypeAnnotations(const QStringList &directoryPath, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds); void updateTypeAnnotation(const QString &directoryPath, const QString &filePath, SourceId sourceId, - SourceContextId directoryId, + DirectoryPathId directoryId, Storage::Synchronization::SynchronizationPackage &package); void updatePropertyEditorPath(const QString &path, Storage::Synchronization::SynchronizationPackage &package, - SourceContextId directoryId, + DirectoryPathId directoryId, long long pathOffset); void updatePropertyEditorFilePath(const QString &filePath, Storage::Synchronization::SynchronizationPackage &package, - SourceContextId directoryId, + DirectoryPathId directoryId, long long pathOffset); void parseTypeInfos(const QStringList &typeInfos, const std::vector &qmldirDependencies, const std::vector &qmldirImports, - SourceContextId directoryId, + DirectoryPathId directoryId, const QString &directoryPath, ModuleId moduleId, Storage::Synchronization::SynchronizationPackage &package, @@ -229,7 +229,7 @@ private: NotUpdatedSourceIds ¬UpdatedSourceIds, IsInsideProject isInsideProject); void parseQmlComponents(Components components, - SourceContextId directoryId, + DirectoryPathId directoryId, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIds &WatchedSourceIds, @@ -239,7 +239,7 @@ private: void parseQmlComponent(Utils::SmallStringView fileName, Utils::SmallStringView directory, Storage::Synchronization::ExportedTypes exportedTypes, - SourceContextId directoryId, + DirectoryPathId directoryId, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds, WatchedSourceIds &WatchedSourceIds, @@ -254,7 +254,7 @@ private: FileState fileState(SourceId sourceId, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds) const; - FileState fileState(SourceContextId sourceContextId, + FileState fileState(DirectoryPathId directoryPathId, Storage::Synchronization::SynchronizationPackage &package, NotUpdatedSourceIds ¬UpdatedSourceIds) const; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.cpp index d646b8b90db..5f86875173b 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.cpp @@ -28,7 +28,7 @@ constexpr auto extraFileElementName = "ExtraFile"_L1; } // namespace Synchronization::TypeAnnotations TypeAnnotationReader::parseTypeAnnotation( - const QString &content, const QString &directoryPath, SourceId sourceId, SourceContextId directoryId) + const QString &content, const QString &directoryPath, SourceId sourceId, DirectoryPathId directoryId) { m_sourceId = sourceId; m_directoryId = directoryId; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.h index 1c704618ae8..af40d985988 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.h @@ -50,7 +50,7 @@ public: Synchronization::TypeAnnotations parseTypeAnnotation(const QString &content, const QString &directoryPath, SourceId sourceId, - SourceContextId directoryId); + DirectoryPathId directoryId); QStringList errors(); @@ -125,7 +125,7 @@ private: json m_itemLibraryEntries; Property m_currentProperty; SourceId m_sourceId; - SourceContextId m_directoryId; + DirectoryPathId m_directoryId; }; } // namespace QmlDesigner::Storage diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/modeltotextmerger.cpp b/src/plugins/qmldesigner/libs/designercore/rewriter/modeltotextmerger.cpp index cd70e4e95b6..f045ad5a88d 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/modeltotextmerger.cpp +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/modeltotextmerger.cpp @@ -16,6 +16,8 @@ #include #include +#include +#include namespace { enum { @@ -355,52 +357,53 @@ QmlRefactoring::PropertyType ModelToTextMerger::propertyType(const AbstractPrope return QmlRefactoring::Invalid; } -PropertyNameList ModelToTextMerger::propertyOrder() +Utils::span ModelToTextMerger::propertyOrder() { - static const PropertyNameList properties = {PropertyName("id"), - PropertyName("name"), - PropertyName("target"), - PropertyName("property"), - PropertyName("x"), - PropertyName("y"), - PropertyName("width"), - PropertyName("height"), - PropertyName("opacity"), - PropertyName("visible"), - PropertyName("position"), - PropertyName("color"), - PropertyName("radius"), - PropertyName("text"), - PropertyName("elide"), - PropertyName("value"), - PropertyName("border.color"), - PropertyName("border.width"), - PropertyName("anchors.verticalCenter"), - PropertyName("anchors.left"), - PropertyName("anchors.right"), - PropertyName("anchors.top"), - PropertyName("anchors.bottom"), - PropertyName("anchors.fill"), - PropertyName("anchors.margins"), - PropertyName("anchors.leftMargin"), - PropertyName("anchors.rightMargin"), - PropertyName("anchors.topMargin"), - PropertyName("anchors.bottomMargin"), - PropertyName("font.letterSpacing"), - PropertyName("font.pixelSize"), - PropertyName("horizontalAlignment"), - PropertyName("verticalAlignment"), - PropertyName("source"), - PropertyName("lineHeight"), - PropertyName("lineHeightMode"), - PropertyName("wrapMode"), - PropertyName(), - PropertyName("states"), - PropertyName("to"), - PropertyName("from"), - PropertyName("transitions")}; + static constexpr auto propertyNames = Utils::to_array( + "id", + "name", + "target", + "property", + "x", + "y", + "width", + "height", + "opacity", + "visible", + "position", + "color", + "radius", + "text", + "elide", + "value", + "border.color", + "border.width", + "anchors.verticalCenter", + "anchors.left", + "anchors.right", + "anchors.top", + "anchors.bottom", + "anchors.fill", + "anchors.margins", + "anchors.leftMargin", + "anchors.rightMargin", + "anchors.topMargin", + "anchors.bottomMargin", + "font.letterSpacing", + "font.pixelSize", + "horizontalAlignment", + "verticalAlignment", + "source", + "lineHeight", + "lineHeightMode", + "wrapMode", + "", + "states", + "to", + "from", + "transitions"); - return properties; + return propertyNames; } bool ModelToTextMerger::isInHierarchy(const AbstractProperty &property) { diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/modeltotextmerger.h b/src/plugins/qmldesigner/libs/designercore/rewriter/modeltotextmerger.h index 75d7178039e..d542dad9549 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/modeltotextmerger.h +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/modeltotextmerger.h @@ -52,7 +52,7 @@ protected: { return m_rewriteActions; } static QmlDesigner::QmlRefactoring::PropertyType propertyType(const AbstractProperty &property, const QString &textValue = QString()); - static PropertyNameList propertyOrder(); + static Utils::span propertyOrder(); static bool isInHierarchy(const AbstractProperty &property); diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/qmltextgenerator.cpp b/src/plugins/qmldesigner/libs/designercore/rewriter/qmltextgenerator.cpp index d40d0fe4a94..a5a987b0fc5 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/qmltextgenerator.cpp +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/qmltextgenerator.cpp @@ -72,7 +72,7 @@ static QString unicodeEscape(const QString &stringValue) return stringValue; } -QmlTextGenerator::QmlTextGenerator(const PropertyNameList &propertyOrder, +QmlTextGenerator::QmlTextGenerator(Utils::span propertyOrder, const TextEditor::TabSettings &tabSettings, const int startIndentDepth) : m_propertyOrder(propertyOrder) @@ -220,7 +220,7 @@ QString QmlTextGenerator::propertiesToQml(const ModelNode &node, int indentDepth PropertyNameList nodePropertyNames = node.propertyNames(); bool addToTop = true; - for (const PropertyName &propertyName : std::as_const(m_propertyOrder)) { + for (const auto propertyName : m_propertyOrder) { if (propertyName == "id") { // the model handles the id property special, so: if (!node.id().isEmpty()) { diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/qmltextgenerator.h b/src/plugins/qmldesigner/libs/designercore/rewriter/qmltextgenerator.h index 971d6a2d1d0..5b6376bb214 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/qmltextgenerator.h +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/qmltextgenerator.h @@ -16,7 +16,7 @@ namespace Internal { class QmlTextGenerator { public: - explicit QmlTextGenerator(const PropertyNameList &propertyOrder, + explicit QmlTextGenerator(Utils::span propertyOrder, const TextEditor::TabSettings &tabSettings, const int startIndentDepth = 0); @@ -33,7 +33,7 @@ private: QString propertyToQml(const AbstractProperty &property, int indentDepth) const; private: - PropertyNameList m_propertyOrder; + Utils::span m_propertyOrder; TextEditor::TabSettings m_tabSettings; const int m_startIndentDepth; }; diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/rewriteaction.cpp b/src/plugins/qmldesigner/libs/designercore/rewriter/rewriteaction.cpp index 1035f8273a0..9b7f316d39e 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/rewriteaction.cpp +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/rewriteaction.cpp @@ -60,42 +60,47 @@ QStringView toString(QmlRefactoring::PropertyType type) } // namespace anonymous +std::optional PropertyRewriteAction::nodeLocation() const +{ + if (movedAfterCreation()) + return std::make_optional(m_property.toNodeListProperty().indexOf(m_containedModelNode)); + + return std::nullopt; +} + bool AddPropertyRewriteAction::execute(QmlRefactoring &refactoring, ModelNodePositionStorage &positionStore) { - if (m_sheduledInHierarchy) { - const int parentLocation = positionStore.nodeOffset(m_property.parentModelNode()); + if (scheduledInHierarchy()) { + const int parentLocation = positionStore.nodeOffset(property().parentModelNode()); bool result = false; - if (m_propertyType != QmlRefactoring::ScriptBinding && m_property.isDefaultProperty()) { - const int nodeLocation = movedAfterCreation() - ? m_property.toNodeListProperty().indexOf(m_containedModelNode) - : -1; - result = refactoring.addToObjectMemberList(parentLocation, nodeLocation, m_valueText); + if (propertyType() != QmlRefactoring::ScriptBinding && property().isDefaultProperty()) { + result = refactoring.addToObjectMemberList(parentLocation, nodeLocation(), valueText()); if (!result) { qDebug() << "*** AddPropertyRewriteAction::execute failed in addToObjectMemberList(" - << parentLocation << ',' << nodeLocation << ',' << m_valueText << ") **" + << parentLocation << ',' << nodeLocation() << ',' << valueText() << ") **" << info(); } - } else if (m_property.isNodeListProperty() && m_property.toNodeListProperty().count() > 1) { - result = refactoring.addToArrayMemberList(parentLocation, m_property.name(), m_valueText); + } else if (property().isNodeListProperty() && property().toNodeListProperty().count() > 1) { + result = refactoring.addToArrayMemberList(parentLocation, property().name(), valueText()); if (!result) { qDebug() << "*** AddPropertyRewriteAction::execute failed in addToArrayMemberList(" - << parentLocation << ',' << m_property.name() << ',' << m_valueText + << parentLocation << ',' << property().name() << ',' << valueText() << ") **" << info(); } } else { result = refactoring.addProperty(parentLocation, - m_property.name(), - m_valueText, - m_propertyType, - m_property.dynamicTypeName()); + property().name(), + valueText(), + propertyType(), + property().dynamicTypeName()); if (!result) { qDebug() << "*** AddPropertyRewriteAction::execute failed in addProperty(" - << parentLocation << ',' << m_property.name() << ',' << m_valueText << "," - << toString(m_propertyType) << ") **" << info(); + << parentLocation << ',' << property().name() << ',' << valueText() << "," + << toString(propertyType()) << ") **" << info(); } } @@ -109,12 +114,12 @@ QString AddPropertyRewriteAction::info() const { return QStringView(u"AddPropertyRewriteAction for property \"%1\" (type: %2) of node \"%3\" " u"with value >>%4<< and contained object \"%5\"") - .arg(QString::fromUtf8(m_property.name()), - toString(m_propertyType), - (m_property.parentModelNode().isValid() ? m_property.parentModelNode().id() + .arg(QString::fromUtf8(property().name()), + toString(propertyType()), + (property().parentModelNode().isValid() ? property().parentModelNode().id() : QLatin1String("(invalid)")), - QString(m_valueText).replace(QLatin1Char('\n'), QLatin1String("\\n")), - (m_containedModelNode.isValid() ? m_containedModelNode.id() + QString(valueText()).replace(QLatin1Char('\n'), QLatin1String("\\n")), + (containedModelNode().isValid() ? containedModelNode().id() : QString(QStringLiteral("(none)")))); } @@ -166,46 +171,42 @@ QString ChangeIdRewriteAction::info() const bool ChangePropertyRewriteAction::execute(QmlRefactoring &refactoring, ModelNodePositionStorage &positionStore) { - if (m_sheduledInHierarchy) { - const int parentLocation = positionStore.nodeOffset(m_property.parentModelNode()); + if (scheduledInHierarchy()) { + const int parentLocation = positionStore.nodeOffset(property().parentModelNode()); if (parentLocation < 0) { qWarning() << "*** ChangePropertyRewriteAction::execute ignored. Invalid node location"; return true; } bool result = false; - if (m_propertyType != QmlRefactoring::ScriptBinding && m_property.isDefaultProperty()) { - const int nodeLocation = movedAfterCreation() - ? m_property.toNodeListProperty().indexOf(m_containedModelNode) - : -1; - - result = refactoring.addToObjectMemberList(parentLocation, nodeLocation, m_valueText); + if (propertyType() != QmlRefactoring::ScriptBinding && property().isDefaultProperty()) { + result = refactoring.addToObjectMemberList(parentLocation, nodeLocation(), valueText()); if (!result) { qDebug() << "*** ChangePropertyRewriteAction::execute failed in addToObjectMemberList(" - << parentLocation << ',' << nodeLocation << ',' << m_valueText << ") **" + << parentLocation << ',' << nodeLocation() << ',' << valueText() << ") **" << info(); } - } else if (m_propertyType == QmlRefactoring::ArrayBinding) { - result = refactoring.addToArrayMemberList(parentLocation, m_property.name(), m_valueText); + } else if (propertyType() == QmlRefactoring::ArrayBinding) { + result = refactoring.addToArrayMemberList(parentLocation, property().name(), valueText()); if (!result) { qDebug() << "*** ChangePropertyRewriteAction::execute failed in addToArrayMemberList(" - << parentLocation << ',' << m_property.name() << ',' << m_valueText << ") **" + << parentLocation << ',' << property().name() << ',' << valueText() << ") **" << info(); } } else { result = refactoring.changeProperty(parentLocation, - m_property.name(), - m_valueText, - m_propertyType); + property().name(), + valueText(), + propertyType()); if (!result) { qDebug() << "*** ChangePropertyRewriteAction::execute failed in changeProperty(" - << parentLocation << ',' << m_property.name() << ',' << m_valueText << ',' - << toString(m_propertyType) << ") **" << info(); + << parentLocation << ',' << property().name() << ',' << valueText() << ',' + << toString(propertyType()) << ") **" << info(); } } @@ -219,12 +220,12 @@ QString ChangePropertyRewriteAction::info() const { return QStringView(u"ChangePropertyRewriteAction for property \"%1\" (type: %2) of node \"%3\" " u"with value >>%4<< and contained object \"%5\"") - .arg(QString::fromUtf8(m_property.name()), - toString(m_propertyType), - (m_property.parentModelNode().isValid() ? m_property.parentModelNode().id() + .arg(QString::fromUtf8(property().name()), + toString(propertyType()), + (property().parentModelNode().isValid() ? property().parentModelNode().id() : QLatin1String("(invalid)")), - QString(m_valueText).replace(QLatin1Char('\n'), QLatin1String("\\n")), - (m_containedModelNode.isValid() ? m_containedModelNode.id() + QString(valueText()).replace(QLatin1Char('\n'), QLatin1String("\\n")), + (containedModelNode().isValid() ? containedModelNode().id() : QString(QStringLiteral("(none)")))); } diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/rewriteaction.h b/src/plugins/qmldesigner/libs/designercore/rewriter/rewriteaction.h index a1f77f70d64..00fa8bc04c6 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/rewriteaction.h +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/rewriteaction.h @@ -48,43 +48,53 @@ public: RewriteAction &operator=(const RewriteAction&) = delete; }; -class AddPropertyRewriteAction: public RewriteAction +class PropertyRewriteAction : public RewriteAction { public: - AddPropertyRewriteAction(const AbstractProperty &property, const QString &valueText, QmlDesigner::QmlRefactoring::PropertyType propertyType, const ModelNode &containedModelNode/* = ModelNode()*/): - m_property(property), m_valueText(valueText), m_propertyType(propertyType), m_containedModelNode(containedModelNode), - m_sheduledInHierarchy(property.isValid() && property.parentModelNode().isInHierarchy()) + PropertyRewriteAction(const AbstractProperty &property, + const QString &valueText, + QmlDesigner::QmlRefactoring::PropertyType propertyType, + const ModelNode &containedModelNode /* = ModelNode()*/) + : m_property(property) + , m_valueText(valueText) + , m_propertyType(propertyType) + , m_containedModelNode(containedModelNode) + , m_scheduledInHierarchy(property.isValid() && property.parentModelNode().isInHierarchy()) {} - bool execute(QmlDesigner::QmlRefactoring &refactoring, ModelNodePositionStorage &positionStore) override; - QString info() const override; + AbstractProperty property() const { return m_property; } - AddPropertyRewriteAction *asAddPropertyRewriteAction() override { return this; } + QString valueText() const { return m_valueText; } - AbstractProperty property() const - { return m_property; } + QmlDesigner::QmlRefactoring::PropertyType propertyType() const { return m_propertyType; } - QString valueText() const - { return m_valueText; } + ModelNode containedModelNode() const { return m_containedModelNode; } - QmlDesigner::QmlRefactoring::PropertyType propertyType() const - { return m_propertyType; } - - ModelNode containedModelNode() const - { return m_containedModelNode; } - - bool movedAfterCreation() const { return m_movedAfterCreation; } void setMovedAfterCreation(bool moved) { m_movedAfterCreation = moved; } +protected: + bool scheduledInHierarchy() const { return m_scheduledInHierarchy; } + bool movedAfterCreation() const { return m_movedAfterCreation; } + std::optional nodeLocation() const; + private: AbstractProperty m_property; QString m_valueText; QmlDesigner::QmlRefactoring::PropertyType m_propertyType; ModelNode m_containedModelNode; - bool m_sheduledInHierarchy; + bool m_scheduledInHierarchy; bool m_movedAfterCreation = false; }; +class AddPropertyRewriteAction : public PropertyRewriteAction +{ +public: + using PropertyRewriteAction::PropertyRewriteAction; + bool execute(QmlDesigner::QmlRefactoring &refactoring, ModelNodePositionStorage &positionStore) override; + QString info() const override; + AddPropertyRewriteAction *asAddPropertyRewriteAction() override { return this; } +}; + class ChangeIdRewriteAction: public RewriteAction { public: @@ -106,41 +116,13 @@ private: QString m_newId; }; -class ChangePropertyRewriteAction: public RewriteAction +class ChangePropertyRewriteAction : public PropertyRewriteAction { public: - ChangePropertyRewriteAction(const AbstractProperty &property, const QString &valueText, QmlDesigner::QmlRefactoring::PropertyType propertyType, const ModelNode &containedModelNode/* = ModelNode()*/): - m_property(property), m_valueText(valueText), m_propertyType(propertyType), m_containedModelNode(containedModelNode), - m_sheduledInHierarchy(property.isValid() && property.parentModelNode().isInHierarchy()) - {} - + using PropertyRewriteAction::PropertyRewriteAction; bool execute(QmlDesigner::QmlRefactoring &refactoring, ModelNodePositionStorage &positionStore) override; QString info() const override; - ChangePropertyRewriteAction *asChangePropertyRewriteAction() override { return this; } - - AbstractProperty property() const - { return m_property; } - - QString valueText() const - { return m_valueText; } - - QmlDesigner::QmlRefactoring::PropertyType propertyType() const - { return m_propertyType; } - - ModelNode containedModelNode() const - { return m_containedModelNode; } - - bool movedAfterCreation() const { return m_movedAfterCreation; } - void setMovedAfterCreation(bool moved) { m_movedAfterCreation = moved; } - -private: - AbstractProperty m_property; - QString m_valueText; - QmlDesigner::QmlRefactoring::PropertyType m_propertyType; - ModelNode m_containedModelNode; - bool m_sheduledInHierarchy; - bool m_movedAfterCreation; }; class ChangeTypeRewriteAction:public RewriteAction diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/rewriteactioncompressor.h b/src/plugins/qmldesigner/libs/designercore/rewriter/rewriteactioncompressor.h index e7e13becbbf..26cf0394efa 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/rewriteactioncompressor.h +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/rewriteactioncompressor.h @@ -11,9 +11,10 @@ namespace Internal { class RewriteActionCompressor { public: - RewriteActionCompressor(const PropertyNameList &propertyOrder, ModelNodePositionStorage *positionStore) : - m_propertyOrder(propertyOrder), - m_positionStore(positionStore) + RewriteActionCompressor(Utils::span propertyOrder, + ModelNodePositionStorage *positionStore) + : m_propertyOrder(propertyOrder) + , m_positionStore(positionStore) {} void operator()(QList &actions, const TextEditor::TabSettings &tabSettings) const; @@ -31,7 +32,7 @@ private: void compressSlidesIntoNewNode(QList &actions) const; private: - PropertyNameList m_propertyOrder; + Utils::span m_propertyOrder; ModelNodePositionStorage *m_positionStore; }; diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/rewriterview.cpp b/src/plugins/qmldesigner/libs/designercore/rewriter/rewriterview.cpp index 02f5c2f05d3..d94846d234a 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/rewriterview.cpp +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/rewriterview.cpp @@ -678,6 +678,11 @@ void RewriterView::setIsDocumentRewriterView(bool b) } #endif +void RewriterView::setRemoveImports(bool removeImports) +{ + m_textToModelMerger->setRemoveImports(removeImports); +} + Internal::ModelNodePositionStorage *RewriterView::positionStorage() const { return m_positionStorage.get(); diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp b/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp index 57785a1a570..f9f56923378 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp @@ -702,8 +702,10 @@ void TextToModelMerger::setupImports(const Document::Ptr &doc, } } - for (const Import &import : std::as_const(existingImports)) - differenceHandler.importAbsentInQMl(import); + if (m_removeImports) { + for (const Import &import : std::as_const(existingImports)) + differenceHandler.importAbsentInQMl(import); + } } namespace { @@ -2439,6 +2441,11 @@ void TextToModelMerger::clearPossibleImportKeys() m_previousPossibleModulesSize = -1; } +void TextToModelMerger::setRemoveImports(bool removeImports) +{ + m_removeImports = removeImports; +} + QString TextToModelMerger::textAt(const Document::Ptr &doc, const SourceLocation &location) { diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.h b/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.h index 897555c301d..9220f226703 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.h +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.h @@ -124,6 +124,8 @@ public: void clearPossibleImportKeys(); + void setRemoveImports(bool removeImports); + private: void setupCustomParserNode(const ModelNode &node); void setupComponent(const ModelNode &node); @@ -160,6 +162,7 @@ private: Imports m_possibleModules; int m_previousPossibleModulesSize = -1; bool m_hasVersionlessImport = false; + bool m_removeImports = true; }; class DifferenceHandler diff --git a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathcache.h b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathcache.h index cc7d0a89f98..ed0cc900f23 100644 --- a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathcache.h +++ b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathcache.h @@ -31,8 +31,8 @@ class SourcePathCache final : public SourcePathCacheInterface public: SourcePathCache(Storage &storage) - : m_sourceContextStorageAdapter{storage} - , m_sourceNameStorageAdapter{storage} + : m_directoryPathStorageAdapter{storage} + , m_fileNameStorageAdapter{storage} { populateIfEmpty(); @@ -43,44 +43,44 @@ public: void populateIfEmpty() override { - if (m_sourceNameCache.isEmpty()) { - m_sourceContextPathCache.populate(); - m_sourceNameCache.populate(); + if (m_fileNameCache.isEmpty()) { + m_directoryPathCache.populate(); + m_fileNameCache.populate(); } } SourceId sourceId(SourcePathView sourcePath) const override { - Utils::SmallStringView sourceContextPath = sourcePath.directory(); + Utils::SmallStringView directoryPath = sourcePath.directory(); - auto sourceContextId = m_sourceContextPathCache.id(sourceContextPath); + auto directoryPathId = m_directoryPathCache.id(directoryPath); - Utils::SmallStringView sourceName = sourcePath.name(); + Utils::SmallStringView fileName = sourcePath.name(); - auto sourceNameId = m_sourceNameCache.id(sourceName); + auto fileNameId = m_fileNameCache.id(fileName); - return SourceId::create(sourceNameId, sourceContextId); + return SourceId::create(directoryPathId, fileNameId); } - SourceNameId sourceNameId(Utils::SmallStringView sourceName) const override + FileNameId fileNameId(Utils::SmallStringView fileName) const override { - return m_sourceNameCache.id(sourceName); + return m_fileNameCache.id(fileName); } - SourceId sourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName) const override + SourceId sourceId(DirectoryPathId directoryPathId, Utils::SmallStringView fileName) const override { - SourceNameId sourceNameId = m_sourceNameCache.id(sourceName); + FileNameId fileNameId = m_fileNameCache.id(fileName); - return SourceId::create(sourceNameId, sourceContextId); + return SourceId::create(directoryPathId, fileNameId); } - SourceContextId sourceContextId(Utils::SmallStringView sourceContextPath) const override + DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const override { - Utils::SmallStringView path = sourceContextPath.back() == '/' - ? sourceContextPath.substr(0, sourceContextPath.size() - 1) - : sourceContextPath; + Utils::SmallStringView path = directoryPath.back() == '/' + ? directoryPath.substr(0, directoryPath.size() - 1) + : directoryPath; - return m_sourceContextPathCache.id(path); + return m_directoryPathCache.id(path); } SourcePath sourcePath(SourceId sourceId) const override @@ -88,88 +88,99 @@ public: if (!sourceId) [[unlikely]] throw NoSourcePathForInvalidSourceId(); - auto sourceName = m_sourceNameCache.value(sourceId.mainId()); + auto fileName = m_fileNameCache.value(sourceId.fileNameId()); - Utils::PathString sourceContextPath = m_sourceContextPathCache.value(sourceId.contextId()); + Utils::PathString directoryPath = m_directoryPathCache.value(sourceId.directoryPathId()); - return SourcePath{sourceContextPath, sourceName}; + return SourcePath{directoryPath, fileName}; } - Utils::PathString sourceContextPath(SourceContextId sourceContextId) const override + Utils::PathString directoryPath(DirectoryPathId directoryPathId) const override { - if (!sourceContextId) [[unlikely]] - throw NoSourceContextPathForInvalidSourceContextId(); + if (!directoryPathId) [[unlikely]] + throw NoDirectoryPathForInvalidDirectoryPathId(); - return m_sourceContextPathCache.value(sourceContextId); + return m_directoryPathCache.value(directoryPathId); } - Utils::SmallString sourceName(SourceNameId sourceNameId) const override + Utils::SmallString fileName(FileNameId fileNameId) const override { - if (!sourceNameId) [[unlikely]] - throw NoSourceNameForInvalidSourceNameId(); + if (!fileNameId) [[unlikely]] + throw NoFileNameForInvalidFileNameId(); - return m_sourceNameCache.value(sourceNameId); + return m_fileNameCache.value(fileNameId); } private: - class SourceContextStorageAdapter + class DirectoryPathStorageAdapter { public: - auto fetchId(Utils::SmallStringView sourceContextPath) + auto fetchId(Utils::SmallStringView directoryPath) { - return storage.fetchSourceContextId(sourceContextPath); + return storage.fetchDirectoryPathId(directoryPath); } - auto fetchValue(SourceContextId id) { return storage.fetchSourceContextPath(id); } + auto fetchValue(DirectoryPathId id) { return storage.fetchDirectoryPath(id); } - auto fetchAll() { return storage.fetchAllSourceContexts(); } + auto fetchAll() { return storage.fetchAllDirectoryPaths(); } Storage &storage; }; - class SourceNameStorageAdapter + class FileNameStorageAdapter { public: - auto fetchId(Utils::SmallStringView sourceNameView) + auto fetchId(Utils::SmallStringView fileNameView) { - return storage.fetchSourceNameId(sourceNameView); + return storage.fetchFileNameId(fileNameView); } - auto fetchValue(SourceNameId id) { return storage.fetchSourceName(id); } + auto fetchValue(FileNameId id) { return storage.fetchFileName(id); } - auto fetchAll() { return storage.fetchAllSourceNames(); } + auto fetchAll() { return storage.fetchAllFileNames(); } Storage &storage; }; - static bool sourceLess(Utils::SmallStringView first, Utils::SmallStringView second) noexcept + struct FileNameLess { - return std::lexicographical_compare(first.rbegin(), - first.rend(), - second.rbegin(), - second.rend()); - } + bool operator()(Utils::SmallStringView first, Utils::SmallStringView second) const noexcept + { + return first < second; + } + }; - using SourceContextPathCache = StorageCache; - using SourceNameCache = StorageCache; + using FileNameCache = StorageCache; + FileNameLess, + Cache::FileName>; private: - SourceContextStorageAdapter m_sourceContextStorageAdapter; - SourceNameStorageAdapter m_sourceNameStorageAdapter; - mutable SourceContextPathCache m_sourceContextPathCache{m_sourceContextStorageAdapter}; - mutable SourceNameCache m_sourceNameCache{m_sourceNameStorageAdapter}; + DirectoryPathStorageAdapter m_directoryPathStorageAdapter; + FileNameStorageAdapter m_fileNameStorageAdapter; + mutable DirectoryPathCache m_directoryPathCache{m_directoryPathStorageAdapter}; + mutable FileNameCache m_fileNameCache{m_fileNameStorageAdapter}; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathcacheinterface.h b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathcacheinterface.h index 6f2378643f7..8cb9d27b986 100644 --- a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathcacheinterface.h +++ b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathcacheinterface.h @@ -24,19 +24,19 @@ public: virtual SourceId sourceId(SourcePathView sourcePath) const = 0; - virtual SourceId sourceId(SourceContextId sourceContextId, - Utils::SmallStringView sourceName) const + virtual SourceId sourceId(DirectoryPathId directoryPathId, + Utils::SmallStringView fileName) const = 0; - virtual SourceNameId sourceNameId(Utils::SmallStringView sourceName) const = 0; + virtual FileNameId fileNameId(Utils::SmallStringView fileName) const = 0; - virtual SourceContextId sourceContextId(Utils::SmallStringView sourceContextPath) const = 0; + virtual DirectoryPathId directoryPathId(Utils::SmallStringView directoryPath) const = 0; virtual SourcePath sourcePath(SourceId sourceId) const = 0; - virtual Utils::PathString sourceContextPath(SourceContextId sourceContextId) const = 0; + virtual Utils::PathString directoryPath(DirectoryPathId directoryPathId) const = 0; - virtual Utils::SmallString sourceName(SourceNameId sourceNameId) const = 0; + virtual Utils::SmallString fileName(FileNameId fileNameId) const = 0; protected: ~SourcePathCacheInterface() = default; diff --git a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathcachetypes.h b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathcachetypes.h index 0f6a40c626c..645340456a0 100644 --- a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathcachetypes.h +++ b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathcachetypes.h @@ -13,35 +13,35 @@ namespace QmlDesigner::Cache { -class SourceContext - : public StorageCacheEntry +class DirectoryPath + : public StorageCacheEntry { - using Base = StorageCacheEntry; + using Base = StorageCacheEntry; public: using Base::Base; - friend bool operator==(const SourceContext &first, const SourceContext &second) + friend bool operator==(const DirectoryPath &first, const DirectoryPath &second) { return first.id == second.id && first.value == second.value; } }; -using SourceContexts = std::vector; +using DirectoryPaths = std::vector; -class SourceName : public StorageCacheEntry +class FileName : public StorageCacheEntry { - using Base = StorageCacheEntry; + using Base = StorageCacheEntry; public: using Base::Base; - friend bool operator==(const SourceName &first, const SourceName &second) + friend bool operator==(const FileName &first, const FileName &second) { return first.id == second.id && first.value == second.value; } }; -using SourceNames = std::vector; +using FileNames = std::vector; } // namespace QmlDesigner::Cache diff --git a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathexceptions.cpp b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathexceptions.cpp index 04365236e71..4e55c977be1 100644 --- a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathexceptions.cpp +++ b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathexceptions.cpp @@ -26,42 +26,42 @@ const char *NoSourcePathForInvalidSourceId::what() const noexcept return "You cannot get a file path for an invalid file path id!"; } -NoSourceContextPathForInvalidSourceContextId::NoSourceContextPathForInvalidSourceContextId() +NoDirectoryPathForInvalidDirectoryPathId::NoDirectoryPathForInvalidDirectoryPathId() { - category().threadEvent("NoSourceContextPathForInvalidSourceContextId"); + category().threadEvent("NoDirectoryPathForInvalidDirectoryPathId"); } -const char *NoSourceContextPathForInvalidSourceContextId::what() const noexcept +const char *NoDirectoryPathForInvalidDirectoryPathId::what() const noexcept { return "You cannot get a directory path for an invalid directory path id!"; } -SourceContextIdDoesNotExists::SourceContextIdDoesNotExists() +DirectoryPathIdDoesNotExists::DirectoryPathIdDoesNotExists() { - category().threadEvent("SourceContextIdDoesNotExists"); + category().threadEvent("DirectoryPathIdDoesNotExists"); } -const char *SourceContextIdDoesNotExists::what() const noexcept +const char *DirectoryPathIdDoesNotExists::what() const noexcept { return "The source context id does not exist in the database!"; } -SourceNameIdDoesNotExists::SourceNameIdDoesNotExists() +FileNameIdDoesNotExists::FileNameIdDoesNotExists() { - category().threadEvent("SourceNameIdDoesNotExists"); + category().threadEvent("FileNameIdDoesNotExists"); } -const char *SourceNameIdDoesNotExists::what() const noexcept +const char *FileNameIdDoesNotExists::what() const noexcept { return "The source id does not exist in the database!"; } -NoSourceNameForInvalidSourceNameId::NoSourceNameForInvalidSourceNameId() +NoFileNameForInvalidFileNameId::NoFileNameForInvalidFileNameId() { - category().threadEvent("NoSourceNameForInvalidSourceNameId"); + category().threadEvent("NoFileNameForInvalidFileNameId"); } -const char *NoSourceNameForInvalidSourceNameId::what() const noexcept +const char *NoFileNameForInvalidFileNameId::what() const noexcept { return "You cannot get a source name for an invalid source name id!"; } diff --git a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathexceptions.h b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathexceptions.h index 958f99fab93..23691db61c2 100644 --- a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathexceptions.h +++ b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathexceptions.h @@ -27,31 +27,31 @@ public: const char *what() const noexcept override; }; -class QMLDESIGNERCORE_EXPORT NoSourceNameForInvalidSourceNameId : public SourcePathError +class QMLDESIGNERCORE_EXPORT NoFileNameForInvalidFileNameId : public SourcePathError { public: - NoSourceNameForInvalidSourceNameId(); + NoFileNameForInvalidFileNameId(); const char *what() const noexcept override; }; -class QMLDESIGNERCORE_EXPORT NoSourceContextPathForInvalidSourceContextId : public SourcePathError +class QMLDESIGNERCORE_EXPORT NoDirectoryPathForInvalidDirectoryPathId : public SourcePathError { public: - NoSourceContextPathForInvalidSourceContextId(); + NoDirectoryPathForInvalidDirectoryPathId(); const char *what() const noexcept override; }; -class QMLDESIGNERCORE_EXPORT SourceContextIdDoesNotExists : public SourcePathError +class QMLDESIGNERCORE_EXPORT DirectoryPathIdDoesNotExists : public SourcePathError { public: - SourceContextIdDoesNotExists(); + DirectoryPathIdDoesNotExists(); const char *what() const noexcept override; }; -class QMLDESIGNERCORE_EXPORT SourceNameIdDoesNotExists : public SourcePathError +class QMLDESIGNERCORE_EXPORT FileNameIdDoesNotExists : public SourcePathError { public: - SourceNameIdDoesNotExists(); + FileNameIdDoesNotExists(); const char *what() const noexcept override; }; diff --git a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathstorage.cpp b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathstorage.cpp index e1f8beaab51..f10384467f1 100644 --- a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathstorage.cpp +++ b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathstorage.cpp @@ -18,24 +18,24 @@ struct SourcePathStorage::Statements {} Sqlite::Database &database; - mutable Sqlite::ReadStatement<1, 1> selectSourceContextIdFromSourceContextsBySourceContextPathStatement{ - "SELECT sourceContextId FROM sourceContexts WHERE sourceContextPath = ?", database}; - mutable Sqlite::ReadStatement<1, 1> selectSourceContextPathFromSourceContextsBySourceContextIdStatement{ - "SELECT sourceContextPath FROM sourceContexts WHERE sourceContextId = ?", database}; - mutable Sqlite::ReadStatement<2> selectAllSourceContextsStatement{ - "SELECT sourceContextPath, sourceContextId FROM sourceContexts", database}; - Sqlite::WriteStatement<1> insertIntoSourceContextsStatement{ - "INSERT INTO sourceContexts(sourceContextPath) VALUES (?)", database}; - mutable Sqlite::ReadStatement<1, 1> selectSourceNameIdFromSourceNamesBySourceNameStatement{ - "SELECT sourceNameId FROM sourceNames WHERE sourceName = ?", database}; - mutable Sqlite::ReadStatement<1, 1> selectSourceNameFromSourceNamesBySourceNameIdStatement{ - "SELECT sourceName FROM sourceNames WHERE sourceNameId = ?", database}; + mutable Sqlite::ReadStatement<1, 1> selectDirectoryPathIdFromDirectoryPathsByDirectoryPathStatement{ + "SELECT directoryPathId FROM directoryPaths WHERE directoryPath = ?", database}; + mutable Sqlite::ReadStatement<1, 1> selectDirectoryPathFromDirectoryPathsByDirectoryPathIdStatement{ + "SELECT directoryPath FROM directoryPaths WHERE directoryPathId = ?", database}; + mutable Sqlite::ReadStatement<2> selectAllDirectoryPathsStatement{ + "SELECT directoryPath, directoryPathId FROM directoryPaths", database}; + Sqlite::WriteStatement<1> insertIntoDirectoryPathsStatement{ + "INSERT INTO directoryPaths(directoryPath) VALUES (?)", database}; + mutable Sqlite::ReadStatement<1, 1> selectFileNameIdFromFileNamesByFileNameStatement{ + "SELECT fileNameId FROM fileNames WHERE fileName = ?", database}; + mutable Sqlite::ReadStatement<1, 1> selectFileNameFromFileNamesByFileNameIdStatement{ + "SELECT fileName FROM fileNames WHERE fileNameId = ?", database}; Sqlite::WriteStatement<1> insertIntoSourcesStatement{ - "INSERT INTO sourceNames(sourceName) VALUES (?)", database}; + "INSERT INTO fileNames(fileName) VALUES (?)", database}; mutable Sqlite::ReadStatement<2> selectAllSourcesStatement{ - "SELECT sourceName, sourceNameId FROM sourceNames", database}; - Sqlite::WriteStatement<0> deleteAllSourceNamesStatement{"DELETE FROM sourceNames", database}; - Sqlite::WriteStatement<0> deleteAllSourceContextsStatement{"DELETE FROM sourceContexts", database}; + "SELECT fileName, fileNameId FROM fileNames", database}; + Sqlite::WriteStatement<0> deleteAllFileNamesStatement{"DELETE FROM fileNames", database}; + Sqlite::WriteStatement<0> deleteAllDirectoryPathsStatement{"DELETE FROM directoryPaths", database}; }; class SourcePathStorage::Initializer @@ -44,32 +44,32 @@ public: Initializer(Database &database, bool isInitialized) { if (!isInitialized) { - createSourceContextsTable(database); - createSourceNamesTable(database); + createDirectoryPathsTable(database); + createFileNamesTable(database); } } - void createSourceContextsTable(Database &database) + void createDirectoryPathsTable(Database &database) { Sqlite::Table table; table.setUseIfNotExists(true); - table.setName("sourceContexts"); - table.addColumn("sourceContextId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); - const Sqlite::Column &sourceContextPathColumn = table.addColumn("sourceContextPath"); + table.setName("directoryPaths"); + table.addColumn("directoryPathId", Sqlite::ColumnType::Integer, {Sqlite::PrimaryKey{}}); + const Sqlite::Column &directoryPathColumn = table.addColumn("directoryPath"); - table.addUniqueIndex({sourceContextPathColumn}); + table.addUniqueIndex({directoryPathColumn}); table.initialize(database); } - void createSourceNamesTable(Database &database) + void createFileNamesTable(Database &database) { Sqlite::StrictTable table; table.setUseIfNotExists(true); - table.setName("sourceNames"); - table.addColumn("sourceNameId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); - const auto &sourceNameColumn = table.addColumn("sourceName", Sqlite::StrictColumnType::Text); - table.addUniqueIndex({sourceNameColumn}); + table.setName("fileNames"); + table.addColumn("fileNameId", Sqlite::StrictColumnType::Integer, {Sqlite::PrimaryKey{}}); + const auto &fileNameColumn = table.addColumn("fileName", Sqlite::StrictColumnType::Text); + table.addUniqueIndex({fileNameColumn}); table.initialize(database); } @@ -88,52 +88,52 @@ SourcePathStorage::SourcePathStorage(Database &database, bool isInitialized) SourcePathStorage::~SourcePathStorage() = default; -SourceContextId SourcePathStorage::fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath) +DirectoryPathId SourcePathStorage::fetchDirectoryPathIdUnguarded(Utils::SmallStringView directoryPath) { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"fetch source context id unguarded", category()}; - auto sourceContextId = readSourceContextId(sourceContextPath); + auto directoryPathId = readDirectoryPathId(directoryPath); - return sourceContextId ? sourceContextId : writeSourceContextId(sourceContextPath); + return directoryPathId ? directoryPathId : writeDirectoryPathId(directoryPath); } -SourceContextId SourcePathStorage::fetchSourceContextId(Utils::SmallStringView sourceContextPath) +DirectoryPathId SourcePathStorage::fetchDirectoryPathId(Utils::SmallStringView directoryPath) { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"fetch source context id", category(), - keyValue("source context path", sourceContextPath)}; + keyValue("source context path", directoryPath)}; - SourceContextId sourceContextId; + DirectoryPathId directoryPathId; try { - sourceContextId = Sqlite::withDeferredTransaction(database, [&] { - return fetchSourceContextIdUnguarded(sourceContextPath); + directoryPathId = Sqlite::withDeferredTransaction(database, [&] { + return fetchDirectoryPathIdUnguarded(directoryPath); }); } catch (const Sqlite::ConstraintPreventsModification &) { - sourceContextId = fetchSourceContextId(sourceContextPath); + directoryPathId = fetchDirectoryPathId(directoryPath); } - tracer.end(keyValue("source context id", sourceContextId)); + tracer.end(keyValue("source context id", directoryPathId)); - return sourceContextId; + return directoryPathId; } -Utils::PathString SourcePathStorage::fetchSourceContextPath(SourceContextId sourceContextId) const +Utils::PathString SourcePathStorage::fetchDirectoryPath(DirectoryPathId directoryPathId) const { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"fetch source context path", category(), - keyValue("source context id", sourceContextId)}; + keyValue("source context id", directoryPathId)}; auto path = Sqlite::withDeferredTransaction(database, [&] { - auto optionalSourceContextPath = s->selectSourceContextPathFromSourceContextsBySourceContextIdStatement - .optionalValue(sourceContextId); + auto optionalDirectoryPath = s->selectDirectoryPathFromDirectoryPathsByDirectoryPathIdStatement + .optionalValue(directoryPathId); - if (!optionalSourceContextPath) - throw SourceContextIdDoesNotExists(); + if (!optionalDirectoryPath) + throw DirectoryPathIdDoesNotExists(); - return std::move(*optionalSourceContextPath); + return std::move(*optionalDirectoryPath); }); tracer.end(keyValue("source context path", path)); @@ -141,133 +141,133 @@ Utils::PathString SourcePathStorage::fetchSourceContextPath(SourceContextId sour return path; } -Cache::SourceContexts SourcePathStorage::fetchAllSourceContexts() const +Cache::DirectoryPaths SourcePathStorage::fetchAllDirectoryPaths() const { NanotraceHR::Tracer tracer{"fetch all source contexts", category()}; - return s->selectAllSourceContextsStatement.valuesWithTransaction(); + return s->selectAllDirectoryPathsStatement.valuesWithTransaction(); } -SourceNameId SourcePathStorage::fetchSourceNameId(Utils::SmallStringView sourceName) +FileNameId SourcePathStorage::fetchFileNameId(Utils::SmallStringView fileName) { using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"fetch source id", category(), keyValue("source name", sourceName)}; + NanotraceHR::Tracer tracer{"fetch source id", category(), keyValue("source name", fileName)}; - auto sourceNameId = Sqlite::withDeferredTransaction(database, [&] { - return fetchSourceNameIdUnguarded(sourceName); + auto fileNameId = Sqlite::withDeferredTransaction(database, [&] { + return fetchFileNameIdUnguarded(fileName); }); - tracer.end(keyValue("source name id", sourceNameId)); + tracer.end(keyValue("source name id", fileNameId)); - return sourceNameId; + return fileNameId; } -Utils::SmallString SourcePathStorage::fetchSourceName(SourceNameId sourceNameId) const +Utils::SmallString SourcePathStorage::fetchFileName(FileNameId fileNameId) const { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"fetch source name and source context id", category(), - keyValue("source name id", sourceNameId)}; + keyValue("source name id", fileNameId)}; - auto sourceName = s->selectSourceNameFromSourceNamesBySourceNameIdStatement - .valueWithTransaction(sourceNameId); + auto fileName = s->selectFileNameFromFileNamesByFileNameIdStatement + .valueWithTransaction(fileNameId); - if (sourceName.empty()) - throw SourceNameIdDoesNotExists(); + if (fileName.empty()) + throw FileNameIdDoesNotExists(); - tracer.end(keyValue("source name", sourceName)); + tracer.end(keyValue("source name", fileName)); - return sourceName; + return fileName; } void SourcePathStorage::clearSources() { Sqlite::withImmediateTransaction(database, [&] { - s->deleteAllSourceContextsStatement.execute(); - s->deleteAllSourceNamesStatement.execute(); + s->deleteAllDirectoryPathsStatement.execute(); + s->deleteAllFileNamesStatement.execute(); }); } -Cache::SourceNames SourcePathStorage::fetchAllSourceNames() const +Cache::FileNames SourcePathStorage::fetchAllFileNames() const { NanotraceHR::Tracer tracer{"fetch all sources", category()}; - return s->selectAllSourcesStatement.valuesWithTransaction(); + return s->selectAllSourcesStatement.valuesWithTransaction(); } -SourceNameId SourcePathStorage::fetchSourceNameIdUnguarded(Utils::SmallStringView sourceName) +FileNameId SourcePathStorage::fetchFileNameIdUnguarded(Utils::SmallStringView fileName) { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"fetch source id unguarded", category(), - keyValue("source name", sourceName)}; + keyValue("source name", fileName)}; - auto sourceId = readSourceNameId(sourceName); + auto sourceId = readFileNameId(fileName); if (!sourceId) - sourceId = writeSourceNameId(sourceName); + sourceId = writeFileNameId(fileName); tracer.end(keyValue("source id", sourceId)); return sourceId; } -SourceContextId SourcePathStorage::readSourceContextId(Utils::SmallStringView sourceContextPath) +DirectoryPathId SourcePathStorage::readDirectoryPathId(Utils::SmallStringView directoryPath) { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"read source context id", category(), - keyValue("source context path", sourceContextPath)}; + keyValue("source context path", directoryPath)}; - auto sourceContextId = s->selectSourceContextIdFromSourceContextsBySourceContextPathStatement - .value(sourceContextPath); + auto directoryPathId = s->selectDirectoryPathIdFromDirectoryPathsByDirectoryPathStatement + .value(directoryPath); - tracer.end(keyValue("source context id", sourceContextId)); + tracer.end(keyValue("source context id", directoryPathId)); - return sourceContextId; + return directoryPathId; } -SourceContextId SourcePathStorage::writeSourceContextId(Utils::SmallStringView sourceContextPath) +DirectoryPathId SourcePathStorage::writeDirectoryPathId(Utils::SmallStringView directoryPath) { using NanotraceHR::keyValue; NanotraceHR::Tracer tracer{"write source context id", category(), - keyValue("source context path", sourceContextPath)}; + keyValue("source context path", directoryPath)}; - s->insertIntoSourceContextsStatement.write(sourceContextPath); + s->insertIntoDirectoryPathsStatement.write(directoryPath); - auto sourceContextId = SourceContextId::create(static_cast(database.lastInsertedRowId())); + auto directoryPathId = DirectoryPathId::create(static_cast(database.lastInsertedRowId())); - tracer.end(keyValue("source context id", sourceContextId)); + tracer.end(keyValue("source context id", directoryPathId)); - return sourceContextId; + return directoryPathId; } -SourceNameId SourcePathStorage::writeSourceNameId(Utils::SmallStringView sourceName) +FileNameId SourcePathStorage::writeFileNameId(Utils::SmallStringView fileName) { using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"write source id", category(), keyValue("source name", sourceName)}; + NanotraceHR::Tracer tracer{"write source id", category(), keyValue("source name", fileName)}; - s->insertIntoSourcesStatement.write(sourceName); + s->insertIntoSourcesStatement.write(fileName); - auto sourceNameId = SourceNameId::create(static_cast(database.lastInsertedRowId())); + auto fileNameId = FileNameId::create(static_cast(database.lastInsertedRowId())); - tracer.end(keyValue("source name id", sourceNameId)); + tracer.end(keyValue("source name id", fileNameId)); - return sourceNameId; + return fileNameId; } -SourceNameId SourcePathStorage::readSourceNameId(Utils::SmallStringView sourceName) +FileNameId SourcePathStorage::readFileNameId(Utils::SmallStringView fileName) { using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"read source id", category(), keyValue("source name", sourceName)}; + NanotraceHR::Tracer tracer{"read source id", category(), keyValue("source name", fileName)}; - auto sourceNameId = s->selectSourceNameIdFromSourceNamesBySourceNameStatement.value( - sourceName); + auto fileNameId = s->selectFileNameIdFromFileNamesByFileNameStatement.value( + fileName); - tracer.end(keyValue("source id", sourceNameId)); + tracer.end(keyValue("source id", fileNameId)); - return sourceNameId; + return fileNameId; } void SourcePathStorage::resetForTestsOnly() diff --git a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathstorage.h b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathstorage.h index 2fc5896a320..b3e306ee18e 100644 --- a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathstorage.h +++ b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/sourcepathstorage.h @@ -21,34 +21,34 @@ public: SourcePathStorage(Database &database, bool isInitialized); ~SourcePathStorage(); - SourceContextId fetchSourceContextIdUnguarded(Utils::SmallStringView sourceContextPath); + DirectoryPathId fetchDirectoryPathIdUnguarded(Utils::SmallStringView directoryPath); - SourceContextId fetchSourceContextId(Utils::SmallStringView sourceContextPath); + DirectoryPathId fetchDirectoryPathId(Utils::SmallStringView directoryPath); - Utils::PathString fetchSourceContextPath(SourceContextId sourceContextId) const; + Utils::PathString fetchDirectoryPath(DirectoryPathId directoryPathId) const; - Cache::SourceContexts fetchAllSourceContexts() const; + Cache::DirectoryPaths fetchAllDirectoryPaths() const; - SourceNameId fetchSourceNameId(Utils::SmallStringView sourceName); + FileNameId fetchFileNameId(Utils::SmallStringView fileName); - Utils::SmallString fetchSourceName(SourceNameId sourceId) const; + Utils::SmallString fetchFileName(FileNameId sourceId) const; void clearSources(); - Cache::SourceNames fetchAllSourceNames() const; + Cache::FileNames fetchAllFileNames() const; - SourceNameId fetchSourceNameIdUnguarded(Utils::SmallStringView sourceName); + FileNameId fetchFileNameIdUnguarded(Utils::SmallStringView fileName); void resetForTestsOnly(); private: - SourceContextId readSourceContextId(Utils::SmallStringView sourceContextPath); + DirectoryPathId readDirectoryPathId(Utils::SmallStringView directoryPath); - SourceContextId writeSourceContextId(Utils::SmallStringView sourceContextPath); + DirectoryPathId writeDirectoryPathId(Utils::SmallStringView directoryPath); - SourceNameId writeSourceNameId(Utils::SmallStringView sourceName); + FileNameId writeFileNameId(Utils::SmallStringView fileName); - SourceNameId readSourceNameId(Utils::SmallStringView sourceName); + FileNameId readFileNameId(Utils::SmallStringView fileName); class Initializer; diff --git a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/storagecache.h b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/storagecache.h index 1a3e3ec3a05..ef29ab9b08e 100644 --- a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/storagecache.h +++ b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/storagecache.h @@ -33,7 +33,7 @@ template> class StorageCache { @@ -140,17 +140,11 @@ public: { m_entries = m_storage.fetchAll(); - std::sort(m_entries.begin(), m_entries.end(), [](ViewType first, ViewType second) { - return compare(first, second); - }); + std::ranges::sort(m_entries, Compare{}); std::size_t max_id = 0; - auto found = std::max_element(m_entries.begin(), - m_entries.end(), - [](const auto &first, const auto &second) { - return first.id < second.id; - }); + auto found = std::ranges::max_element(m_entries, {}, &CacheEntry::id); if (found != m_entries.end()) max_id = static_cast(found->id); @@ -162,31 +156,25 @@ public: void add(std::vector &&views) { - auto less = [](ViewType first, ViewType second) { return compare(first, second); }; + std::ranges::sort(views, Compare{}); - std::sort(views.begin(), views.end(), less); - - views.erase(std::unique(views.begin(), views.end()), views.end()); + auto removed = std::ranges::unique(views.begin(), views.end()); + views.erase(removed.begin(), removed.end()); CacheEntries newCacheEntries; newCacheEntries.reserve(views.size()); - std::set_difference(views.begin(), - views.end(), - m_entries.begin(), - m_entries.end(), - Utils::make_iterator([&](ViewType newView) { - IndexType index = m_storage.fetchId(newView); - newCacheEntries.emplace_back(newView, index); - }), - less); + Utils::set_difference( + views, + m_entries, + [&](ViewType newView) { + IndexType index = m_storage.fetchId(newView); + newCacheEntries.emplace_back(newView, index); + }, + Compare{}); if (newCacheEntries.size()) { - auto found = std::max_element(newCacheEntries.begin(), - newCacheEntries.end(), - [](const auto &first, const auto &second) { - return first.id < second.id; - }); + auto found = std::ranges::max_element(newCacheEntries, {}, &CacheEntry::id); auto max_id = static_cast(found->id); @@ -196,12 +184,12 @@ public: CacheEntries mergedCacheEntries; mergedCacheEntries.reserve(newCacheEntries.size() + m_entries.size()); - std::merge(std::make_move_iterator(m_entries.begin()), - std::make_move_iterator(m_entries.end()), - std::make_move_iterator(newCacheEntries.begin()), - std::make_move_iterator(newCacheEntries.end()), - std::back_inserter(mergedCacheEntries), - less); + std::ranges::merge(std::make_move_iterator(m_entries.begin()), + std::make_move_iterator(m_entries.end()), + std::make_move_iterator(newCacheEntries.begin()), + std::make_move_iterator(newCacheEntries.end()), + std::back_inserter(mergedCacheEntries), + Compare{}); m_entries = std::move(mergedCacheEntries); @@ -213,38 +201,50 @@ public: { std::shared_lock sharedLock(m_mutex); - auto found = find(view); + auto [iter, found] = find(view); - if (found != m_entries.end()) - return found->id; + if (found) + return iter->id; sharedLock.unlock(); std::lock_guard exclusiveLock(m_mutex); - if (!std::is_base_of::value) - found = find(view); - if (found == m_entries.end()) - found = insertEntry(found, view, m_storage.fetchId(view)); + if constexpr (!std::is_base_of_v) + std::tie(iter, found) = find(view); + if (!found) + iter = insertEntry(iter, view, m_storage.fetchId(view)); - return found->id; + return iter->id; } - template - std::vector ids(const Container &values) + template + std::vector ids(Utils::span values) { std::vector ids; ids.reserve(values.size()); - std::transform(values.begin(), values.end(), std::back_inserter(ids), [&](const auto &values) { - return this->id(values); + std::ranges::transform(values, std::back_inserter(ids), [&](ViewType value) { + return this->id(value); }); return ids; } - std::vector ids(std::initializer_list values) + template Proj> + using projected_value_t = std::remove_cvref_t &>>; + + template, Projection>> + QVarLengthArray ids(Value value, Projection projection) { - return ids>(values); + std::shared_lock sharedLock(m_mutex); + + auto range = std::ranges::equal_range(m_entries, value, Compare{}, projection); + + QVarLengthArray ids; + std::ranges::transform(range, std::back_inserter(ids), &CacheEntry::id); + return ids; } ResultType value(IndexType id) @@ -252,9 +252,9 @@ public: std::shared_lock sharedLock(m_mutex); if (IndexType::create(static_cast(m_indices.size()) + 1) > id) { - if (StorageCacheIndex indirectionIndex = m_indices.at(static_cast(id) - 1); + if (StorageCacheIndex indirectionIndex = m_indices[static_cast(id) - 1]; indirectionIndex.isValid()) { - return m_entries.at(static_cast(indirectionIndex)).value; + return m_entries[static_cast(indirectionIndex)].value; } } @@ -262,7 +262,7 @@ public: std::lock_guard exclusiveLock(m_mutex); Type value{m_storage.fetchValue(id)}; - auto interator = insertEntry(find(value), value, id); + auto interator = insertEntry(std::get<0>(find(value)), value, id); return interator->value; } @@ -276,9 +276,7 @@ public: for (IndexType id : ids) { values.emplace_back( - m_entries - .at(static_cast(m_indices.at(static_cast(id) - 1))) - .value); + m_entries[static_cast(m_indices[static_cast(id) - 1])].value); } return values; } @@ -304,34 +302,21 @@ private: } template - static auto find(Entries &&entries, ViewType view) + static std::tuple, bool> find(Entries &&entries, ViewType view) { - auto begin = entries.begin(); - auto end = entries.end(); - auto found = std::lower_bound(begin, end, view, compare); + auto found = std::ranges::lower_bound(entries, view, Compare{}); - if (found == entries.end()) { - return entries.end(); - } - - const auto &value = *found; - - if (value == view) { - return found; - } - - return entries.end(); + return {found, found != entries.end() && *found == view}; } IndexType id(ViewType view) const { std::shared_lock sharedLock(m_mutex); - auto found = find(view); + auto [iter, found] = find(view); - if (found != m_entries.end()) { - return found->id; - } + if (found) + return iter->id; return IndexType(); } @@ -341,9 +326,9 @@ private: std::shared_lock sharedLock(m_mutex); if (IndexType::create(static_cast(m_indices.size()) + 1) > id) { - if (StorageCacheIndex indirectionIndex = m_indices.at(static_cast(id) - 1); + if (StorageCacheIndex indirectionIndex = m_indices[static_cast(id) - 1]; indirectionIndex.isValid()) { - return m_entries.at(static_cast(indirectionIndex)).value; + return m_entries[static_cast(indirectionIndex)].value; } } @@ -377,7 +362,7 @@ private: auto indirectionIndex = static_cast(id) - 1; ensureSize(indirectionIndex); - m_indices.at(indirectionIndex) = newIndirectionIndex; + m_indices[indirectionIndex] = newIndirectionIndex; return inserted; } diff --git a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/storagecachefwd.h b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/storagecachefwd.h index a74c782f634..4ee78b4fa93 100644 --- a/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/storagecachefwd.h +++ b/src/plugins/qmldesigner/libs/designercore/sourcepathstorage/storagecachefwd.h @@ -9,12 +9,6 @@ namespace QmlDesigner { class NonLockingMutex; -template +template class StorageCache; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/project/projectstorageerrornotifier.cpp b/src/plugins/qmldesigner/project/projectstorageerrornotifier.cpp index f6fefe2b297..25646c21a35 100644 --- a/src/plugins/qmldesigner/project/projectstorageerrornotifier.cpp +++ b/src/plugins/qmldesigner/project/projectstorageerrornotifier.cpp @@ -24,6 +24,17 @@ void logIssue(ProjectExplorer::Task::TaskType type, const QString &message, cons ProjectExplorer::TaskHub::addTask(task); ProjectExplorer::TaskHub::requestPopup(); } + +void logIssue(ProjectExplorer::Task::TaskType type, const QString &message, QStringView sourcePath) +{ + const Utils::Id category = ProjectExplorer::Constants::TASK_CATEGORY_BUILDSYSTEM; + + Utils::FilePath filePath = Utils::FilePath::fromPathPart(sourcePath); + ProjectExplorer::Task task(type, message, filePath, -1, category); + ProjectExplorer::TaskHub::addTask(task); + ProjectExplorer::TaskHub::requestPopup(); +} + } // namespace void ProjectStorageErrorNotifier::typeNameCannotBeResolved(Utils::SmallStringView typeName, @@ -71,4 +82,11 @@ void ProjectStorageErrorNotifier::qmlDocumentDoesNotExistsForQmldirEntry(Utils:: m_pathCache.sourcePath(qmldirSourceId)); } +void ProjectStorageErrorNotifier::qmltypesFileMissing(QStringView qmltypesPath) +{ + logIssue(ProjectExplorer::Task::Warning, + Tr::tr("Not existing Qmltypes File %1.").arg(qmltypesPath), + qmltypesPath); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/project/projectstorageerrornotifier.h b/src/plugins/qmldesigner/project/projectstorageerrornotifier.h index ae720bac693..03606259d43 100644 --- a/src/plugins/qmldesigner/project/projectstorageerrornotifier.h +++ b/src/plugins/qmldesigner/project/projectstorageerrornotifier.h @@ -27,6 +27,7 @@ public: Storage::Version version, SourceId qmlDocumentSourceId, SourceId qmldirSourceId) override; + void qmltypesFileMissing(QStringView qmltypesPath) override; private: PathCacheType &m_pathCache; diff --git a/src/plugins/qmldesigner/project/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/project/qmldesignerprojectmanager.cpp index 40d38afb62c..3ae8a554585 100644 --- a/src/plugins/qmldesigner/project/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/project/qmldesignerprojectmanager.cpp @@ -214,10 +214,10 @@ public: , qmlDocumentParser{storage, pathCache} , pathWatcher{pathCache, fileStatusCache, &updater} , projectPartId{ProjectPartId::create( - pathCache.sourceContextId(Utils::PathString{project->projectDirectory().path()}) + pathCache.directoryPathId(Utils::PathString{project->projectDirectory().path()}) .internalId())} , qtPartId{ProjectPartId::create( - pathCache.sourceContextId(Utils::PathString{qmlPath(project)}).internalId())} + pathCache.directoryPathId(Utils::PathString{qmlPath(project)}).internalId())} , updater{fileSystem, storage, fileStatusCache, @@ -294,7 +294,7 @@ public: class QmlDesignerProjectManager::Data { public: - Sqlite::Database sourcePathDatabase{createDatabasePath("source_path.db"), + Sqlite::Database sourcePathDatabase{createDatabasePath("source_path_v1.db"), Sqlite::JournalMode::Wal, Sqlite::LockingMode::Normal}; QmlDesigner::SourcePathStorage sourcePathStorage{sourcePathDatabase, @@ -366,14 +366,21 @@ namespace { return nullptr; } +[[maybe_unused]] ProjectStorageTriggerUpdateInterface *dummyTriggerUpdate() +{ + return nullptr; +} + } // namespace ProjectStorageDependencies QmlDesignerProjectManager::projectStorageDependencies() { if constexpr (useProjectStorage()) { - return {m_projectData->projectStorageData->storage, m_data->pathCache}; + return {m_projectData->projectStorageData->storage, + m_data->pathCache, + m_projectData->projectStorageData->pathWatcher}; } else { - return {*dummyProjectStorage(), *dummyPathCache()}; + return {*dummyProjectStorage(), *dummyPathCache(), *dummyTriggerUpdate()}; } } @@ -400,6 +407,11 @@ namespace { if constexpr (useProjectStorage()) { auto qmlRootPath = qmlPath(target); qmldirPaths.push_back(qmlRootPath + "/QML"); + qmldirPaths.push_back(qmlRootPath + "/Qt"); + // TODO: Charts plugins.qmltypes needs to be fixed before QtCharts can be added (QTBUG-115358) + //qmldirPaths.push_back(qmlRootPath + "/QtCharts"); + // TODO: Graphs plugins.qmltypes needs to be fixed before QtGraphs can be added (QTBUG-135402) + //qmldirPaths.push_back(qmlRootPath + "/QtGraphs"); qmldirPaths.push_back(qmlRootPath + "/QtQml"); qmldirPaths.push_back(qmlRootPath + "/QtQuick"); qmldirPaths.push_back(qmlRootPath + "/QtQuick3D"); diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 58fc32e9932..8b1e89c4c78 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -44,6 +44,14 @@ inline constexpr char EDIT3D_EDIT_SHOW_CAMERA_FRUSTUM[] = "QmlDesigner.Editor3D.ToggleCameraFrustum"; inline constexpr char EDIT3D_EDIT_SHOW_PARTICLE_EMITTER[] = "QmlDesigner.Editor3D.ToggleParticleEmitter"; + +inline constexpr char EDIT3D_PRESETS[] = "QmlDesigner.Editor3D.Presets"; +inline constexpr char EDIT3D_PRESET_SINGLE[] = "QmlDesigner.Editor3D.Single"; +inline constexpr char EDIT3D_PRESET_QUAD[] = "QmlDesigner.Editor3D.Quad"; +inline constexpr char EDIT3D_PRESET_3LEFT1RIGHT[] = "QmlDesigner.Editor3D.3Left1Right"; +inline constexpr char EDIT3D_PRESET_2HORIZONTAL[] = "QmlDesigner.Editor3D.2Horizontal"; +inline constexpr char EDIT3D_PRESET_2VERTICAL[] = "QmlDesigner.Editor3D.2Vertical"; + inline constexpr char EDIT3D_RESET_VIEW[] = "QmlDesigner.Editor3D.ResetView"; inline constexpr char EDIT3D_PARTICLE_MODE[] = "QmlDesigner.Editor3D.ParticleViewModeToggle"; inline constexpr char EDIT3D_PARTICLES_PLAY[] = "QmlDesigner.Editor3D.ParticlesPlay"; @@ -59,6 +67,7 @@ inline constexpr char EDIT3D_SNAP_CONFIG[] = "QmlDesigner.Editor3D.SnapConfig"; inline constexpr char EDIT3D_CAMERA_SPEED_CONFIG[] = "QmlDesigner.Editor3D.CameraSpeedConfig"; inline constexpr char BUNDLE_JSON_FILENAME[] = "bundle.json"; +inline constexpr char CUSTOM_BUNDLES_JSON_FILENAME[] = "custom_bundles.json"; inline constexpr char BUNDLE_SUFFIX[] = "qdsbundle"; inline constexpr char COMPONENT_BUNDLES_EFFECT_BUNDLE_TYPE[] = "Effects"; inline constexpr char COMPONENT_BUNDLES_ASSET_REF_FILE[] = "_asset_ref.json"; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index fe2b72c61fe..d549973b0da 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -676,9 +676,7 @@ void QmlDesignerPlugin::enforceDelayedInitialize() transitionEditorView->registerActions(); if (QmlDesignerBasePlugin::experimentalFeaturesEnabled()) - d->viewManager.registerView( - std::make_unique(d->externalDependencies, - d->projectManager.projectStorageDependencies())); + d->viewManager.registerView(std::make_unique(d->externalDependencies)); d->viewManager.registerFormEditorTool(std::make_unique()); d->viewManager.registerFormEditorTool(std::make_unique()); @@ -849,6 +847,12 @@ void QmlDesignerPlugin::launchFeedbackPopupInternal(const QString &identifier) const QString qmlPath = Core::ICore::resourcePath("qmldesigner/feedback/FeedbackPopup.qml").toUrlishString(); m_feedbackWidget->setSource(QUrl::fromLocalFile(qmlPath)); + if (Utils::HostOsInfo::isLinuxHost()) { + QPoint pos = Core::ICore::dialogParent()->pos(); + int x = (Core::ICore::dialogParent()->width() - m_feedbackWidget->width()) / 2; + int y = (Core::ICore::dialogParent()->height() - m_feedbackWidget->height()) / 2; + m_feedbackWidget->move(pos.x() + x, pos.y() + y); + } if (!m_feedbackWidget->errors().isEmpty()) { qDebug() << qmlPath; qDebug() << m_feedbackWidget->errors().first().toString(); diff --git a/src/plugins/qmldesigner/qmltools/qmlvisualnode.cpp b/src/plugins/qmldesigner/qmltools/qmlvisualnode.cpp index 5b6246c69af..f586852b83f 100644 --- a/src/plugins/qmldesigner/qmltools/qmlvisualnode.cpp +++ b/src/plugins/qmldesigner/qmltools/qmlvisualnode.cpp @@ -289,6 +289,8 @@ static QmlObjectNode createQmlObjectNodeFromSource(AbstractView *view, auto inputModel = Model::create("QtQuick.Item", 1, 0, view->model()); #endif inputModel->setFileUrl(view->model()->fileUrl()); + inputModel->changeImports(view->model()->imports(), {}); + QPlainTextEdit textEdit; textEdit.setPlainText(source); @@ -300,6 +302,7 @@ static QmlObjectNode createQmlObjectNodeFromSource(AbstractView *view, rewriterView->setTextModifier(&modifier); rewriterView->setAllowComponentRoot(true); rewriterView->setPossibleImportsEnabled(false); + rewriterView->setRemoveImports(false); inputModel->setRewriterView(rewriterView.get()); if (rewriterView->errors().isEmpty() && rewriterView->rootModelNode().isValid()) { diff --git a/src/plugins/qmldesignerbase/utils/windowmanager.cpp b/src/plugins/qmldesignerbase/utils/windowmanager.cpp index a254da69ab0..5b7ed2131fc 100644 --- a/src/plugins/qmldesignerbase/utils/windowmanager.cpp +++ b/src/plugins/qmldesignerbase/utils/windowmanager.cpp @@ -19,11 +19,32 @@ WindowManager::WindowManager() connect(qGuiApp, &QGuiApplication::focusWindowChanged, this, &WindowManager::focusWindowChanged); connect( Core::ICore::instance(), &Core::ICore::coreAboutToClose, this, &WindowManager::aboutToQuit); - connect( - Core::ICore::instance()->mainWindow()->windowHandle(), - &QWindow::visibleChanged, - this, - &WindowManager::mainWindowVisibleChanged); + + if (!connectMainWindowHandle()) + Core::ICore::instance()->mainWindow()->installEventFilter(this); +} + +bool WindowManager::connectMainWindowHandle() +{ + if (QWindow *windowHandle = Core::ICore::instance()->mainWindow()->windowHandle()) { + QMetaObject::Connection success = connect( + windowHandle, + &QWindow::visibleChanged, + this, + &WindowManager::mainWindowVisibleChanged, + Qt::UniqueConnection); + return success; + } + return false; +} + +bool WindowManager::eventFilter(QObject *watched, QEvent *event) +{ + if (watched == Core::ICore::instance()->mainWindow() && event->type() == QEvent::WinIdChange) { + connectMainWindowHandle(); + Core::ICore::instance()->mainWindow()->removeEventFilter(this); + } + return QObject::eventFilter(watched, event); } void WindowManager::registerDeclarativeType() diff --git a/src/plugins/qmldesignerbase/utils/windowmanager.h b/src/plugins/qmldesignerbase/utils/windowmanager.h index 1e74c721bc6..d329b53dc98 100644 --- a/src/plugins/qmldesignerbase/utils/windowmanager.h +++ b/src/plugins/qmldesignerbase/utils/windowmanager.h @@ -35,6 +35,7 @@ signals: private: WindowManager(); + bool connectMainWindowHandle(); + bool eventFilter(QObject *watched, QEvent *event) override; }; - } // namespace QmlDesigner diff --git a/src/plugins/qmlprojectmanager/CMakeLists.txt b/src/plugins/qmlprojectmanager/CMakeLists.txt index 34c66276806..ba1e001aff2 100644 --- a/src/plugins/qmlprojectmanager/CMakeLists.txt +++ b/src/plugins/qmlprojectmanager/CMakeLists.txt @@ -48,6 +48,7 @@ extend_qtc_plugin(QmlProjectManager cmakewriter.cpp cmakewriter.h cmakewriterv0.cpp cmakewriterv0.h cmakewriterv1.cpp cmakewriterv1.h + cmakewriterlib.cpp cmakewriterlib.h exporter.cpp exporter.h filegenerator.cpp filegenerator.h filetypes.cpp filetypes.h diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/boilerplate.qrc b/src/plugins/qmlprojectmanager/qmlprojectexporter/boilerplate.qrc index 50e9909a17c..822a2f807bd 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/boilerplate.qrc +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/boilerplate.qrc @@ -2,6 +2,7 @@ templates/cmakeroot_v0.tpl templates/cmakeroot_v1.tpl + templates/cmakeroot_lib.tpl templates/main_cpp_v0.tpl templates/main_cpp_v1.tpl templates/cmakemodule_v1.tpl diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.cpp index a24b1501640..72ba19c4276 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.cpp @@ -10,10 +10,12 @@ #include #include +#include #include #include #include +#include #include @@ -61,7 +63,12 @@ void CMakeGenerator::updateProject(QmlProject *project) if (!isEnabled()) return; - m_writer = CMakeWriter::create(this); + if (!isActive()) + return; + + createWriter(); + if (!m_writer) + return; m_root = std::make_shared(); m_root->type = Node::Type::App; @@ -86,6 +93,14 @@ QString CMakeGenerator::projectName() const return m_projectName; } +Utils::FilePath CMakeGenerator::projectDir() const +{ + if (!m_root) + return {}; + + return m_root->dir; +} + bool CMakeGenerator::findFile(const Utils::FilePath& file) const { return findFile(m_root, file); @@ -441,6 +456,18 @@ void CMakeGenerator::removeFile(NodePtr &node, const Utils::FilePath &path) cons } } +void CMakeGenerator::removeAmbiguousFiles(const Utils::FilePath &rootPath) const +{ + const Utils::FilePath rootCMakeFile = rootPath.pathAppended("CMakeLists.txt"); + rootCMakeFile.removeFile(); + + const Utils::FilePath sourceDirPath = rootPath.pathAppended("App"); + if (sourceDirPath.exists()) { + const Utils::FilePath appCMakeFile = sourceDirPath.pathAppended("CMakeLists.txt"); + appCMakeFile.removeFile(); + } +} + void CMakeGenerator::printModules(const NodePtr &node) const { if (node->type == Node::Type::Module) @@ -471,11 +498,12 @@ void CMakeGenerator::printNodeTree(const NodePtr &generatorNode, size_t indent) case Node::Type::Module: typeString = "Node::Type::Module"; break; + case Node::Type::MockModule: + typeString = "Node::Type::MockModule"; + break; case Node::Type::Library: typeString = "Node::Type::Library"; break; - default: - typeString = "Node::Type::Undefined"; } qDebug() << addIndent(indent) << "GeneratorNode: " << generatorNode->name; @@ -518,7 +546,11 @@ void CMakeGenerator::parseSourceTree() { QTC_ASSERT(m_writer, return); - const Utils::FilePath srcDir = m_root->dir.pathAppended(m_writer->sourceDirName()); + QString srcDirName = m_writer->sourceDirName(); + if (srcDirName.isEmpty()) + return; + + const Utils::FilePath srcDir = m_root->dir.pathAppended(srcDirName); QDirIterator it(srcDir.path(), {"*.cpp"}, QDir::Files, QDirIterator::Subdirectories); NodePtr srcNode = std::make_shared(); @@ -561,5 +593,62 @@ void CMakeGenerator::compareWithFileSystem(const NodePtr &node) const logIssue(ProjectExplorer::Task::Warning, text, file); } +void CMakeGenerator::createWriter() +{ + auto writer = CMakeWriter::create(this); + + const QmlProject *project = qmlProject(); + QTC_ASSERT(project, return ); + + const Utils::FilePath rootPath = project->projectDirectory(); + const Utils::FilePath settingsFile = rootPath.pathAppended("CMakeLists.txt.shared"); + Utils::PersistentSettingsReader reader; + reader.load(settingsFile); + auto store = reader.restoreValues(); + + auto writeSettings = [settingsFile, &store](int identifier) { + store["CMake Generator"] = identifier; + QString error; + Utils::PersistentSettingsWriter settingsWriter(settingsFile, "QtCreatorProject"); + if (!settingsWriter.save(store, &error)) { + const QString text("Failed to write settings file"); + logIssue(ProjectExplorer::Task::Error, text, settingsFile); + } + }; + + QVariant idVariant = store["CMake Generator"]; + if (!idVariant.isValid()) { + writeSettings(writer->identifier()); + m_writer = writer; + return; + } + + int identifier = writer->identifier(); + int currentId = idVariant.toInt(); + if (currentId == identifier) { + m_writer = writer; + return; + } + + QMessageBox msgBox; + msgBox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Ok); + msgBox.setText("The CmakeGenerator Has Changed"); + msgBox.setInformativeText( + "This operation will delete build files that may contain" + " user-made changes. Are you sure you want to proceed?"); + int ret = msgBox.exec(); + + if (ret == QMessageBox::Cancel) { + m_writer = CMakeWriter::createAndRecover(currentId, this); + return; + } + + removeAmbiguousFiles( rootPath ); + + writeSettings(writer->identifier()); + m_writer = writer; +} + } // namespace QmlProjectExporter } // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.h index ed03b36994c..f1225f858e2 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.h +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakegenerator.h @@ -33,6 +33,8 @@ public: void updateMenuAction() override; QString projectName() const; + Utils::FilePath projectDir() const; + bool findFile(const Utils::FilePath &file) const; bool isRootNode(const NodePtr &node) const; bool hasChildModule(const NodePtr &node) const; @@ -57,6 +59,7 @@ private: bool findFile(const NodePtr &node, const Utils::FilePath &file) const; void insertFile(NodePtr &node, const Utils::FilePath &path) const; void removeFile(NodePtr &node, const Utils::FilePath &path) const; + void removeAmbiguousFiles(const Utils::FilePath &rootPath) const; void printModules(const NodePtr &generatorNode) const; void printNodeTree(const NodePtr &generatorNode, size_t indent = 0) const; @@ -66,6 +69,7 @@ private: void compareWithFileSystem(const NodePtr &node) const; + void createWriter(); CMakeWriter::Ptr m_writer = {}; QString m_projectName = {}; diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.cpp index c6e6fc2e3ee..04f629795c5 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.cpp @@ -4,6 +4,7 @@ #include "cmakegenerator.h" #include "cmakewriterv0.h" #include "cmakewriterv1.h" +#include "cmakewriterlib.h" #include "qmlprojectmanager/buildsystem/qmlbuildsystem.h" #include "qmlprojectmanager/qmlproject.h" @@ -42,14 +43,24 @@ CMakeWriter::Ptr CMakeWriter::create(CMakeGenerator *parent) const QmlBuildSystem *buildSystem = parent->buildSystem(); QTC_ASSERT(buildSystem, return {}); - auto [major, minor, patch] = versionFromString(buildSystem->versionDesignStudio()); + auto version = versionFromString(buildSystem->versionDesignStudio()); + auto normalizedVersion = normalizeVersion(version); - bool useV1 = false; - if (major.has_value()) - useV1 = minor.has_value() ? *major >= 4 && *minor >= 5 : *major >= 5; - - if (useV1) + if (normalizedVersion >= std::make_tuple(4, 5, 0)) { + if (!buildSystem->standaloneApp()) { + if (normalizedVersion >= std::make_tuple(4, 8, 0)) { + return std::make_unique(parent); + } else { + CMakeGenerator::logIssue( + ProjectExplorer::Task::Error, + Tr::tr( + "Compiling the project as a library requires" + " Qt Design Studio 4.8 or later."), + buildSystem->projectFilePath()); + } + } return std::make_unique(parent); + } CMakeGenerator::logIssue( ProjectExplorer::Task::Warning, @@ -67,6 +78,24 @@ CMakeWriter::Ptr CMakeWriter::create(CMakeGenerator *parent) return std::make_unique(parent); } +CMakeWriter::Ptr CMakeWriter::createAndRecover(int id, CMakeGenerator *parent) +{ + switch (id) + { + case 1: + return std::make_unique(parent); + case 2: + parent->setStandaloneApp(true); + return std::make_unique(parent); + case 3: + parent->setStandaloneApp(false); + return std::make_unique(parent); + default: + break; + } + return {}; +} + CMakeWriter::Version CMakeWriter::versionFromString(const QString &versionString) { const QStringList versions = versionString.split('.', Qt::SkipEmptyParts); @@ -98,6 +127,12 @@ CMakeWriter::Version CMakeWriter::versionFromIgnoreFile(const Utils::FilePath &p return {}; } +CMakeWriter::NormalizedVersion CMakeWriter::normalizeVersion(const Version &version) +{ + auto [major, minor, patch] = version; + return {major.value_or(0), minor.value_or(0), patch.value_or(0)}; +} + QString CMakeWriter::readTemplate(const QString &templatePath) { QFile templatefile(templatePath); @@ -149,6 +184,19 @@ QString CMakeWriter::sourceDirName() const void CMakeWriter::transformNode(NodePtr &) const {} +bool CMakeWriter::hasNewComponents() const +{ + auto rootDir = m_parent->projectDir(); + auto componentsDir = rootDir.pathAppended("Dependencies/Components"); + + if (!componentsDir.exists()) + return false; + + auto ignoreFile = componentsDir.pathAppended("ignore-in-qds"); + auto version = normalizeVersion(versionFromIgnoreFile(ignoreFile)); + return version >= std::make_tuple(4, 8, 0); +} + std::vector CMakeWriter::files(const NodePtr &node, const FileGetter &getter) const { std::vector out = getter(node); diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.h index 15f3e090b91..481f702909f 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.h +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriter.h @@ -63,10 +63,14 @@ class CMakeWriter public: using Ptr = std::shared_ptr; using Version = std::tuple, std::optional, std::optional>; + using NormalizedVersion = std::tuple; static Ptr create(CMakeGenerator *parent); + static Ptr createAndRecover(int id, CMakeGenerator *parent); + static Version versionFromString(const QString &versionString); static Version versionFromIgnoreFile(const Utils::FilePath &path); + static NormalizedVersion normalizeVersion(const Version &version); static QString readTemplate(const QString &templatePath); static void writeFile(const Utils::FilePath &path, const QString &content); @@ -79,11 +83,14 @@ public: virtual QString sourceDirName() const; virtual void transformNode(NodePtr &) const; + virtual int identifier() const = 0; virtual void writeRootCMakeFile(const NodePtr &node) const = 0; virtual void writeModuleCMakeFile(const NodePtr &node, const NodePtr &root) const = 0; virtual void writeSourceFiles(const NodePtr &node, const NodePtr &root) const = 0; protected: + bool hasNewComponents() const; + std::vector files(const NodePtr &node, const FileGetter &getter) const; std::vector qmlFiles(const NodePtr &node) const; std::vector singletons(const NodePtr &node) const; diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterlib.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterlib.cpp new file mode 100644 index 00000000000..7a2985a7b96 --- /dev/null +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterlib.cpp @@ -0,0 +1,112 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include "cmakewriterlib.h" +#include "cmakegenerator.h" + +#include "qmlprojectmanager/buildsystem/qmlbuildsystem.h" + +#include + +namespace QmlProjectManager { + +namespace QmlProjectExporter { + +CMakeWriterLib::CMakeWriterLib(CMakeGenerator *parent) + : CMakeWriterV1(parent) +{ } + +QString CMakeWriterLib::mainLibName() const +{ + QTC_ASSERT(parent(), return {}); + return parent()->projectName() + "Lib"; +} + +void CMakeWriterLib::transformNode(NodePtr &node) const +{ + CMakeWriterV1::transformNode(node); +} + +int CMakeWriterLib::identifier() const +{ + return 3; +} + +void CMakeWriterLib::writeRootCMakeFile(const NodePtr &node) const +{ + QTC_ASSERT(parent(), return); + + const Utils::FilePath cmakeFolderPath = node->dir.pathAppended("cmake"); + if (!cmakeFolderPath.exists()) + cmakeFolderPath.createDir(); + + const Utils::FilePath insightPath = cmakeFolderPath.pathAppended("insight.cmake"); + if (!insightPath.exists()) { + const QString insightTemplate = readTemplate(":/templates/insight"); + writeFile(insightPath, insightTemplate); + } + + createDependencies(node->dir); + + const Utils::FilePath sharedFile = node->dir.pathAppended("CMakeLists.txt.shared"); + if (!sharedFile.exists()) { + const QString sharedTemplate = readTemplate(":/templates/cmake_shared"); + writeFile(sharedFile, sharedTemplate); + } + + const Utils::FilePath file = node->dir.pathAppended("CMakeLists.txt"); + if (!file.exists()) { + QString fileSection = ""; + const QString configFile = getEnvironmentVariable(ENV_VARIABLE_CONTROLCONF); + if (!configFile.isEmpty()) + fileSection = QString("\t\t%1").arg(configFile); + + const QString fileTemplate = readTemplate(":/templates/cmakeroot_lib"); + const QString fileContent = fileTemplate.arg(mainLibName(), fileSection); + writeFile(file, fileContent); + } +} + +void CMakeWriterLib::writeModuleCMakeFile(const NodePtr &node, const NodePtr &root) const +{ + CMakeWriterV1::writeModuleCMakeFile(node, root); +} + +void CMakeWriterLib::writeSourceFiles(const NodePtr &node, const NodePtr &root) const +{ + QTC_ASSERT(parent(), return); + QTC_ASSERT(parent()->buildSystem(), return); + + const QmlBuildSystem *buildSystem = parent()->buildSystem(); + + const Utils::FilePath srcDir = node->dir; + if (!srcDir.exists()) + srcDir.createDir(); + + const Utils::FilePath cmakePath = srcDir.pathAppended("CMakeLists.txt"); + if (!cmakePath.exists()) { + const QString includeAutogen = + "\ntarget_include_directories(%1 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})"; + writeFile(cmakePath, includeAutogen.arg(mainLibName())); + } + + const Utils::FilePath autogenDir = srcDir.pathAppended("autogen"); + if (!autogenDir.exists()) + autogenDir.createDir(); + + const Utils::FilePath headerPath = autogenDir.pathAppended("environment.h"); + + QString environmentPrefix; + for (const QString &module : plugins(root)) + environmentPrefix.append(QString("Q_IMPORT_QML_PLUGIN(%1)\n").arg(module + "Plugin")); + + const QString mainFile("const char mainQmlFile[] = \"qrc:/qt/qml/%1\";"); + environmentPrefix.append("\n"); + environmentPrefix.append(mainFile.arg(buildSystem->mainFile())); + + const QString environmentPostfix = makeSetEnvironmentFn(); + const QString headerTemplate = readTemplate(":/templates/environment_h"); + writeFile(headerPath, headerTemplate.arg(environmentPrefix, environmentPostfix)); +} + +} // namespace QmlProjectExporter +} // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterlib.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterlib.h new file mode 100644 index 00000000000..5b957d47937 --- /dev/null +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterlib.h @@ -0,0 +1,26 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#pragma once + +#include "cmakewriterv1.h" + +namespace QmlProjectManager { + +namespace QmlProjectExporter { + +class CMakeWriterLib final : public CMakeWriterV1 +{ +public: + CMakeWriterLib(CMakeGenerator *parent); + + QString mainLibName() const override; + void transformNode(NodePtr &node) const override; + + int identifier() const override; + void writeRootCMakeFile(const NodePtr &node) const override; + void writeModuleCMakeFile(const NodePtr &node, const NodePtr &root) const override; + void writeSourceFiles(const NodePtr &node, const NodePtr &root) const override; +}; + +} // namespace QmlProjectExporter +} // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.cpp index 41cd2e52e9a..7b4cb9984f8 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.cpp @@ -46,6 +46,11 @@ void CMakeWriterV0::transformNode(NodePtr &node) const } } +int CMakeWriterV0::identifier() const +{ + return 1; +} + void CMakeWriterV0::writeRootCMakeFile(const NodePtr &node) const { QTC_ASSERT(parent(), return); diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.h index b7f47f0d547..747b0389e7a 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.h +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv0.h @@ -16,6 +16,7 @@ public: bool isPlugin(const NodePtr &node) const override; void transformNode(NodePtr &node) const override; + int identifier() const override; void writeRootCMakeFile(const NodePtr &node) const override; void writeModuleCMakeFile(const NodePtr &node, const NodePtr &root) const override; void writeSourceFiles(const NodePtr &node, const NodePtr &root) const override; diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.cpp index 5593f556178..1cfbdb8add8 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.cpp @@ -33,6 +33,11 @@ CMakeWriterV1::CMakeWriterV1(CMakeGenerator *parent) : CMakeWriter(parent) {} +QString CMakeWriterV1::mainLibName() const +{ + return "${CMAKE_PROJECT_NAME}"; +} + QString CMakeWriterV1::sourceDirName() const { return "App"; @@ -47,6 +52,11 @@ void CMakeWriterV1::transformNode(NodePtr &node) const node->type = Node::Type::Module; } +int CMakeWriterV1::identifier() const +{ + return 2; +} + void CMakeWriterV1::writeRootCMakeFile(const NodePtr &node) const { QTC_ASSERT(parent(), return); @@ -62,72 +72,7 @@ void CMakeWriterV1::writeRootCMakeFile(const NodePtr &node) const writeFile(insightPath, insightTemplate); } - const Utils::FilePath dependenciesPath = node->dir.pathAppended(DEPENDENCIES_DIR); - const Utils::FilePath componentsPath = dependenciesPath.pathAppended(COMPONENTS_DIR); - const Utils::FilePath componentsIgnoreFile = componentsPath.pathAppended(COMPONENTS_IGNORE_FILE); - - bool copyComponents = false; - // Note: If dependencies directory exists but not the components directory, we assunme - // the user has intentionally deleted it because he has the components installed in Qt. - if (!dependenciesPath.exists()) { - dependenciesPath.createDir(); - copyComponents = true; - } else if (componentsIgnoreFile.exists()) { - auto normalizeVersion = [](const auto &version) -> std::tuple { - auto [major, minor, patch] = version; - return {major.value_or(0), minor.value_or(0), patch.value_or(0)}; - }; - auto *bs = parent()->buildSystem(); - auto versionDS = normalizeVersion(versionFromString(bs->versionDesignStudio())); - auto versionIgnore = normalizeVersion(versionFromIgnoreFile(componentsIgnoreFile)); - if (versionDS > versionIgnore) { - copyComponents = true; - if (componentsPath.exists()) - componentsPath.removeRecursively(); - } - } - - if (copyComponents) { - if (!componentsPath.exists()) - componentsPath.createDir(); - - const Utils::FilePath componentsSrc = - Core::ICore::resourcePath("qmldesigner/Dependencies/qtquickdesigner-components"); - - if (componentsSrc.exists()) { - auto cpyResult = componentsSrc.copyRecursively(componentsPath); - if (cpyResult) { - QString depsTemplate = - QString::fromUtf8(TEMPLATE_DEPENDENCIES_CMAKELISTS, -1).arg(COMPONENTS_DIR); - writeFile(dependenciesPath.pathAppended("CMakeLists.txt"), depsTemplate); - - const Utils::FilePath qmlComponentsFilePath = - cmakeFolderPath.pathAppended("qmlcomponents.cmake"); - - if (qmlComponentsFilePath.exists()) { - - const QString warningMsg = Tr::tr( - "The project structure has changed.\n" - "Please clean the build folder before rebuilding\n"); - - CMakeGenerator::logIssue( - ProjectExplorer::Task::Warning, warningMsg, componentsPath); - - auto removeResult = qmlComponentsFilePath.removeFile(); - if (!removeResult) { - QString removeMsg = Tr::tr("Failed to remove the qmlcomponents.cmake file.\n"); - removeMsg.append(removeResult.error()); - - CMakeGenerator::logIssue( - ProjectExplorer::Task::Warning, removeMsg, qmlComponentsFilePath); - } - } - } else { - CMakeGenerator::logIssue( - ProjectExplorer::Task::Error, cpyResult.error(), componentsSrc); - } - } - } + createDependencies(node->dir); const Utils::FilePath sharedFile = node->dir.pathAppended("CMakeLists.txt.shared"); if (!sharedFile.exists()) { @@ -179,12 +124,15 @@ void CMakeWriterV1::writeModuleCMakeFile(const NodePtr &node, const NodePtr &) c pluginNames.append("\n"); } + if (hasNewComponents()) + pluginNames.append(QString("\n\t") + "QtQuickDesignerComponents"); + QString linkLibrariesTemplate( - "target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE\n" - "%1)"); + "target_link_libraries(%1 PRIVATE\n" + "%2)"); userFileContent.append("\n"); - userFileContent.append(linkLibrariesTemplate.arg(pluginNames)); + userFileContent.append(linkLibrariesTemplate.arg(mainLibName(), pluginNames)); writeFile(userFile, userFileContent); return; } @@ -265,5 +213,78 @@ void CMakeWriterV1::writeSourceFiles(const NodePtr &node, const NodePtr &root) c writeFile(headerPath, headerTemplate.arg(environmentPrefix, environmentPostfix)); } +void CMakeWriterV1::createDependencies(const Utils::FilePath &rootDir) const +{ + const Utils::FilePath dependenciesPath = rootDir.pathAppended(DEPENDENCIES_DIR); + const Utils::FilePath componentsPath = dependenciesPath.pathAppended(COMPONENTS_DIR); + const Utils::FilePath componentsIgnoreFile = componentsPath.pathAppended(COMPONENTS_IGNORE_FILE); + + bool copyComponents = false; + // Note: If dependencies directory exists but not the components directory, we assunme + // the user has intentionally deleted it because he has the components installed in Qt. + if (!dependenciesPath.exists()) { + dependenciesPath.createDir(); + copyComponents = true; + } else if (componentsIgnoreFile.exists()) { + auto *bs = parent()->buildSystem(); + auto versionDS = normalizeVersion(versionFromString(bs->versionDesignStudio())); + auto versionIgnore = normalizeVersion(versionFromIgnoreFile(componentsIgnoreFile)); + if (versionDS > versionIgnore) { + copyComponents = true; + if (componentsPath.exists()) + componentsPath.removeRecursively(); + } + } + + if (copyComponents) { + if (!componentsPath.exists()) + componentsPath.createDir(); + + Utils::FilePath componentsSrc = + Core::ICore::resourcePath("qmldesigner/Dependencies/qtquickdesigner-components"); + + const Utils::FilePath unifiedPath = + Core::ICore::resourcePath("qmldesigner/Dependencies/qtquickdesigner-components/components"); + + if (unifiedPath.exists( )) + componentsSrc = unifiedPath; + + if (componentsSrc.exists()) { + auto cpyResult = componentsSrc.copyRecursively(componentsPath); + if (cpyResult) { + QString depsTemplate = + QString::fromUtf8(TEMPLATE_DEPENDENCIES_CMAKELISTS, -1).arg(COMPONENTS_DIR); + writeFile(dependenciesPath.pathAppended("CMakeLists.txt"), depsTemplate); + + const Utils::FilePath cmakeFolderPath = rootDir.pathAppended("cmake"); + const Utils::FilePath qmlComponentsFilePath = + cmakeFolderPath.pathAppended("qmlcomponents.cmake"); + + if (qmlComponentsFilePath.exists()) { + + const QString warningMsg = Tr::tr( + "The project structure has changed.\n" + "Please clean the build folder before rebuilding\n"); + + CMakeGenerator::logIssue( + ProjectExplorer::Task::Warning, warningMsg, componentsPath); + + auto removeResult = qmlComponentsFilePath.removeFile(); + if (!removeResult) { + QString removeMsg = Tr::tr("Failed to remove the qmlcomponents.cmake file.\n"); + removeMsg.append(removeResult.error()); + + CMakeGenerator::logIssue( + ProjectExplorer::Task::Warning, removeMsg, qmlComponentsFilePath); + } + } + } else { + CMakeGenerator::logIssue( + ProjectExplorer::Task::Error, cpyResult.error(), componentsSrc); + } + } + } +} + } // namespace QmlProjectExporter } // namespace QmlProjectManager diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.h index ed51eb070e6..4b6a515cea9 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.h +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/cmakewriterv1.h @@ -8,17 +8,23 @@ namespace QmlProjectManager { namespace QmlProjectExporter { -class CMakeWriterV1 final : public CMakeWriter +class CMakeWriterV1 : public CMakeWriter { public: CMakeWriterV1(CMakeGenerator *parent); + virtual QString mainLibName() const; + QString sourceDirName() const override; void transformNode(NodePtr &node) const override; + int identifier() const override; void writeRootCMakeFile(const NodePtr &node) const override; void writeModuleCMakeFile(const NodePtr &node, const NodePtr &root) const override; void writeSourceFiles(const NodePtr &node, const NodePtr &root) const override; + +protected: + void createDependencies(const Utils::FilePath &rootDir) const; }; } // namespace QmlProjectExporter diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/exporter.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/exporter.cpp index 40de901c4fe..0763f2a442c 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/exporter.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/exporter.cpp @@ -36,9 +36,6 @@ void Exporter::updateProjectItem(QmlProjectItem *item, bool updateEnabled) if (updateEnabled) { m_cmakeGen->setEnabled(item->enableCMakeGeneration()); m_pythonGen->setEnabled(item->enablePythonGeneration()); - - m_cmakeGen->setStandaloneApp(item->standaloneApp()); - m_pythonGen->setStandaloneApp(item->standaloneApp()); } } diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.cpp b/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.cpp index 39cfbad5876..0de60d37ea3 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.cpp +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.cpp @@ -8,6 +8,7 @@ #include "../qmlprojectmanagertr.h" #include +#include #include #include @@ -68,6 +69,17 @@ bool FileGenerator::isEnabled() const return m_enabled; } +bool FileGenerator::isActive() const +{ + if (!m_buildSystem) + return false; + + if (auto *configuration = m_buildSystem->buildConfiguration()) + return configuration->isActive(); + + return false; +} + void FileGenerator::setEnabled(bool enabled) { m_enabled = enabled; @@ -75,12 +87,15 @@ void FileGenerator::setEnabled(bool enabled) bool FileGenerator::standaloneApp() const { - return m_standaloneApp; + if (m_buildSystem) + return m_buildSystem->standaloneApp(); + return false; } void FileGenerator::setStandaloneApp(bool value) { - m_standaloneApp = value; + if (m_buildSystem) + m_buildSystem->setStandaloneApp(value); } void FileGenerator::updateMenuAction(const Utils::Id &id, std::function isEnabled) diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.h b/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.h index a617d4448cf..7914aee527e 100644 --- a/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.h +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/filegenerator.h @@ -32,6 +32,7 @@ public: const QmlBuildSystem *buildSystem() const; bool isEnabled() const; + bool isActive() const; void setEnabled(bool enabled); bool standaloneApp() const; @@ -42,7 +43,6 @@ protected: private: bool m_enabled = false; - bool m_standaloneApp = false; QmlBuildSystem *m_buildSystem = nullptr; }; diff --git a/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/cmakeroot_lib.tpl b/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/cmakeroot_lib.tpl new file mode 100644 index 00000000000..b98746e425e --- /dev/null +++ b/src/plugins/qmlprojectmanager/qmlprojectexporter/templates/cmakeroot_lib.tpl @@ -0,0 +1,28 @@ + +cmake_minimum_required(VERSION 3.21.1) + +option(LINK_INSIGHT "Link Qt Insight Tracker library" ON) +option(BUILD_QDS_COMPONENTS "Build design studio components" ON) + +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +set(CMAKE_AUTOMOC ON) +set(CMAKE_INCLUDE_CURRENT_DIR ON) +set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml) +set(QML_IMPORT_PATH ${QT_QML_OUTPUT_DIRECTORY} + CACHE STRING "Import paths for Qt Creator's code model" + FORCE +) + +qt_add_library(%1) +qt_add_resources(%1 "configuration" + PREFIX "/" + FILES +%2) + +include(qds) + +if (LINK_INSIGHT) + include(insight OPTIONAL) +endif () + diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp index cb909f8c784..4b11a2b50d7 100644 --- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp +++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp @@ -701,6 +701,8 @@ void StudioWelcomePlugin::extensionsInitialized() bool StudioWelcomePlugin::delayedInitialize() { QTimer::singleShot(2000, this, []() { + if (!ProjectExplorer::KitManager::isLoaded()) + return; auto modelManager = QmlJS::ModelManagerInterface::instance(); if (!modelManager) return; diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 7a91cb6d55c..01597e8f7e4 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -882,6 +882,7 @@ public: void updateRedoAction(); void updateUndoAction(); void updateCopyAction(bool on); + void updatePasteAction(); public: TextEditorWidget *q; @@ -1079,6 +1080,7 @@ public: QAction *m_copyAction = nullptr; QAction *m_copyHtmlAction = nullptr; QAction *m_cutAction = nullptr; + QAction *m_pasteAction = nullptr; QAction *m_autoIndentAction = nullptr; QAction *m_autoFormatAction = nullptr; QAction *m_visualizeWhitespaceAction = nullptr; @@ -1279,6 +1281,8 @@ TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent) connect(q, &PlainTextEdit::copyAvailable, this, &TextEditorWidgetPrivate::updateCopyAction); + connect(qApp->clipboard(), &QClipboard::changed, this, &TextEditorWidgetPrivate::updatePasteAction); + m_parenthesesMatchingTimer.setSingleShot(true); m_parenthesesMatchingTimer.setInterval(50); connect(&m_parenthesesMatchingTimer, &QTimer::timeout, @@ -4263,11 +4267,13 @@ void TextEditorWidgetPrivate::registerActions() .addOnTriggered([this] { q->cut(); }) .setScriptable(true) .contextAction(); - m_modifyingActions << ActionBuilder(this, PASTE) - .setContext(m_editorContext) - .addOnTriggered([this] { q->paste(); }) - .setScriptable(true) - .contextAction(); + m_pasteAction = ActionBuilder(this, PASTE) + .setContext(m_editorContext) + .addOnTriggered([this] { q->paste(); }) + .setScriptable(true) + .contextAction(); + m_modifyingActions << m_pasteAction; + ActionBuilder(this, SELECTALL) .setContext(m_editorContext) .setScriptable(true) @@ -4716,7 +4722,7 @@ void TextEditorWidgetPrivate::updateActions() updateRedoAction(); updateUndoAction(); updateCopyAction(q->textCursor().hasSelection()); - + updatePasteAction(); updateOptionalActions(); } @@ -4761,6 +4767,12 @@ void TextEditorWidgetPrivate::updateCopyAction(bool hasCopyableText) m_copyHtmlAction->setEnabled(hasCopyableText); } +void TextEditorWidgetPrivate::updatePasteAction() +{ + if (m_pasteAction) + m_pasteAction->setEnabled(!q->isReadOnly() && !qApp->clipboard()->text(QClipboard::Mode::Clipboard).isEmpty()); +} + bool TextEditorWidget::codeFoldingVisible() const { return d->m_codeFoldingVisible; diff --git a/src/tools/qmlpuppet/mockfiles/qt6/EditCameraController.qml b/src/tools/qmlpuppet/mockfiles/qt6/EditCameraController.qml index 27f1f717034..6ef65c9718c 100644 --- a/src/tools/qmlpuppet/mockfiles/qt6/EditCameraController.qml +++ b/src/tools/qmlpuppet/mockfiles/qt6/EditCameraController.qml @@ -8,9 +8,9 @@ Item { id: cameraCtrl property var viewRoot: null - property int splitId: -1 + property int viewportId: -1 property Camera camera: view3d ? view3d.camera : null - property View3D view3d: viewRoot.editViews[splitId] + property View3D view3d: viewRoot.editViews[viewportId] property string sceneId: viewRoot.sceneId property vector3d _lookAtPoint property vector3d _pressPoint @@ -55,11 +55,11 @@ Item { _lookAtPoint = Qt.vector3d(0, 0, 0); _zoomFactor = 1; - if (splitId === 1) { + if (viewportId === 1) { jumpToRotation(originGizmo.quaternionForAxis(OriginGizmo.PositiveZ)); - } else if (splitId === 2) { + } else if (viewportId === 2) { jumpToRotation(originGizmo.quaternionForAxis(OriginGizmo.NegativeY)); - } else if (splitId === 3) { + } else if (viewportId === 3) { jumpToRotation(originGizmo.quaternionForAxis(OriginGizmo.NegativeX)); } else { camera.position = _defaultCameraPosition; @@ -79,7 +79,7 @@ Item { cameraState[1] = _zoomFactor; cameraState[2] = camera.position; cameraState[3] = camera.rotation; - _generalHelper.storeToolState(sceneId, "editCamState" + splitId, cameraState, delay); + _generalHelper.storeToolState(sceneId, "editCamState" + viewportId, cameraState, delay); } function focusObject(targetNodes, rotation, updateZoom, closeUp) @@ -254,12 +254,12 @@ Item { } on_LookAtPointChanged: { - viewRoot.overlayViews[splitId].lookAtGizmo.position = _lookAtPoint; + viewRoot.overlayViews[viewportId].lookAtGizmo.position = _lookAtPoint; } Connections { target: _generalHelper - enabled: viewRoot.activeSplit === cameraCtrl.splitId + enabled: viewRoot.activeViewport === cameraCtrl.viewportId function onRequestCameraMove(camera, moveVec) { if (camera === cameraCtrl.camera) { @@ -272,7 +272,7 @@ Item { Image { anchors.centerIn: parent source: "qrc:///qtquickplugin/mockfiles/images/crosshair.png" - visible: cameraCtrl.showCrosshairs && viewRoot.activeSplit === cameraCtrl.splitId + visible: cameraCtrl.showCrosshairs && viewRoot.activeViewport === cameraCtrl.viewportId opacity: 0.7 } @@ -303,7 +303,7 @@ Item { onPressed: (mouse) => { if (cameraCtrl.flyMode) return; - viewRoot.activeSplit = cameraCtrl.splitId + viewRoot.activeViewport = cameraCtrl.viewportId if (cameraCtrl.camera && (mouse.modifiers & (Qt.AltModifier | Qt.ShiftModifier))) { cameraCtrl._dragging = true; cameraCtrl._startRotation = cameraCtrl.camera.eulerRotation; @@ -328,9 +328,9 @@ Item { onCanceled: handleRelease() onWheel: (wheel) => { - if (cameraCtrl.flyMode && cameraCtrl.splitId !== viewRoot.activeSplit) + if (cameraCtrl.flyMode && cameraCtrl.viewportId !== viewRoot.activeViewport) return; - viewRoot.activeSplit = cameraCtrl.splitId; + viewRoot.activeViewport = cameraCtrl.viewportId; if (cameraCtrl.camera) { // Empirically determined divisor for nice zoom cameraCtrl.zoomRelative(wheel.angleDelta.y / -40); @@ -373,7 +373,7 @@ Item { targetNode: cameraCtrl.camera onAxisClicked: (axis) => { - viewRoot.activeSplit = cameraCtrl.splitId + viewRoot.activeViewport = cameraCtrl.viewportId cameraCtrl.jumpToRotation(quaternionForAxis(axis)); } } diff --git a/src/tools/qmlpuppet/mockfiles/qt6/EditView3D.qml b/src/tools/qmlpuppet/mockfiles/qt6/EditView3D.qml index f3a60c53020..2d4edbe033c 100644 --- a/src/tools/qmlpuppet/mockfiles/qt6/EditView3D.qml +++ b/src/tools/qmlpuppet/mockfiles/qt6/EditView3D.qml @@ -12,7 +12,7 @@ Item { visible: true property Node activeScene: null - property int activeSplit: 0 + property int activeViewport: 0 property var editViews: [null, null, null, null] property var usePerspective: [true, false, false, false] property var overlayViews: [overlayView0, overlayView1, overlayView2, overlayView3] @@ -21,8 +21,8 @@ Item { property var materialOverrides: [DebugSettings.None, DebugSettings.None, DebugSettings.None, DebugSettings.None] property var showWireframes: [false, false, false, false] - property var activeEditView: editViews[activeSplit] - property var activeOverlayView: overlayViews[activeSplit] + property var activeEditView: editViews[activeViewport] + property var activeOverlayView: overlayViews[activeViewport] property string sceneId property bool showEditLight: false @@ -37,12 +37,56 @@ Item { property color backgroundGradientColorStart: "#222222" property color backgroundGradientColorEnd: "#999999" property color gridColor: "#cccccc" + property color viewportBorderColor: "#aaaaaaaa" property bool syncEnvBackground: true - property bool splitView: false + property string activePreset: "Single" property bool flyMode: false property bool showCameraSpeed: false property string cameraViewMode + // The presets used to customize the display of the viewports + property var viewportPresets: { + "Single": { + numViewports: 1, + viewRects: [ + { x: 0.0, y: 0.0, width: 1.0, height: 1.0 } + ] + }, + "Quad": { + numViewports: 4, + viewRects: [ + { x: 0.0, y: 0.0, width: 0.5, height: 0.5 }, + { x: 0.5, y: 0.0, width: 0.5, height: 0.5 }, + { x: 0.0, y: 0.5, width: 0.5, height: 0.5 }, + { x: 0.5, y: 0.5, width: 0.5, height: 0.5 } + ] + }, + "3Left1Right": { + numViewports: 4, + viewRects: [ + { x: 0.0, y: 0.0, width: 0.25, height: 0.33 }, + { x: 0.0, y: 0.33, width: 0.25, height: 0.34 }, + { x: 0.0, y: 0.67, width: 0.25, height: 0.33 }, + { x: 0.25, y: 0.0, width: 0.75, height: 1.0 } + ] + }, + "2Horizontal": { + numViewports: 2, + viewRects: [ + { x: 0.0, y: 0.0, width: 1.0, height: 0.5 }, + { x: 0.0, y: 0.5, width: 1.0, height: 0.5 } + ] + }, + "2Vertical": { + numViewports: 2, + viewRects: [ + { x: 0.0, y: 0.0, width: 0.5, height: 1.0 }, + { x: 0.5, y: 0.0, width: 0.5, height: 1.0 } + ] + } + //TODO: reset of presets + }; + enum SelectionMode { Item, Group } enum TransformMode { Move, Rotate, Scale } @@ -64,7 +108,7 @@ Item { signal commitObjectProperty(var objects, var propNames) signal changeObjectProperty(var objects, var propNames) signal notifyActiveSceneChange() - signal notifyActiveSplitChange(int index) + signal notifyActiveViewportChange(int index) onUsePerspectiveChanged: _generalHelper.storeToolState(sceneId, "usePerspective", usePerspective) onShowEditLightChanged: _generalHelper.storeToolState(sceneId, "showEditLight", showEditLight) @@ -81,14 +125,14 @@ Item { onTransformModeChanged: _generalHelper.storeToolState(sceneId, "transformMode", transformMode); onMaterialOverridesChanged: _generalHelper.storeToolState(sceneId, "matOverride", materialOverrides); onShowWireframesChanged: _generalHelper.storeToolState(sceneId, "showWireframe", showWireframes); - onSplitViewChanged: { - _generalHelper.storeToolState(sceneId, "splitView", splitView); + onActivePresetChanged: { + _generalHelper.storeToolState(sceneId, "activePreset", activePreset); _generalHelper.requestOverlayUpdate(); } - onActiveSplitChanged: { - _generalHelper.storeToolState(sceneId, "activeSplit", activeSplit); - cameraControls[activeSplit].forceActiveFocus(); - notifyActiveSplitChange(activeSplit); + onActiveViewportChanged: { + _generalHelper.storeToolState(sceneId, "activeViewport", activeViewport); + cameraControls[activeViewport].forceActiveFocus(); + notifyActiveViewportChange(activeViewport); } onActiveSceneChanged: updateActiveScene() @@ -141,7 +185,7 @@ Item { selectionBoxCount = 0; editViewsChanged(); - cameraControls[activeSplit].forceActiveFocus(); + cameraControls[activeViewport].forceActiveFocus(); return true; } return false; @@ -234,7 +278,7 @@ Item { } else if (selectedNodes.length > 0 && selectionBoxCount > 0) { boxModels.push(activeEditView.selectionBoxes[0].model); } - cameraControls[activeSplit].focusObject( + cameraControls[activeViewport].focusObject( boxModels, activeEditView.camera.eulerRotation, true, false); } } @@ -242,7 +286,7 @@ Item { function alignCamerasToView(cameraNodes) { if (activeEditView) { - cameraControls[activeSplit].alignCameras(cameraNodes); + cameraControls[activeViewport].alignCameras(cameraNodes); var propertyNames = ["position", "eulerRotation"]; viewRoot.changeObjectProperty(cameraNodes, propertyNames); viewRoot.commitObjectProperty(cameraNodes, propertyNames); @@ -252,7 +296,7 @@ Item { function alignViewToCamera(cameraNodes) { if (activeEditView) - cameraControls[activeSplit].alignView(cameraNodes); + cameraControls[activeViewport].alignView(cameraNodes); } function updateBackgroundColors(colors) @@ -388,15 +432,16 @@ Item { viewRoot.showCameraSpeed = false; } - if ("splitView" in toolStates) - splitView = toolStates.splitView; + if ("activePreset" in toolStates) + activePreset = toolStates.activePreset; else if (resetToDefault) - splitView = false; + activePreset = "Quad"; + applyViewportPreset(activePreset) - if ("activeSplit" in toolStates) - activeSplit = toolStates.activeSplit; + if ("activeViewport" in toolStates) + activeViewport = toolStates.activeViewport; else if (resetToDefault) - activeSplit = 0; + activeViewport = 0; if ("showWireframe" in toolStates) showWireframes = toolStates.showWireframe; @@ -424,8 +469,8 @@ Item { _generalHelper.storeToolState(sceneId, "globalOrientation", globalOrientation) _generalHelper.storeToolState(sceneId, "selectionMode", selectionMode); _generalHelper.storeToolState(sceneId, "transformMode", transformMode); - _generalHelper.storeToolState(sceneId, "splitView", splitView) - _generalHelper.storeToolState(sceneId, "activeSplit", activeSplit) + _generalHelper.storeToolState(sceneId, "activePreset", activePreset) + _generalHelper.storeToolState(sceneId, "activeViewport", activeViewport) _generalHelper.storeToolState(sceneId, "showWireframe", showWireframes) _generalHelper.storeToolState(sceneId, "matOverride", materialOverrides) @@ -527,6 +572,7 @@ Item { selectionChanged(newSelection); } + //TODO: only update the active viewport views function addLightGizmo(scene, obj) { for (var i = 0; i < 4; ++i) @@ -617,64 +663,95 @@ Item { overlayViews[i].updateReflectionProbeGizmoScene(scene, obj); } - function resolveSplitPoint(x, y) + function resolveViewportPoint(x, y) { - if (!splitView || activeSplit === 0) + let rect = viewRects[activeViewport]; + // Check invisible or out or range, then fallback to original origin + if (!rect || !rect.visible) return Qt.point(x, y); - if (activeSplit === 1) - return Qt.point(x - viewContainer.width / 2, y); - else if (activeSplit === 2) - return Qt.point(x, y - viewContainer.height / 2); - else - return Qt.point(x - viewContainer.width / 2, y - viewContainer.height / 2); + // Transform topleft of the active viewport to be the origin + return Qt.point(x - rect.x, y - rect.y); } - function updateActiveSplit(x, y) + function updateActiveViewport(x, y) { - if (splitView) { - if (x <= viewContainer.width / 2) { - if (y <= viewContainer.height / 2) - activeSplit = 0; - else - activeSplit = 2; - } else { - if (y <= viewContainer.height / 2) - activeSplit = 1; - else - activeSplit = 3; + for (let i = 0; i < 4; ++i) { + let rect = viewRects[i]; + if (!rect.visible) + continue; + + if (x >= rect.x && x <= rect.x + rect.width + && y >= rect.y && y <= rect.y + rect.height) { + activeViewport = i; + return; } } + + // TODO: if click outside all visible viewRects, do nothing + // or reset to e.g. activeVireport = -1 or 0 } function gizmoAt(x, y) { - updateActiveSplit(x, y); - let splitPoint = resolveSplitPoint(x, y); + updateActiveViewport(x, y); + let viewportPoint = resolveViewportPoint(x, y); - return activeOverlayView.gizmoAt(splitPoint.x, splitPoint.y); + return activeOverlayView.gizmoAt(viewportPoint.x, viewportPoint.y); } function rotateEditCamera(angles) { - cameraControls[activeSplit].rotateCamera(angles); + cameraControls[activeViewport].rotateCamera(angles); } function moveEditCamera(amounts) { - cameraControls[activeSplit].moveCamera(amounts); + cameraControls[activeViewport].moveCamera(amounts); + } + + // Update viewports based on selected preset + function applyViewportPreset(presetName) + { + let preset = viewportPresets[presetName]; + if (!preset) + return; + + let count = preset.numViewports; + + for (let i = 0; i < 4; ++i) { + if (i < count) { + viewRects[i].visible = true; + viewRects[i].x = preset.viewRects[i].x * viewContainer.width; + viewRects[i].y = preset.viewRects[i].y * viewContainer.height; + viewRects[i].width = preset.viewRects[i].width * viewContainer.width; + viewRects[i].height = preset.viewRects[i].height * viewContainer.height; + } else { + viewRects[i].visible = false; + } + } + + //TODO: Do we need this here? + cameraView.updateSnapping(); } Component.onCompleted: { createEditViews(); selectObjects([]); + applyViewportPreset(activePreset) // Work-around the fact that the projection matrix for the camera is not calculated until // the first frame is rendered, so any initial calls to mapFrom3DScene() will fail. _generalHelper.requestOverlayUpdate(); } - onWidthChanged: _generalHelper.requestOverlayUpdate() - onHeightChanged: _generalHelper.requestOverlayUpdate() + onWidthChanged: { + applyViewportPreset(activePreset) + _generalHelper.requestOverlayUpdate() + } + onHeightChanged: { + applyViewportPreset(activePreset) + _generalHelper.requestOverlayUpdate() + } Connections { target: _generalHelper @@ -715,9 +792,9 @@ Item { } // Shared nodes of the overlay, set as importScene on all overlay views. - // Content here can be used as is on all splits. - // Nodes that utilize autoscaling or otherwise need to have different appearance on each split - // need to have separate copy on each split. + // Content here can be used as is on all viewports. + // Nodes that utilize autoscaling or otherwise need to have different appearance on each viewport + // need to have separate copy on each viewport. Node { id: overlayScene @@ -743,12 +820,9 @@ Item { Rectangle { id: viewRect0 - width: viewRoot.splitView ? parent.width / 2 : parent.width - height: viewRoot.splitView ? parent.height / 2 : parent.height - x: 0 - y: 0 - visible: viewRoot.splitView || viewRoot.activeSplit == 0 gradient: bgGradient + border.width: 1 + border.color: viewportBorderColor OverlayView3D { id: overlayView0 editView: viewRoot.editViews[0] @@ -765,18 +839,15 @@ Item { EditCameraController { id: cameraControl0 viewRoot: viewRoot - splitId: 0 + viewportId: 0 } } Rectangle { id: viewRect1 - width: viewRoot.splitView ? parent.width / 2 : parent.width - height: viewRoot.splitView ? parent.height / 2 : parent.height - x: viewRoot.splitView ? parent.width / 2 : 0 - y: 0 - visible: viewRoot.splitView || viewRoot.activeSplit == 1 gradient: bgGradient + border.width: 1 + border.color: viewportBorderColor OverlayView3D { id: overlayView1 editView: viewRoot.editViews[1] @@ -793,18 +864,15 @@ Item { EditCameraController { id: cameraControl1 viewRoot: viewRoot - splitId: 1 + viewportId: 1 } } Rectangle { id: viewRect2 - width: viewRoot.splitView ? parent.width / 2 : parent.width - height: viewRoot.splitView ? parent.height / 2 : parent.height - x: 0 - y: viewRoot.splitView ? parent.height / 2 : 0 - visible: viewRoot.splitView || viewRoot.activeSplit == 2 gradient: bgGradient + border.width: 1 + border.color: viewportBorderColor OverlayView3D { id: overlayView2 editView: viewRoot.editViews[2] @@ -821,18 +889,15 @@ Item { EditCameraController { id: cameraControl2 viewRoot: viewRoot - splitId: 2 + viewportId: 2 } } Rectangle { id: viewRect3 - width: viewRoot.splitView ? parent.width / 2 : parent.width - height: viewRoot.splitView ? parent.height / 2 : parent.height - x: viewRoot.splitView ? parent.width / 2 : 0 - y: viewRoot.splitView ? parent.height / 2 : 0 - visible: viewRoot.splitView || viewRoot.activeSplit == 3 gradient: bgGradient + border.width: 1 + border.color: viewportBorderColor OverlayView3D { id: overlayView3 editView: viewRoot.editViews[3] @@ -849,44 +914,21 @@ Item { EditCameraController { id: cameraControl3 viewRoot: viewRoot - splitId: 3 + viewportId: 3 } } + // Active viewport highlight Rectangle { - // Vertical border between splits - visible: viewRoot.splitView - x: parent.width / 2 - y: 0 - width: 1 - height: parent.height - border.width: 1 - border.color: "#aaaaaa" - } - - Rectangle { - // Horizontal border between splits - visible: viewRoot.splitView - x: 0 - y: parent.height / 2 - height: 1 - width: parent.width - border.width: 1 - border.color: "#aaaaaa" - } - - Rectangle { - // Active split highlight - visible: viewRoot.splitView - x: viewRects[viewRoot.activeSplit].x - y: viewRects[viewRoot.activeSplit].y - height: viewRects[viewRoot.activeSplit].height - + (viewRoot.activeSplit === 0 || viewRoot.activeSplit === 1 ? 1 : 0) - width: viewRects[viewRoot.activeSplit].width - + (viewRoot.activeSplit === 0 || viewRoot.activeSplit === 2 ? 1 : 0) + visible: activePreset !== "Single" && viewRects[viewRoot.activeViewport].visible + x: viewRects[viewRoot.activeViewport].x + y: viewRects[viewRoot.activeViewport].y + width: viewRects[viewRoot.activeViewport].width + height: viewRects[viewRoot.activeViewport].height border.width: 2 border.color: "#57B9FC" color: "transparent" + z: 1000 // Edge case to make sure selection rect drawn over everything } MouseArea { @@ -903,20 +945,20 @@ Item { if (viewRoot.flyMode) return; - viewRoot.updateActiveSplit(mouse.x, mouse.y); + viewRoot.updateActiveViewport(mouse.x, mouse.y); - let splitPoint = viewRoot.resolveSplitPoint(mouse.x, mouse.y); + let viewportPoint = viewRoot.resolveViewportPoint(mouse.x, mouse.y); if (viewRoot.activeEditView) { // First pick overlay to check for hits there var pickResult = _generalHelper.pickViewAt(activeOverlayView, - splitPoint.x, splitPoint.y); + viewportPoint.x, viewportPoint.y); var resolvedResult = _generalHelper.resolvePick(pickResult.objectHit); if (!resolvedResult) { // No hits from overlay view, pick the main scene pickResult = _generalHelper.pickViewAt(viewRoot.activeEditView, - splitPoint.x, splitPoint.y); + viewportPoint.x, viewportPoint.y); resolvedResult = _generalHelper.resolvePick(pickResult.objectHit); } @@ -940,17 +982,17 @@ Item { } onPositionChanged: (mouse) => { if (freeDraggerArea) { - let splitPoint = viewRoot.resolveSplitPoint(mouse.x, mouse.y); - let splitPress = viewRoot.resolveSplitPoint(pressPoint.x, pressPoint.y); - if (initialMoveBlock && Math.abs(splitPress.x - splitPoint.x) - + Math.abs(splitPress.y - splitPoint.y) > 10) { + let viewportPoint = viewRoot.resolveViewportPoint(mouse.x, mouse.y); + let viewportPress = viewRoot.resolveViewportPoint(pressPoint.x, pressPoint.y); + if (initialMoveBlock && Math.abs(viewportPress.x - viewportPoint.x) + + Math.abs(viewportPress.y - viewportPoint.y) > 10) { // Don't force press event at actual press, as that puts the gizmo // in free-dragging state, which is bad UX if drag is not actually done - freeDraggerArea.forcePressEvent(splitPress.x, splitPress.y); - freeDraggerArea.forceMoveEvent(splitPoint.x, splitPoint.y); + freeDraggerArea.forcePressEvent(viewportPress.x, viewportPress.y); + freeDraggerArea.forceMoveEvent(viewportPoint.x, viewportPoint.y); initialMoveBlock = false; } else { - freeDraggerArea.forceMoveEvent(splitPoint.x, splitPoint.y); + freeDraggerArea.forceMoveEvent(viewportPoint.x, viewportPoint.y); } } } @@ -959,11 +1001,11 @@ Item { { if (freeDraggerArea) { if (initialMoveBlock) { - let splitPress = viewRoot.resolveSplitPoint(pressPoint.x, pressPoint.y); - freeDraggerArea.forceReleaseEvent(splitPress.x, splitPress.y); + let viewportPress = viewRoot.resolveViewportPoint(pressPoint.x, pressPoint.y); + freeDraggerArea.forceReleaseEvent(viewportPress.x, viewportPress.y); } else { - let splitPoint = viewRoot.resolveSplitPoint(mouse.x, mouse.y); - freeDraggerArea.forceReleaseEvent(splitPoint.x, splitPoint.y); + let viewportPoint = viewRoot.resolveViewportPoint(mouse.x, mouse.y); + freeDraggerArea.forceReleaseEvent(viewportPoint.x, viewportPoint.y); } freeDraggerArea = null; } @@ -1107,19 +1149,17 @@ Item { viewPortSize: Qt.size(viewRoot.viewPortRect.width, viewRoot.viewPortRect.height) function updateSnapping() { - if (!viewRoot.splitView) - cameraView.snapLeft = true - else if (viewRoot.activeSplit === 2) - cameraView.snapLeft = false - else if (viewRoot.activeSplit === 3) - cameraView.snapLeft = true + const rect = viewRoot.viewRects[viewRoot.activeViewport]; + if (!rect || !rect.visible) + return; + + const centerX = rect.x + rect.width / 2; + cameraView.snapLeft = centerX < viewContainer.width / 2; } Connections { target: viewRoot - - onSplitViewChanged: cameraView.updateSnapping() - onActiveSplitChanged: cameraView.updateSnapping() + onActiveViewportChanged: cameraView.updateSnapping() } } } diff --git a/src/tools/qmlpuppet/mockfiles/qt6/OverlayView3D.qml b/src/tools/qmlpuppet/mockfiles/qt6/OverlayView3D.qml index 7d7f419e429..59dd33d6f3a 100644 --- a/src/tools/qmlpuppet/mockfiles/qt6/OverlayView3D.qml +++ b/src/tools/qmlpuppet/mockfiles/qt6/OverlayView3D.qml @@ -16,7 +16,7 @@ View3D { property var viewRoot: null property View3D editView: null - property bool isActive: viewRoot.overlayViews[viewRoot.activeSplit] === overlayView + property bool isActive: viewRoot.overlayViews[viewRoot.activeViewport] === overlayView property var lightIconGizmos: [] property var cameraGizmos: [] @@ -629,7 +629,7 @@ View3D { scale: lookAtAutoScale.getScale(Qt.vector3d(10, 10, 10)) visible: overlayView.viewRoot.showLookAt && overlayView.isActive - && !overlayView.viewRoot.cameraControls[viewRoot.activeSplit].showCrosshairs + && !overlayView.viewRoot.cameraControls[viewRoot.activeViewport].showCrosshairs } } } diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserver.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserver.cpp index 9d8e6e65f8e..eb8d2083e2e 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserver.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserver.cpp @@ -182,7 +182,7 @@ NodeInstanceServer::~NodeInstanceServer() m_objectInstanceHash.clear(); } -QList NodeInstanceServer::createInstances(const QVector &containerVector) +QList NodeInstanceServer::createInstances(const QList &containerVector) { Q_ASSERT(declarativeView() || quickWindow()); QList instanceList; @@ -349,7 +349,7 @@ void NodeInstanceServer::removeInstances(const RemoveInstancesCommand &command) if (activeStateInstance().isValid()) activeStateInstance().deactivateState(); - const QVector instanceIds = command.instanceIds(); + const QList instanceIds = command.instanceIds(); for (qint32 instanceId : instanceIds) removeInstanceRelationsip(instanceId); @@ -363,7 +363,7 @@ void NodeInstanceServer::removeInstances(const RemoveInstancesCommand &command) void NodeInstanceServer::removeProperties(const RemovePropertiesCommand &command) { bool hasDynamicProperties = false; - const QVector props = command.properties(); + const QList props = command.properties(); for (const PropertyAbstractContainer &container : props) { hasDynamicProperties |= container.isDynamic(); resetInstanceProperty(container); @@ -375,7 +375,7 @@ void NodeInstanceServer::removeProperties(const RemovePropertiesCommand &command startRenderTimer(); } -void NodeInstanceServer::reparentInstances(const QVector &containerVector) +void NodeInstanceServer::reparentInstances(const QList &containerVector) { for (const ReparentContainer &container : containerVector) { if (hasInstanceForId(container.instanceId())) { @@ -418,7 +418,7 @@ void NodeInstanceServer::completeComponent(const CompleteComponentCommand &comma { QList instanceList; - const QVector instanceIds = command.instances(); + const QList instanceIds = command.instances(); for (qint32 instanceId : instanceIds) { if (hasInstanceForId(instanceId)) { ServerNodeInstance instance = instanceForId(instanceId); @@ -449,7 +449,7 @@ void NodeInstanceServer::removeSharedMemory(const RemoveSharedMemoryCommand &/*c { } -void NodeInstanceServer::setupImports(const QVector &containerVector) +void NodeInstanceServer::setupImports(const QList &containerVector) { Q_ASSERT(quickWindow()); QSet importStatementSet; @@ -622,7 +622,7 @@ void NodeInstanceServer::changeFileUrl(const ChangeFileUrlCommand &command) void NodeInstanceServer::changePropertyValues(const ChangeValuesCommand &command) { bool hasDynamicProperties = false; - const QVector valueChanges = command.valueChanges(); + const QList valueChanges = command.valueChanges(); for (const PropertyValueContainer &container : valueChanges) { hasDynamicProperties |= container.isDynamic(); setInstancePropertyVariant(container); @@ -636,7 +636,7 @@ void NodeInstanceServer::changePropertyValues(const ChangeValuesCommand &command void NodeInstanceServer::changeAuxiliaryValues(const ChangeAuxiliaryCommand &command) { - const QVector auxiliaryChanges = command.auxiliaryChanges; + const QList auxiliaryChanges = command.auxiliaryChanges; for (const PropertyValueContainer &container : auxiliaryChanges) setInstanceAuxiliaryData(container); @@ -646,7 +646,7 @@ void NodeInstanceServer::changeAuxiliaryValues(const ChangeAuxiliaryCommand &com void NodeInstanceServer::changePropertyBindings(const ChangeBindingsCommand &command) { bool hasDynamicProperties = false; - const QVector bindingChanges = command.bindingChanges; + const QList bindingChanges = command.bindingChanges; for (const PropertyBindingContainer &container : bindingChanges) { hasDynamicProperties |= container.isDynamic(); setInstancePropertyBinding(container); @@ -688,7 +688,7 @@ QQmlContext *NodeInstanceServer::rootContext() const return engine()->rootContext(); } -const QVector NodeInstanceServer::changedPropertyList() const +const QList NodeInstanceServer::changedPropertyList() const { return m_changedPropertyList; } @@ -724,7 +724,7 @@ static bool isTypeAvailable(const MockupTypeContainer &mockupType, QQmlEngine *e return !component.isError(); } -void NodeInstanceServer::setupMockupTypes(const QVector &container) +void NodeInstanceServer::setupMockupTypes(const QList &container) { for (const MockupTypeContainer &mockupType : container) { if (!isTypeAvailable(mockupType, engine())) { @@ -1082,9 +1082,9 @@ NodeInstanceClientInterface *NodeInstanceServer::nodeInstanceClient() const return m_nodeInstanceClient; } -static QVector createInformationVector(const QList &instanceList, bool initial) +static QList createInformationVector(const QList &instanceList, bool initial) { - QVector informationVector; + QList informationVector; for (const ServerNodeInstance &instance : instanceList) { if (instance.isValid()) { @@ -1166,7 +1166,7 @@ static QVector createInformationVector(const QList &instanceList) const { - QVector instanceVector; + QList instanceVector; for (const ServerNodeInstance &instance : instanceList) instanceVector.append(instance.instanceId()); @@ -1190,7 +1190,7 @@ static bool supportedVariantType(int type) ValuesChangedCommand NodeInstanceServer::createValuesChangedCommand(const QList &instanceList) const { - QVector valueVector; + QList valueVector; for (const ServerNodeInstance &instance : instanceList) { const QList propertyNames = instance.propertyNames(); @@ -1208,7 +1208,7 @@ ValuesChangedCommand NodeInstanceServer::createValuesChangedCommand(const QList< ComponentCompletedCommand NodeInstanceServer::createComponentCompletedCommand(const QList &instanceList) { - QVector idVector; + QList idVector; for (const ServerNodeInstance &instance : instanceList) { if (instance.instanceId() >= 0) idVector.append(instance.instanceId()); @@ -1219,7 +1219,7 @@ ComponentCompletedCommand NodeInstanceServer::createComponentCompletedCommand(co ChangeSelectionCommand NodeInstanceServer::createChangeSelectionCommand(const QList &instanceList) { - QVector idVector; + QList idVector; for (const ServerNodeInstance &instance : instanceList) { if (instance.instanceId() >= 0) idVector.append(instance.instanceId()); @@ -1228,9 +1228,9 @@ ChangeSelectionCommand NodeInstanceServer::createChangeSelectionCommand(const QL return ChangeSelectionCommand(idVector); } -ValuesChangedCommand NodeInstanceServer::createValuesChangedCommand(const QVector &propertyList) const +ValuesChangedCommand NodeInstanceServer::createValuesChangedCommand(const QList &propertyList) const { - QVector valueVector; + QList valueVector; for (const InstancePropertyPair &property : propertyList) { const PropertyName propertyName = property.second; @@ -1257,9 +1257,9 @@ ValuesChangedCommand NodeInstanceServer::createValuesChangedCommand(const QVecto } ValuesModifiedCommand NodeInstanceServer::createValuesModifiedCommand( - const QVector &propertyList) const + const QList &propertyList) const { - QVector valueVector; + QList valueVector; for (const InstancePropertyValueTriple &property : propertyList) { const PropertyName propertyName = property.propertyName; @@ -1322,7 +1322,7 @@ PixmapChangedCommand NodeInstanceServer::createPixmapChangedCommand(const QList< { NANOTRACE_SCOPE("Update", "createPixmapChangedCommand"); - QVector imageVector; + QList imageVector; for (const ServerNodeInstance &instance : instanceList) { if (!instance.isValid()) @@ -1440,13 +1440,13 @@ void NodeInstanceServer::loadDummyDataContext(const QString &directory) void NodeInstanceServer::sendDebugOutput(DebugOutputCommand::Type type, const QString &message, qint32 instanceId) { - QVector ids; + QList ids; ids.append(instanceId); sendDebugOutput(type, message, ids); } void NodeInstanceServer::sendDebugOutput(DebugOutputCommand::Type type, const QString &message, - const QVector &instanceIds) + const QList &instanceIds) { DebugOutputCommand command(message, type, instanceIds); nodeInstanceClient()->debugOutput(command); @@ -1532,7 +1532,7 @@ void NodeInstanceServer::sheduleRootItemRender() if (result) { connect(result.data(), &QQuickItemGrabResult::ready, [this, result, instanceId] { - QVector imageVector; + QList imageVector; ImageContainer container(instanceId, result->image(), instanceId); imageVector.append(container); nodeInstanceClient()->pixmapChanged(PixmapChangedCommand(imageVector)); @@ -1618,7 +1618,7 @@ void NodeInstanceServer::addAnimation(QQuickAbstractAnimation *animation) } } -QVector NodeInstanceServer::animations() const +QList NodeInstanceServer::animations() const { return m_animations; } diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserver.h b/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserver.h index e7070a63bde..ac081cd7379 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserver.h +++ b/src/tools/qmlpuppet/qmlpuppet/instances/nodeinstanceserver.h @@ -5,7 +5,6 @@ #include #include -#include #include #include #include @@ -153,7 +152,7 @@ public: ServerNodeInstance instanceForObject(QObject *object) const; bool hasInstanceForObject(QObject *object) const; - const QVector &nodeInstances() const { return m_idInstances; } + const QList &nodeInstances() const { return m_idInstances; } virtual QQmlEngine *engine() const = 0; QQmlContext *context() const; @@ -190,7 +189,7 @@ public: virtual void setRootItem(QQuickItem *item) = 0; void sendDebugOutput(DebugOutputCommand::Type type, const QString &message, qint32 instanceId = 0); - void sendDebugOutput(DebugOutputCommand::Type type, const QString &message, const QVector &instanceIds); + void sendDebugOutput(DebugOutputCommand::Type type, const QString &message, const QList &instanceIds); void removeInstanceRelationsipForDeletedObject(QObject *object, qint32 instanceId); @@ -213,7 +212,7 @@ public: virtual bool isInformationServer() const; virtual bool isPreviewServer() const; void addAnimation(QQuickAbstractAnimation *animation); - QVector animations() const; + QList animations() const; QVariant animationDefaultValue(int index) const; public slots: @@ -222,8 +221,8 @@ public slots: void emitParentChanged(QObject *child); protected: - virtual QList createInstances(const QVector &container); - void reparentInstances(const QVector &containerVector); + virtual QList createInstances(const QList &container); + void reparentInstances(const QList &containerVector); Internal::ChildrenChangeEventFilter *childrenChangeEventFilter(); void resetInstanceProperty(const PropertyAbstractContainer &propertyContainer); @@ -240,8 +239,8 @@ protected: void timerEvent(QTimerEvent *) override; ValuesChangedCommand createValuesChangedCommand(const QList &instanceList) const; - ValuesChangedCommand createValuesChangedCommand(const QVector &propertyList) const; - ValuesModifiedCommand createValuesModifiedCommand(const QVector &propertyList) const; + ValuesChangedCommand createValuesChangedCommand(const QList &propertyList) const; + ValuesModifiedCommand createValuesModifiedCommand(const QList &propertyList) const; PixmapChangedCommand createPixmapChangedCommand(const QList &instanceList) const; InformationChangedCommand createAllInformationChangedCommand(const QList &instanceList, bool initial = false) const; ChildrenChangedCommand createChildrenChangedCommand(const ServerNodeInstance &parentInstance, const QList &instanceList) const; @@ -276,16 +275,16 @@ protected: QQmlContext *rootContext() const; - const QVector changedPropertyList() const; + const QList changedPropertyList() const; void clearChangedPropertyList(); virtual void refreshBindings() = 0; void setupDummysForContext(QQmlContext *context); - void setupMockupTypes(const QVector &container); + void setupMockupTypes(const QList &container); void setupFileUrl(const QUrl &fileUrl); - void setupImports(const QVector &container); + void setupImports(const QList &container); void setupDummyData(const QUrl &fileUrl); void setupDefaultDummyData(); QList setupInstances(const CreateSceneCommand &command); @@ -301,7 +300,7 @@ private: void setupOnlyWorkingImports(const QStringList &workingImportStatementList); ServerNodeInstance m_rootNodeInstance; ServerNodeInstance m_activeStateInstance; - QVector m_idInstances; + QList m_idInstances; QHash m_objectInstanceHash; QMultiHash m_fileSystemWatcherHash; QList > > m_dummyObjectList; @@ -314,7 +313,7 @@ private: int m_renderTimerInterval = 16; TimerMode m_timerMode = TimerMode::NormalTimer; int m_timerModeInterval = 200; - QVector m_changedPropertyList; + QList m_changedPropertyList; QByteArray m_importCode; QPointer m_dummyContextObject; QPointer m_importComponent; @@ -322,8 +321,8 @@ private: std::unique_ptr multilanguageLink; int m_needsExtraRenderCount = 0; int m_extraRenderCurrentPass = 0; - QVector m_animations; - QVector m_defaultValues; + QList m_animations; + QList m_defaultValues; }; } diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/objectnodeinstance.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/objectnodeinstance.cpp index fb9f3cdd411..9dc8b7e6611 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/objectnodeinstance.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/objectnodeinstance.cpp @@ -346,7 +346,7 @@ void ObjectNodeInstance::addToNewProperty(QObject *object, QObject *newParent, c if (isList(property)) { QQmlListReference list = qvariant_cast(property.read()); - if (!QmlPrivateGate::hasFullImplementedListInterface(list)) { + if (!list.isValid() || !list.canAppend()) { qWarning() << "Property list interface not fully implemented for Class " << property.property().typeName() << " in property " << property.name() << "!"; return; } diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/qt5capturepreviewnodeinstanceserver.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/qt5capturepreviewnodeinstanceserver.cpp index 22e0d92084f..f9d530ddd54 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/qt5capturepreviewnodeinstanceserver.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/qt5capturepreviewnodeinstanceserver.cpp @@ -29,7 +29,7 @@ QImage renderPreviewImage(ServerNodeInstance rootNodeInstance) } CapturedDataCommand::StateData collectStateData(ServerNodeInstance rootNodeInstance, - const QVector &nodeInstances, + const QList &nodeInstances, qint32 stateInstanceId) { CapturedDataCommand::StateData stateData; @@ -74,7 +74,7 @@ void Qt5CapturePreviewNodeInstanceServer::collectItemChangesAndSendChangeCommand QQuickDesignerSupport::polishItems(quickWindow()); - QVector stateDatas; + QList stateDatas; stateDatas.push_back(collectStateData(rootNodeInstance(), nodeInstances(), 0)); for (ServerNodeInstance stateInstance : rootNodeInstance().stateInstances()) { diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/qt5informationnodeinstanceserver.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/qt5informationnodeinstanceserver.cpp index a85a8770dd9..99928dfe681 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/qt5informationnodeinstanceserver.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/qt5informationnodeinstanceserver.cpp @@ -327,7 +327,7 @@ void Qt5InformationNodeInstanceServer::updateActiveScenePreferredCamera() } void Qt5InformationNodeInstanceServer::updateMaterialPreviewData( - const QVector &valueChanges) + const QList &valueChanges) { for (const auto &container : valueChanges) { if (container.instanceId() == 0) { @@ -342,7 +342,7 @@ void Qt5InformationNodeInstanceServer::updateMaterialPreviewData( } void Qt5InformationNodeInstanceServer::updateRotationBlocks( - [[maybe_unused]] const QVector &valueChanges) + [[maybe_unused]] const QList &valueChanges) { #ifdef QUICK3D_MODULE auto helper = qobject_cast(m_3dHelper); @@ -372,7 +372,7 @@ void Qt5InformationNodeInstanceServer::updateRotationBlocks( } void Qt5InformationNodeInstanceServer::updateSnapAndCameraSettings( - [[maybe_unused]] const QVector &valueChanges) + [[maybe_unused]] const QList &valueChanges) { #ifdef QUICK3D_MODULE auto helper = qobject_cast(m_3dHelper); @@ -411,7 +411,7 @@ void Qt5InformationNodeInstanceServer::updateSnapAndCameraSettings( } void Qt5InformationNodeInstanceServer::updateColorSettings( - [[maybe_unused]] const QVector &valueChanges) + [[maybe_unused]] const QList &valueChanges) { #ifdef QUICK3D_MODULE if (m_editView3DData.rootItem) { @@ -430,7 +430,7 @@ void Qt5InformationNodeInstanceServer::updateColorSettings( } void Qt5InformationNodeInstanceServer::removeRotationBlocks( - [[maybe_unused]] const QVector &instanceIds) + [[maybe_unused]] const QList &instanceIds) { #ifdef QUICK3D_MODULE auto helper = qobject_cast(m_3dHelper); @@ -642,7 +642,7 @@ void Qt5InformationNodeInstanceServer::handleParticleSystemSelected(QQuick3DPart || ServerNodeInstance::isSubclassOf(o, "QQuickSequentialAnimation"); }; - const QVector anims = animations(); + const QList anims = animations(); QSet containers; for (auto a : anims) { // Stop all animations by default. We only want to run animations related to currently @@ -802,13 +802,13 @@ void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &ob m_selectionChangeTimer.start(500); } -QVector +QList Qt5InformationNodeInstanceServer::propertyToPropertyValueTriples( const ServerNodeInstance &instance, const PropertyName &propertyName, const QVariant &variant) { - QVector result; + QList result; InstancePropertyValueTriple propTriple; if (variant.typeId() == QMetaType::QVector3D) { @@ -854,7 +854,7 @@ void Qt5InformationNodeInstanceServer::modifyVariantValue(const QObjectList &obj } if (!objects.isEmpty()) { - QVector valueVector; + QList valueVector; for (const auto listObj : objects) { ServerNodeInstance instance = instanceForObject(listObj); if (instance.isValid()) { @@ -865,7 +865,7 @@ void Qt5InformationNodeInstanceServer::modifyVariantValue(const QObjectList &obj instance.setModifiedFlag(false); for (const auto &propNamePair : propNamePairs) { // We do have to split vector3d props into foobar.x, foobar.y, foobar.z - const QVector triple + const QList triple = propertyToPropertyValueTriples(instance, propNamePair.targetPropName, listObj->property(propNamePair.origPropName)); for (const auto &property : triple) { @@ -956,9 +956,9 @@ void Qt5InformationNodeInstanceServer::handleActiveSceneChange() #endif } -void Qt5InformationNodeInstanceServer::handleActiveSplitChange(int index) +void Qt5InformationNodeInstanceServer::handleActiveViewportChange(int index) { - nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::ActiveSplitChanged, + nodeInstanceClient()->handlePuppetToCreatorCommand({PuppetToCreatorCommand::ActiveViewportChanged, index}); } @@ -1631,13 +1631,13 @@ void Qt5InformationNodeInstanceServer::selectInstances(const QList &properties) + const QList &properties) { nodeInstanceClient()->valuesModified(createValuesModifiedCommand(properties)); } QList Qt5InformationNodeInstanceServer::createInstances( - const QVector &container) + const QList &container) { const auto createdInstances = NodeInstanceServer::createInstances(container); @@ -1966,8 +1966,8 @@ void Qt5InformationNodeInstanceServer::setup3DEditView( this, SLOT(handleObjectPropertyChange(QVariant, QVariant))); QObject::connect(m_editView3DData.rootItem, SIGNAL(notifyActiveSceneChange()), this, SLOT(handleActiveSceneChange())); - QObject::connect(m_editView3DData.rootItem, SIGNAL(notifyActiveSplitChange(int)), - this, SLOT(handleActiveSplitChange(int))); + QObject::connect(m_editView3DData.rootItem, SIGNAL(notifyActiveViewportChange(int)), + this, SLOT(handleActiveViewportChange(int))); QObject::connect(&m_propertyChangeTimer, &QTimer::timeout, this, &Qt5InformationNodeInstanceServer::handleObjectPropertyChangeTimeout); QObject::connect(&m_selectionChangeTimer, &QTimer::timeout, @@ -2054,7 +2054,7 @@ void Qt5InformationNodeInstanceServer::collectItemChangesAndSendChangeCommands() QQuickDesignerSupport::polishItems(quickWindow()); QSet informationChangedInstanceSet; - QVector propertyChangedList; + QList propertyChangedList; if (quickWindow()) { for (QQuickItem *item : allItems()) { @@ -2221,7 +2221,7 @@ void Qt5InformationNodeInstanceServer::completeComponent(const CompleteComponent Qt5NodeInstanceServer::completeComponent(command); QList instanceList; - const QVector instances = command.instances(); + const QList instances = command.instances(); for (qint32 instanceId : instances) { if (hasInstanceForId(instanceId)) { ServerNodeInstance instance = instanceForId(instanceId); @@ -2258,7 +2258,7 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm } // Find a scene root of the selection to update active scene shown - const QVector instanceIds = command.instanceIds(); + const QList instanceIds = command.instanceIds(); QVariantList selectedObjs; QObject *firstSceneRoot = nullptr; ServerNodeInstance firstInstance; @@ -2473,7 +2473,7 @@ bool Qt5InformationNodeInstanceServer::isSceneEnvironmentBgProperty(const Proper void Qt5InformationNodeInstanceServer::changePropertyValues(const ChangeValuesCommand &command) { bool hasDynamicProperties = false; - const QVector values = command.valueChanges(); + const QList values = command.valueChanges(); QSet sceneEnvs; for (const PropertyValueContainer &container : values) { if (!container.isReflected()) { @@ -2599,6 +2599,9 @@ void Qt5InformationNodeInstanceServer::view3DAction([[maybe_unused]] const View3 case View3DActionType::SyncEnvBackground: updatedToolState.insert("syncEnvBackground", command.isEnabled()); break; + case View3DActionType::ViewportPreset: + updatedToolState.insert("activePreset", command.value()); + break; #ifdef QUICK3D_PARTICLES_MODULE case View3DActionType::ShowParticleEmitter: updatedToolState.insert("showParticleEmitter", command.isEnabled()); @@ -2637,8 +2640,8 @@ void Qt5InformationNodeInstanceServer::view3DAction([[maybe_unused]] const View3 getNodeAtMainScenePos(data[0].toPointF(), qint32(data[1].toInt())); return; } - case View3DActionType::SplitViewToggle: - updatedToolState.insert("splitView", command.isEnabled()); + case View3DActionType::ViewportViewToggle: + updatedToolState.insert("viewportView", command.isEnabled()); break; case View3DActionType::FlyModeToggle: updatedToolState.insert("flyMode", command.isEnabled()); @@ -2757,7 +2760,7 @@ void Qt5InformationNodeInstanceServer::changeState(const ChangeStateCommand &com void Qt5InformationNodeInstanceServer::removeProperties(const RemovePropertiesCommand &command) { - const QVector props = command.properties(); + const QList props = command.properties(); QSet sceneEnvs; for (const PropertyAbstractContainer &container : props) { diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/qt5informationnodeinstanceserver.h b/src/tools/qmlpuppet/qmlpuppet/instances/qt5informationnodeinstanceserver.h index f0d796f9003..3f93ca5aebc 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/qt5informationnodeinstanceserver.h +++ b/src/tools/qmlpuppet/qmlpuppet/instances/qt5informationnodeinstanceserver.h @@ -66,7 +66,7 @@ private slots: void handleObjectPropertyCommit(const QVariant &objects, const QVariant &propNames); void handleObjectPropertyChange(const QVariant &objects, const QVariant &propNames); void handleActiveSceneChange(); - void handleActiveSplitChange(int index); + void handleActiveViewportChange(int index); void handleToolStateChanged(const QString &sceneId, const QString &tool, const QVariant &toolState); void handleView3DSizeChange(); @@ -80,8 +80,8 @@ protected: bool isDirtyRecursiveForNonInstanceItems(QQuickItem *item) const; bool isDirtyRecursiveForParentInstances(QQuickItem *item) const; void selectInstances(const QList &instanceList); - void modifyProperties(const QVector &properties); - QList createInstances(const QVector &container) override; + void modifyProperties(const QList &properties); + QList createInstances(const QList &container) override; void initializeAuxiliaryViews() override; private: @@ -98,7 +98,7 @@ private: QObject *findView3DForSceneRoot(QObject *sceneRoot) const; QObject *find3DSceneRoot(const ServerNodeInstance &instance) const; QObject *find3DSceneRoot(QObject *obj) const; - QVector propertyToPropertyValueTriples( + QList propertyToPropertyValueTriples( const ServerNodeInstance &instance, const PropertyName &propertyName, const QVariant &variant); @@ -122,11 +122,11 @@ private: void handleInputEvents(); void resolveImportSupport(); void updateActiveScenePreferredCamera(); - void updateMaterialPreviewData(const QVector &valueChanges); - void updateRotationBlocks(const QVector &valueChanges); - void updateSnapAndCameraSettings(const QVector &valueChanges); - void updateColorSettings(const QVector &valueChanges); - void removeRotationBlocks(const QVector &instanceIds); + void updateMaterialPreviewData(const QList &valueChanges); + void updateRotationBlocks(const QList &valueChanges); + void updateSnapAndCameraSettings(const QList &valueChanges); + void updateColorSettings(const QList &valueChanges); + void removeRotationBlocks(const QList &instanceIds); void getNodeAtPos(const QPointF &pos); void getNodeAtMainScenePos(const QPointF &pos, qint32 viewId); diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/qt5nodeinstanceserver.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/qt5nodeinstanceserver.cpp index 85b5021f5ed..f4a11b1a2b8 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/qt5nodeinstanceserver.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/qt5nodeinstanceserver.cpp @@ -189,10 +189,21 @@ QList subItems(QQuickItem *parentItem) const QList Qt5NodeInstanceServer::allItems() const { - if (rootNodeInstance().isValid()) - return rootNodeInstance().allItemsRecursive(); + if (!rootNodeInstance().isValid()) + return {}; - return {}; + QList allItems = rootNodeInstance().allItemsRecursive(); + + // ShaderEffects affecting root item will be root item siblings, so add those as well + QQuickItem *rootItem = rootNodeInstance().rootQuickItem(); + if (rootItem && rootItem->parentItem()) { + const QList siblings = rootItem->parentItem()->childItems(); + for (QQuickItem *sibling : siblings) { + if (sibling != rootItem) + allItems.append(sibling); + } + } + return allItems; } bool Qt5NodeInstanceServer::rootIsRenderable3DObject() const diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/qt5previewnodeinstanceserver.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/qt5previewnodeinstanceserver.cpp index d20d0534b02..5a67de15676 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/qt5previewnodeinstanceserver.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/qt5previewnodeinstanceserver.cpp @@ -52,7 +52,7 @@ void Qt5PreviewNodeInstanceServer::collectItemChangesAndSendChangeCommands() QQuickDesignerSupport::polishItems(quickWindow()); - QVector imageContainerVector; + QList imageContainerVector; // Base state needs to be rendered twice to properly render shared resources, // if there is more than one View3D and at least one of them is dirty. diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/qt5rendernodeinstanceserver.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/qt5rendernodeinstanceserver.cpp index c8f1d489e3e..b055b70cbc7 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/qt5rendernodeinstanceserver.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/qt5rendernodeinstanceserver.cpp @@ -163,7 +163,9 @@ ServerNodeInstance Qt5RenderNodeInstanceServer::findNodeInstanceForItem(QQuickIt if (item) { if (hasInstanceForObject(item)) return instanceForObject(item); - else if (item->parentItem()) + else if (item == rootNodeInstance().rootQuickItem()->parentItem()) + return rootNodeInstance(); + else return findNodeInstanceForItem(item->parentItem()); } @@ -205,7 +207,7 @@ void Qt5RenderNodeInstanceServer::completeComponent(const CompleteComponentComma { Qt5NodeInstanceServer::completeComponent(command); - const QVector ids = command.instances(); + const QList ids = command.instances(); for (qint32 instanceId : ids) { if (hasInstanceForId(instanceId)) { ServerNodeInstance instance = instanceForId(instanceId); @@ -225,7 +227,7 @@ void Qt5RenderNodeInstanceServer::changePropertyValues(const ChangeValuesCommand { Qt5NodeInstanceServer::changePropertyValues(command); - const QVector values = command.valueChanges(); + const QList values = command.valueChanges(); for (const PropertyValueContainer &container : values) { // In case an effect item visibility changed to false, make sure all children are rendered // again as they might not have valid pixmaps yet @@ -253,7 +255,7 @@ void Qt5RenderNodeInstanceServer::changePropertyBindings(const ChangeBindingsCom { Qt5NodeInstanceServer::changePropertyBindings(command); - const QVector changes = command.bindingChanges; + const QList changes = command.bindingChanges; for (const PropertyBindingContainer &container : changes) { if (container.isDynamic() && hasInstanceForId(container.instanceId())) { // Changes to dynamic properties are not always noticed by normal signal spy mechanism @@ -267,7 +269,7 @@ void Qt5RenderNodeInstanceServer::reparentInstances(const ReparentInstancesComma { ServerNodeInstance effectNode; ServerNodeInstance oldParent; - const QVector containers = command.reparentInstances(); + const QList containers = command.reparentInstances(); for (const ReparentContainer &container : containers) { if (hasInstanceForId(container.instanceId())) { ServerNodeInstance instance = instanceForId(container.instanceId()); @@ -302,7 +304,7 @@ void Qt5RenderNodeInstanceServer::reparentInstances(const ReparentInstancesComma void Qt5RenderNodeInstanceServer::removeInstances(const RemoveInstancesCommand &command) { ServerNodeInstance oldParent; - const QVector ids = command.instanceIds(); + const QList ids = command.instanceIds(); for (qint32 id : ids) { if (hasInstanceForId(id)) { ServerNodeInstance instance = instanceForId(id); diff --git a/src/tools/qmlpuppet/qmlpuppet/instances/qt5testnodeinstanceserver.cpp b/src/tools/qmlpuppet/qmlpuppet/instances/qt5testnodeinstanceserver.cpp index ca501b5eb32..6176d108db3 100644 --- a/src/tools/qmlpuppet/qmlpuppet/instances/qt5testnodeinstanceserver.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/instances/qt5testnodeinstanceserver.cpp @@ -238,7 +238,7 @@ void QmlDesigner::Qt5TestNodeInstanceServer::collectItemChangesAndSendChangeComm QQuickDesignerSupport::polishItems(quickWindow()); QSet informationChangedInstanceSet; - QVector propertyChangedList; + QList propertyChangedList; QSet parentChangedSet; if (quickWindow()) { diff --git a/src/tools/qmlpuppet/qmlpuppet/renderer/qmlrenderer.cpp b/src/tools/qmlpuppet/qmlpuppet/renderer/qmlrenderer.cpp index 6a1d6ad78d1..5eb8e11c5ef 100644 --- a/src/tools/qmlpuppet/qmlpuppet/renderer/qmlrenderer.cpp +++ b/src/tools/qmlpuppet/qmlpuppet/renderer/qmlrenderer.cpp @@ -23,6 +23,9 @@ constexpr int DEFAULT_MAX_DIM = 1024; void QmlRenderer::initCoreApp() { +#ifdef Q_OS_MACOS + qputenv("QT_MAC_DISABLE_FOREGROUND_APPLICATION_TRANSFORM", "true"); +#endif #if defined QT_WIDGETS_LIB createCoreApp(); #else @@ -145,9 +148,14 @@ bool QmlRenderer::setupRenderer() return false; } - QObject *renderObj = component.create(); + // Window components will flash the window briefly if we don't initialize visible to false + QVariantMap initialProps; + initialProps["visible"] = false; + QObject *renderObj = component.createWithInitialProperties(initialProps); if (renderObj) { + if (!qobject_cast(renderObj)) + renderObj->setProperty("visible", true); QQuickItem *contentItem3D = nullptr; #ifdef QUICK3D_MODULE renderObj->setParent(m_window->contentItem()); @@ -196,11 +204,6 @@ bool QmlRenderer::setupRenderer() // Hack to render Window items: reparent window content to m_window->contentItem() setRenderSize(renderWindow->size()); m_containerItem = m_window->contentItem(); - // Suppress the original window. - // Offscreen position ensures we don't get even brief flash of it. - renderWindow->setVisible(false); - renderWindow->resize(2, 2); - renderWindow->setPosition(-10000, -10000); const QList childItems = renderWindow->contentItem()->childItems(); for (QQuickItem *item : childItems) { item->setParent(m_window->contentItem()); diff --git a/tests/unit/tests/matchers/projectstorage-matcher.h b/tests/unit/tests/matchers/projectstorage-matcher.h index 197aa36af24..877f1d2cae5 100644 --- a/tests/unit/tests/matchers/projectstorage-matcher.h +++ b/tests/unit/tests/matchers/projectstorage-matcher.h @@ -78,7 +78,7 @@ MATCHER_P3(IsItemLibraryProperty, template auto IsTypeAnnotation(QmlDesigner::SourceId sourceId, - QmlDesigner::SourceContextId directoryId, + QmlDesigner::DirectoryPathId directoryId, Utils::SmallStringView typeName, QmlDesigner::ModuleId moduleId, IconPathMatcher iconPath, diff --git a/tests/unit/tests/matchers/property-matcher.h b/tests/unit/tests/matchers/property-matcher.h new file mode 100644 index 00000000000..33922872bc7 --- /dev/null +++ b/tests/unit/tests/matchers/property-matcher.h @@ -0,0 +1,86 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +#include +#include + +namespace internal { + +template +class PropertyMatcher +{ +public: + PropertyMatcher(Property property, const Matcher &matcher, Arguments... arguments) + : m_property(property) + , m_matcher(matcher) + , m_whose_property() + , m_arguments{arguments...} + {} + + PropertyMatcher(const std::string &whose_property, + Property property, + const Matcher &matcher, + Arguments... arguments) + : m_property(property) + , m_matcher(matcher) + , m_whose_property(whose_property) + , m_arguments{arguments...} + {} + + void DescribeTo(::std::ostream *os) const + { + *os << "is an object " << m_whose_property; + m_matcher.DescribeTo(os); + } + + void DescribeNegationTo(::std::ostream *os) const + { + *os << "is an object " << m_whose_property; + m_matcher.DescribeNegationTo(os); + } + + template + bool MatchAndExplain(const T &value, testing::MatchResultListener *listener) const + { + *listener << "which points to an object "; + + auto result = std::apply( + [&](auto &&...arguments) { return std::invoke(m_property, value, arguments...); }, + m_arguments); + return m_matcher.MatchAndExplain(result, listener->stream()); + } + +private: + Property m_property; + Matcher m_matcher; + std::string m_whose_property; + std::tuple m_arguments; +}; + +template +concept matcher = std::derived_from + || requires { typename PropertyMatcher::is_gtest_matcher; }; + +} // namespace internal + +template +inline auto Property(const std::string &propertyName, + PropertyType property, + const PropertyMatcher &matchingType, + Arguments... arguments) +// requires(sizeof...(Arguments) >= 1) +{ + using namespace std::string_literals; + + return testing::MakePolymorphicMatcher( + internal::PropertyMatcher( + "whose property `"s + propertyName + "` "s, + property, + matchingType, + std::forward(arguments)...)); +} diff --git a/tests/unit/tests/mocks/CMakeLists.txt b/tests/unit/tests/mocks/CMakeLists.txt index 432a2ca2c54..a86e7a8f702 100644 --- a/tests/unit/tests/mocks/CMakeLists.txt +++ b/tests/unit/tests/mocks/CMakeLists.txt @@ -28,6 +28,7 @@ add_qtc_library(TestMocks OBJECT projectstorageobservermock.h projectstoragepathwatchermock.h projectstoragepathwatchernotifiermock.h + projectstoragetriggerupdatemock.h qmldocumentparsermock.h qmltypesparsermock.h sourcepathcachemock.h sourcepathcachemock.cpp diff --git a/tests/unit/tests/mocks/projectstorageerrornotifiermock.h b/tests/unit/tests/mocks/projectstorageerrornotifiermock.h index 17281682974..e58b27d1a33 100644 --- a/tests/unit/tests/mocks/projectstorageerrornotifiermock.h +++ b/tests/unit/tests/mocks/projectstorageerrornotifiermock.h @@ -32,4 +32,5 @@ public: QmlDesigner::SourceId qmlDocumentSourceId, QmlDesigner::SourceId qmldirSourceId), (override)); + MOCK_METHOD(void, qmltypesFileMissing, (QStringView qmltypesPath), (override)); }; diff --git a/tests/unit/tests/mocks/projectstoragemock.cpp b/tests/unit/tests/mocks/projectstoragemock.cpp index 150930db1ab..9d5b89f7743 100644 --- a/tests/unit/tests/mocks/projectstoragemock.cpp +++ b/tests/unit/tests/mocks/projectstoragemock.cpp @@ -243,6 +243,13 @@ void ProjectStorageMock::setItemLibraryEntries( ON_CALL(*this, itemLibraryEntries(TypedEq(sourceId))).WillByDefault(Return(entries)); } +void ProjectStorageMock::setDirectoryImportsItemLibraryEntries( + QmlDesigner::SourceId sourceId, const QmlDesigner::Storage::Info::ItemLibraryEntries &entries) +{ + ON_CALL(*this, directoryImportsItemLibraryEntries(TypedEq(sourceId))) + .WillByDefault(Return(entries)); +} + namespace { void addBaseProperties(TypeId typeId, const QmlDesigner::SmallTypeIds<16> &baseTypeIds, diff --git a/tests/unit/tests/mocks/projectstoragemock.h b/tests/unit/tests/mocks/projectstoragemock.h index 1d64b0cc1e8..8fc77ddd5e8 100644 --- a/tests/unit/tests/mocks/projectstoragemock.h +++ b/tests/unit/tests/mocks/projectstoragemock.h @@ -114,6 +114,8 @@ public: const QmlDesigner::Storage::Info::ItemLibraryEntries &entries); void setItemLibraryEntries(QmlDesigner::SourceId sourceId, const QmlDesigner::Storage::Info::ItemLibraryEntries &entries); + void setDirectoryImportsItemLibraryEntries( + QmlDesigner::SourceId sourceId, const QmlDesigner::Storage::Info::ItemLibraryEntries &entries); MOCK_METHOD(void, synchronize, @@ -131,6 +133,10 @@ public: moduleId, (::Utils::SmallStringView, QmlDesigner::Storage::ModuleKind moduleKind), (const, override)); + MOCK_METHOD(QmlDesigner::SmallModuleIds<128>, + moduleIdsStartsWith, + (::Utils::SmallStringView, QmlDesigner::Storage::ModuleKind moduleKind), + (const, override)); MOCK_METHOD(QmlDesigner::Storage::Module, module, (QmlDesigner::ModuleId), (const, override)); MOCK_METHOD(std::optional, @@ -205,9 +211,9 @@ public: (const, override)); MOCK_METHOD(QmlDesigner::SmallSourceIds<4>, typeAnnotationSourceIds, - (QmlDesigner::SourceContextId directoryId), + (QmlDesigner::DirectoryPathId directoryId), (const, override)); - MOCK_METHOD(QmlDesigner::SmallSourceContextIds<64>, + MOCK_METHOD(QmlDesigner::SmallDirectoryPathIds<64>, typeAnnotationDirectoryIds, (), (const, override)); @@ -228,6 +234,10 @@ public: allItemLibraryEntries, (), (const, override)); + MOCK_METHOD(QmlDesigner::Storage::Info::ItemLibraryEntries, + directoryImportsItemLibraryEntries, + (QmlDesigner::SourceId sourceId), + (const, override)); MOCK_METHOD(std::vector<::Utils::SmallString>, signalDeclarationNames, (QmlDesigner::TypeId typeId), @@ -309,18 +319,18 @@ public: MOCK_METHOD(QmlDesigner::Storage::Synchronization::DirectoryInfos, fetchDirectoryInfos, - (QmlDesigner::SourceContextId directoryId), + (QmlDesigner::DirectoryPathId directoryId), (const, override)); MOCK_METHOD(QmlDesigner::Storage::Synchronization::DirectoryInfos, fetchDirectoryInfos, - (QmlDesigner::SourceContextId directoryId, + (QmlDesigner::DirectoryPathId directoryId, QmlDesigner::Storage::Synchronization::FileType), (const, override)); - MOCK_METHOD(QmlDesigner::SmallSourceContextIds<32>, + MOCK_METHOD(QmlDesigner::SmallDirectoryPathIds<32>, fetchSubdirectoryIds, - (QmlDesigner::SourceContextId directoryId), + (QmlDesigner::DirectoryPathId directoryId), (const, override)); MOCK_METHOD(std::optional, @@ -328,25 +338,25 @@ public: (QmlDesigner::SourceId sourceId), (const, override)); - MOCK_METHOD(QmlDesigner::SourceContextId, - fetchSourceContextId, - (::Utils::SmallStringView SourceContextPath), + MOCK_METHOD(QmlDesigner::DirectoryPathId, + fetchDirectoryPathId, + (::Utils::SmallStringView DirectoryPath), ()); - MOCK_METHOD(QmlDesigner::SourceNameId, fetchSourceNameId, (::Utils::SmallStringView sourceName), ()); - MOCK_METHOD(QmlDesigner::SourceContextId, - fetchSourceContextIdUnguarded, - (::Utils::SmallStringView sourceContextPath), + MOCK_METHOD(QmlDesigner::FileNameId, fetchFileNameId, (::Utils::SmallStringView fileName), ()); + MOCK_METHOD(QmlDesigner::DirectoryPathId, + fetchDirectoryPathIdUnguarded, + (::Utils::SmallStringView directoryPath), ()); - MOCK_METHOD(QmlDesigner::SourceNameId, - fetchSourceNameIdUnguarded, - (::Utils::SmallStringView sourceName), + MOCK_METHOD(QmlDesigner::FileNameId, + fetchFileNameIdUnguarded, + (::Utils::SmallStringView fileName), ()); MOCK_METHOD(::Utils::PathString, - fetchSourceContextPath, - (QmlDesigner::SourceContextId sourceContextId)); - MOCK_METHOD(Utils::SmallString, fetchSourceName, (QmlDesigner::SourceNameId sourceId)); - MOCK_METHOD(std::vector, fetchAllSourceContexts, (), ()); - MOCK_METHOD(std::vector, fetchAllSourceNames, (), ()); + fetchDirectoryPath, + (QmlDesigner::DirectoryPathId directoryPathId)); + MOCK_METHOD(Utils::SmallString, fetchFileName, (QmlDesigner::FileNameId sourceId)); + MOCK_METHOD(std::vector, fetchAllDirectoryPaths, (), ()); + MOCK_METHOD(std::vector, fetchAllFileNames, (), ()); MOCK_METHOD(QmlDesigner::SourceId, propertyEditorPathId, diff --git a/tests/unit/tests/mocks/projectstoragepathwatchermock.h b/tests/unit/tests/mocks/projectstoragepathwatchermock.h index dd4e015d0b0..85918bde040 100644 --- a/tests/unit/tests/mocks/projectstoragepathwatchermock.h +++ b/tests/unit/tests/mocks/projectstoragepathwatchermock.h @@ -14,7 +14,7 @@ public: MOCK_METHOD(void, updateContextIdPaths, (const std::vector &idPaths, - const QmlDesigner::SourceContextIds &sourceContextIds), + const QmlDesigner::DirectoryPathIds &directoryPathIds), (override)); MOCK_METHOD(void, removeIds, (const QmlDesigner::ProjectPartIds &ids), (override)); MOCK_METHOD(void, diff --git a/tests/unit/tests/mocks/projectstoragetriggerupdatemock.h b/tests/unit/tests/mocks/projectstoragetriggerupdatemock.h new file mode 100644 index 00000000000..f77a125990d --- /dev/null +++ b/tests/unit/tests/mocks/projectstoragetriggerupdatemock.h @@ -0,0 +1,19 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "../utils/googletest.h" + +#include + +class ProjectStorageTriggerUpdateMock : public QmlDesigner::ProjectStorageTriggerUpdateInterface +{ +public: + virtual ~ProjectStorageTriggerUpdateMock() = default; + + MOCK_METHOD(void, + checkForChangeInDirectory, + (QmlDesigner::DirectoryPathIds directoryPathIds), + (override)); +}; diff --git a/tests/unit/tests/mocks/sourcepathcachemock.h b/tests/unit/tests/mocks/sourcepathcachemock.h index 5b4f16fe175..715dae589cd 100644 --- a/tests/unit/tests/mocks/sourcepathcachemock.h +++ b/tests/unit/tests/mocks/sourcepathcachemock.h @@ -22,27 +22,27 @@ public: (const, override)); MOCK_METHOD(QmlDesigner::SourceId, sourceId, - (QmlDesigner::SourceContextId sourceContextId, Utils::SmallStringView sourceName), + (QmlDesigner::DirectoryPathId directoryPathId, Utils::SmallStringView fileName), (const, override)); - MOCK_METHOD(QmlDesigner::SourceNameId, - sourceNameId, - (Utils::SmallStringView sourceName), + MOCK_METHOD(QmlDesigner::FileNameId, + fileNameId, + (Utils::SmallStringView fileName), (const, override)); MOCK_METHOD(QmlDesigner::SourcePath, sourcePath, (QmlDesigner::SourceId sourceId), (const, override)); - MOCK_METHOD(QmlDesigner::SourceContextId, - sourceContextId, + MOCK_METHOD(QmlDesigner::DirectoryPathId, + directoryPathId, (Utils::SmallStringView directoryPath), (const, override)); MOCK_METHOD(Utils::PathString, - sourceContextPath, - (QmlDesigner::SourceContextId directoryPathId), + directoryPath, + (QmlDesigner::DirectoryPathId directoryPathId), (const, override)); MOCK_METHOD(Utils::SmallString, - sourceName, - (QmlDesigner::SourceNameId sourceName), + fileName, + (QmlDesigner::FileNameId fileName), (const, override)); MOCK_METHOD(void, populateIfEmpty, (), (override)); }; diff --git a/tests/unit/tests/mocks/sqlitereadstatementmock.h b/tests/unit/tests/mocks/sqlitereadstatementmock.h index aaeb9df94b4..d00e44a60c2 100644 --- a/tests/unit/tests/mocks/sqlitereadstatementmock.h +++ b/tests/unit/tests/mocks/sqlitereadstatementmock.h @@ -64,21 +64,21 @@ public: (long long, Utils::SmallStringView), ()); - MOCK_METHOD(std::vector, - valuesReturnCacheSourceContexts, + MOCK_METHOD(std::vector, + valuesReturnCacheDirectoryPaths, (std::size_t), ()); - MOCK_METHOD(std::vector, - valuesReturnCacheSourceNames, + MOCK_METHOD(std::vector, + valuesReturnCacheFileNames, (std::size_t), ()); MOCK_METHOD(Sqlite::TimeStamp, valueWithTransactionReturnsTimeStamp, (Utils::SmallStringView), ()); MOCK_METHOD(int, valueWithTransactionReturnsInt, (Utils::SmallStringView), ()); - MOCK_METHOD(QmlDesigner::SourceContextId, valueReturnsSourceContextId, (Utils::SmallStringView), ()); - MOCK_METHOD(QmlDesigner::SourceContextId, valueWithTransactionReturnsSourceContextId, (int), ()); + MOCK_METHOD(QmlDesigner::DirectoryPathId, valueReturnsDirectoryPathId, (Utils::SmallStringView), ()); + MOCK_METHOD(QmlDesigner::DirectoryPathId, valueWithTransactionReturnsDirectoryPathId, (int), ()); MOCK_METHOD(QmlDesigner::SourceId, valueReturnsSourceId, (int, Utils::SmallStringView), ()); @@ -161,8 +161,8 @@ public: else if constexpr (std::is_same_v>) return valueReturnsPropertyDeclaration(queryValues...); - else if constexpr (std::is_same_v) - return valueReturnsSourceContextId(queryValues...); + else if constexpr (std::is_same_v) + return valueReturnsDirectoryPathId(queryValues...); else if constexpr (std::is_same_v) return valueReturnsSourceId(queryValues...); else if constexpr (std::is_same_v) @@ -181,8 +181,8 @@ public: else if constexpr (std::is_same_v>) return valueReturnsPropertyDeclaration(queryValues...); - else if constexpr (std::is_same_v) - return valueWithTransactionReturnsSourceContextId(queryValues...); + else if constexpr (std::is_same_v) + return valueWithTransactionReturnsDirectoryPathId(queryValues...); else if constexpr (std::is_same_v) return valueWithTransactionReturnsTimeStamp(queryValues...); else if constexpr (std::is_same_v) @@ -207,10 +207,10 @@ public: return valuesReturnStringVector(reserveSize); else if constexpr (std::is_same_v) return valuesReturnRowIds(reserveSize); - else if constexpr (std::is_same_v) - return valuesReturnCacheSourceContexts(reserveSize); - else if constexpr (std::is_same_v) - return valuesReturnCacheSourceNames(reserveSize); + else if constexpr (std::is_same_v) + return valuesReturnCacheDirectoryPaths(reserveSize); + else if constexpr (std::is_same_v) + return valuesReturnCacheFileNames(reserveSize); else if constexpr (std::is_same_v) return valuesReturnsStorageTypes(reserveSize, queryValues...); else if constexpr (std::is_same_v) diff --git a/tests/unit/tests/printers/gtest-creator-printing.cpp b/tests/unit/tests/printers/gtest-creator-printing.cpp index ad7522c9709..ab55f169d54 100644 --- a/tests/unit/tests/printers/gtest-creator-printing.cpp +++ b/tests/unit/tests/printers/gtest-creator-printing.cpp @@ -489,7 +489,7 @@ std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths) std::ostream &operator<<(std::ostream &out, const WatcherEntry &entry) { - return out << "(" << entry.sourceId << ", " << entry.sourceContextId << ", " << entry.id << ", " + return out << "(" << entry.sourceId << ", " << entry.directoryPathId << ", " << entry.id << ", " << entry.lastModified << ")"; } @@ -598,11 +598,17 @@ std::ostream &operator<<(std::ostream &out, AuxiliaryDataType type) return out; } +std::ostream &operator<<(std::ostream &out, SourceId sourceId) +{ + return out << "id=(" << sourceId.fileNameId().internalId() << ", " + << sourceId.directoryPathId().internalId() << ")"; +} + namespace Cache { -std::ostream &operator<<(std::ostream &out, const SourceContext &sourceContext) +std::ostream &operator<<(std::ostream &out, const DirectoryPath &directoryPath) { - return out << "(" << sourceContext.id << ", " << sourceContext.value << ")"; + return out << "(" << directoryPath.id << ", " << directoryPath.value << ")"; } } // namespace Cache diff --git a/tests/unit/tests/printers/gtest-creator-printing.h b/tests/unit/tests/printers/gtest-creator-printing.h index cb5731c53e6..d0ad6524876 100644 --- a/tests/unit/tests/printers/gtest-creator-printing.h +++ b/tests/unit/tests/printers/gtest-creator-printing.h @@ -139,6 +139,7 @@ struct CompoundPropertyMetaInfo; enum class FlagIs : unsigned int; template class BasicAuxiliaryDataKey; +class SourceId; void PrintTo(const ThemeProperty &prop, std::ostream *os); std::ostream &operator<<(std::ostream &out, const ThemeProperty &prop); @@ -162,11 +163,12 @@ std::ostream &operator<<(std::ostream &out, FlagIs flagIs); std::ostream &operator<<(std::ostream &out, const BasicAuxiliaryDataKey &key); std::ostream &operator<<(std::ostream &out, const BasicAuxiliaryDataKey &key); std::ostream &operator<<(std::ostream &out, AuxiliaryDataType type); +std::ostream &operator<<(std::ostream &out, SourceId sourceId); namespace Cache { -class SourceContext; +class DirectoryPath; -std::ostream &operator<<(std::ostream &out, const SourceContext &sourceContext); +std::ostream &operator<<(std::ostream &out, const DirectoryPath &directoryPath); } // namespace Cache namespace ImageCache { @@ -175,8 +177,8 @@ class FontCollectorSizeAuxiliaryData; class FontCollectorSizesAuxiliaryData; std::ostream &operator<<(std::ostream &out, const LibraryIconAuxiliaryData &date); -std::ostream &operator<<(std::ostream &out, const FontCollectorSizeAuxiliaryData &sourceContext); -std::ostream &operator<<(std::ostream &out, const FontCollectorSizesAuxiliaryData &sourceContext); +std::ostream &operator<<(std::ostream &out, const FontCollectorSizeAuxiliaryData &directoryPath); +std::ostream &operator<<(std::ostream &out, const FontCollectorSizesAuxiliaryData &directoryPath); } // namespace ImageCache namespace Storage { diff --git a/tests/unit/tests/printers/gtest-qt-printing.cpp b/tests/unit/tests/printers/gtest-qt-printing.cpp index ef4425e1eb7..d9c3d4d4ad3 100644 --- a/tests/unit/tests/printers/gtest-qt-printing.cpp +++ b/tests/unit/tests/printers/gtest-qt-printing.cpp @@ -1,6 +1,8 @@ // Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 +#include "gtest-qt-printing.h" + #include #include #include @@ -89,6 +91,19 @@ std::ostream &operator<<(std::ostream &out, const QIcon &icon) out << icon.cacheKey() << ")"; } +std::ostream &operator<<(std::ostream &out, const QStringList &list) +{ + if (list.isEmpty()) + return out << "[]"; + + return out << "[" << list.join("\", \"") << "]"; +} + +void PrintTo(QStringView text, std::ostream *os) +{ + *os << text; +} + void PrintTo(const QString &text, std::ostream *os) { *os << text; diff --git a/tests/unit/tests/printers/gtest-qt-printing.h b/tests/unit/tests/printers/gtest-qt-printing.h index a81994be167..27b2e8fa6a4 100644 --- a/tests/unit/tests/printers/gtest-qt-printing.h +++ b/tests/unit/tests/printers/gtest-qt-printing.h @@ -43,8 +43,10 @@ std::ostream &operator<<(std::ostream &out, QByteArrayView byteArray); std::ostream &operator<<(std::ostream &out, const QTextCharFormat &format); std::ostream &operator<<(std::ostream &out, const QImage &image); std::ostream &operator<<(std::ostream &out, const QIcon &icon); +std::ostream &operator<<(std::ostream &out, const QStringList &list); void PrintTo(const QString &text, std::ostream *os); +void PrintTo(QStringView text, std::ostream *os); void PrintTo(const QVariant &variant, std::ostream *os); void PrintTo(const QByteArray &text, std::ostream *os); QT_END_NAMESPACE diff --git a/tests/unit/tests/testdesignercore/CMakeLists.txt b/tests/unit/tests/testdesignercore/CMakeLists.txt index 240c6b36390..dd9dad3bd30 100644 --- a/tests/unit/tests/testdesignercore/CMakeLists.txt +++ b/tests/unit/tests/testdesignercore/CMakeLists.txt @@ -342,6 +342,7 @@ extend_qtc_library(TestDesignerCore projectstorageinfotypes.h projectstorageobserver.h projectstoragepathwatcher.h + projectstoragetriggerupdateinterface.h projectstoragepathwatcherinterface.h projectstoragepathwatchernotifierinterface.h projectstoragepathwatcher.h diff --git a/tests/unit/tests/unittests/componentcore/propertycomponentgenerator-test.cpp b/tests/unit/tests/unittests/componentcore/propertycomponentgenerator-test.cpp index 4b398420082..facce0fa5e9 100644 --- a/tests/unit/tests/unittests/componentcore/propertycomponentgenerator-test.cpp +++ b/tests/unit/tests/unittests/componentcore/propertycomponentgenerator-test.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -173,10 +174,11 @@ protected: protected: inline static QSharedPointer simpleReaderNode; NiceMock viewMock; + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/foo.qml"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; NiceMock resourceManagementMock; - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", -1, -1, @@ -221,7 +223,7 @@ TEST_F(PropertyComponentGenerator, QString expectedText = QStringLiteral( R"xy( Section { - caption: foo - Foo + caption: "foo - Foo" anchors.left: parent.left anchors.right: parent.right leftPadding: 8 @@ -254,7 +256,7 @@ TEST_F(PropertyComponentGenerator, QString expectedText = QStringLiteral( R"xy( Section { - caption: foo - Foo + caption: "foo - Foo" anchors.left: parent.left anchors.right: parent.right leftPadding: 8 diff --git a/tests/unit/tests/unittests/designercoreutils/modelutils-test.cpp b/tests/unit/tests/unittests/designercoreutils/modelutils-test.cpp index 24393accd04..c190585ab00 100644 --- a/tests/unit/tests/unittests/designercoreutils/modelutils-test.cpp +++ b/tests/unit/tests/unittests/designercoreutils/modelutils-test.cpp @@ -5,7 +5,9 @@ #include #include +#include #include + #include #include #include @@ -18,11 +20,12 @@ using QmlDesigner::Storage::ModuleKind; class ModelUtilsWithModel : public ::testing::Test { protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/model.qml"}; QmlDesigner::SourceId sourceId = pathCacheMock.createSourceId("/path/foo.qml"); NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; QmlDesigner::ModuleId moduleId = projectStorageMock.moduleId("QtQuick", ModuleKind::QmlLibrary); - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", {QmlDesigner::Import::createLibraryImport("QML"), QmlDesigner::Import::createLibraryImport("QtQuick"), diff --git a/tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp b/tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp index 2fa8de50705..48fb66eb97d 100644 --- a/tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp +++ b/tests/unit/tests/unittests/designsystem/dsthemeqml-test.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -23,6 +24,8 @@ using QmlDesigner::Import; using QmlDesigner::ModelNode; using QmlDesigner::ThemeProperty; +constexpr QmlDesigner::ModelTracing::SourceLocation sl; + namespace { std::string formatedPropStr(std::string tag, const QByteArray &name, const QVariant &value) { @@ -103,9 +106,10 @@ protected: const QmlDesigner::GroupType groupType = GetParam(); const QmlDesigner::PropertyName groupName = GroupId(groupType); QmlDesigner::DSThemeGroup group; + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/model.qm"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "QtObject", {Import::createLibraryImport("QM"), Import::createLibraryImport("QtQuick")}, @@ -134,7 +138,7 @@ TEST_P(DesignSystemQmlTest, group_aliase_properties_are_generated) // assert ASSERT_THAT(rootNode, - AllOf(Property("ModelNode::type", &ModelNode::type, Eq("QtObject")), + AllOf(Property("ModelNode::type", &ModelNode::type, Eq("QtObject"), sl), HasBindingProperty(groupName, binding), HasBindingProperty("currentTheme", darkThemeName), HasNodeProperty(darkThemeName, "QtObject"))); @@ -152,7 +156,7 @@ TEST_P(DesignSystemQmlTest, empty_groups_generate_no_group_aliase_properties) // assert ASSERT_THAT(rootNode, - AllOf(Property("ModelNode::type", &ModelNode::type, Eq("QtObject")), + AllOf(Property("ModelNode::type", &ModelNode::type, Eq("QtObject"), sl), Not(HasBindingProperty(groupName, binding)), Not(HasBindingProperty("currentTheme", darkThemeName)), Not(HasNodeProperty(darkThemeName, "QtObject")))); diff --git a/tests/unit/tests/unittests/listmodeleditor/listmodeleditor-test.cpp b/tests/unit/tests/unittests/listmodeleditor/listmodeleditor-test.cpp index 2e8de03cbd2..5b704599bb1 100644 --- a/tests/unit/tests/unittests/listmodeleditor/listmodeleditor-test.cpp +++ b/tests/unit/tests/unittests/listmodeleditor/listmodeleditor-test.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -26,6 +27,8 @@ using QmlDesigner::PropertyDeclarationId; using QmlDesigner::TypeId; namespace Info = QmlDesigner::Storage::Info; +constexpr QmlDesigner::ModelTracing::SourceLocation sl; + MATCHER_P2(HasItem, name, value, @@ -177,18 +180,40 @@ public: QModelIndex index(int row, int column) const { return model.index(row, column); } + int rowCount() const { return model.rowCount(); } + QList elements(const ModelNode &node) const { return node.defaultNodeListProperty().toModelNodeList(); } + QItemSelection rowSelection(std::initializer_list rows) const + { + QItemSelection selection; + for (int row : rows) + selection.select(model.index(row, 0), model.index(row, model.columnCount() - 1)); + return selection; + } + + QItemSelection itemSelection(std::initializer_list> items) const + { + QItemSelection selection; + for (const auto &[row, column] : items) { + QModelIndex idx = index(row, column); + selection.select(idx, idx); + } + return selection; + } + protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/foo.qml"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; NiceMock> goIntoComponentMock; QmlDesigner::ModelPointer designerModel{ QmlDesigner::Model::create(QmlDesigner::ProjectStorageDependencies{projectStorageMock, - pathCacheMock}, + pathCacheMock, + projectStorageTriggerUpdateMock}, "Item", {QmlDesigner::Import::createLibraryImport("QtQml.Models"), QmlDesigner::Import::createLibraryImport("QtQuick")}, @@ -197,6 +222,7 @@ protected: QmlDesigner::ListModelEditorModel model{[&] { return mockView.createModelNode("ListModel"); }, [&] { return mockView.createModelNode("ListElement"); }, goIntoComponentMock.AsStdFunction()}; + QItemSelectionModel selectionModel{&model}; ModelNode listViewNode; ModelNode listModelNode; ModelNode emptyListModelNode; @@ -204,7 +230,7 @@ protected: ModelNode element2; ModelNode element3; QmlDesigner::ModelPointer componentModel{ - QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, + QmlDesigner::Model::create({projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "ListModel", {QmlDesigner::Import::createLibraryImport("QtQml.Models"), QmlDesigner::Import::createLibraryImport("QtQuick")}, @@ -290,7 +316,7 @@ TEST_F(ListModelEditor, add_row_added_invalid_row) { model.setListModel(listModelNode); - model.addRow(); + model.addRow(rowCount()); ASSERT_THAT(displayValues(), ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42), @@ -299,24 +325,252 @@ TEST_F(ListModelEditor, add_row_added_invalid_row) ElementsAre(IsInvalid(), IsInvalid(), IsInvalid(), IsInvalid()))); } +TEST_F(ListModelEditor, add_row_to_zero_index_on_empty_model_works) +{ + model.setListModel(emptyListModelNode); + model.addColumn("foo"); + model.addColumn("bar"); + + model.addRow(0); + + ASSERT_THAT(displayValues(), ElementsAre(ElementsAre(IsInvalid(), IsInvalid()))); +} + +TEST_F(ListModelEditor, add_row_to_zero_index_on_non_empty_model_works) +{ + model.setListModel(listModelNode); + + model.addRow(0); + + ASSERT_THAT(displayValues(), + ElementsAre(ElementsAre(IsInvalid(), IsInvalid(), IsInvalid(), IsInvalid()), + ElementsAre(IsInvalid(), "foo", 1, 42), + ElementsAre("pic.png", "bar", 4, IsInvalid()), + ElementsAre("pic.png", "poo", 111, IsInvalid()))); +} + +TEST_F(ListModelEditor, add_row_to_index_one_works) +{ + model.setListModel(listModelNode); + + model.addRow(1); + + ASSERT_THAT(displayValues(), + ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42), + ElementsAre(IsInvalid(), IsInvalid(), IsInvalid(), IsInvalid()), + ElementsAre("pic.png", "bar", 4, IsInvalid()), + ElementsAre("pic.png", "poo", 111, IsInvalid()))); +} + +TEST_F(ListModelEditor, add_row_to_negative_index_does_nothing) +{ + model.setListModel(listModelNode); + + model.addRow(-1); + + ASSERT_THAT(displayValues(), + ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42), + ElementsAre("pic.png", "bar", 4, IsInvalid()), + ElementsAre("pic.png", "poo", 111, IsInvalid()))); +} + +TEST_F(ListModelEditor, add_row_to_int_max_index_does_nothing) +{ + model.setListModel(listModelNode); + + model.addRow(std::numeric_limits::max()); + + ASSERT_THAT(displayValues(), + ElementsAre(ElementsAre(IsInvalid(), "foo", 1, 42), + ElementsAre("pic.png", "bar", 4, IsInvalid()), + ElementsAre("pic.png", "poo", 111, IsInvalid()))); +} + TEST_F(ListModelEditor, add_row_creates_new_model_node_and_reparents) { model.setListModel(listModelNode); - EXPECT_CALL(mockView, nodeCreated(Property("ModelNode::type", &ModelNode::type, Eq("ListElement")))); EXPECT_CALL(mockView, - nodeReparented(Property("ModelNode::type", &ModelNode::type, Eq("ListElement")), - Property("AbstractProperty::parentModelNode", &AbstractProperty::parentModelNode, Eq(listModelNode)), + nodeCreated(Property("ModelNode::type", &ModelNode::type, Eq("ListElement"), sl))); + EXPECT_CALL(mockView, + nodeReparented(Property("ModelNode::type", &ModelNode::type, Eq("ListElement"), sl), + Property("AbstractProperty::parentModelNode", + &AbstractProperty::parentModelNode, + Eq(listModelNode)), _, _)); - model.addRow(); + model.addRow(rowCount()); +} + +TEST_F(ListModelEditor, current_interaction_row_returns_invalid_on_empty_selection) +{ + QItemSelectionModel emptySelection; + + int currentRow = ListModelEditorModel::currentInteractionRow(emptySelection); + + ASSERT_THAT(currentRow, Eq(-1)); +} + +TEST_F(ListModelEditor, current_interaction_row_returns_0_when_first_row_is_selected) +{ + model.setListModel(listModelNode); + selectionModel.select(rowSelection({0}), QItemSelectionModel::Select); + + int currentRow = ListModelEditorModel::currentInteractionRow(selectionModel); + + ASSERT_THAT(currentRow, Eq(0)); +} + +TEST_F(ListModelEditor, current_interaction_row_returns_1_when_second_row_is_selected) +{ + model.setListModel(listModelNode); + selectionModel.select(rowSelection({1}), QItemSelectionModel::Select); + + int currentRow = ListModelEditorModel::currentInteractionRow(selectionModel); + + ASSERT_THAT(currentRow, Eq(1)); +} + +TEST_F(ListModelEditor, current_interaction_row_returns_first_selected_row_when_multiple_rows_selected) +{ + model.setListModel(listModelNode); + selectionModel.select(rowSelection({1, 2}), QItemSelectionModel::Select); + + int currentRow = ListModelEditorModel::currentInteractionRow(selectionModel); + + ASSERT_THAT(currentRow, Eq(1)); +} + +TEST_F(ListModelEditor, current_interaction_row_returns_first_selected_item_row_when_no_row_selected) +{ + model.setListModel(listModelNode); + selectionModel.select(itemSelection({{2, 2}, {1, 2}}), QItemSelectionModel::Select); + + int currentRow = ListModelEditorModel::currentInteractionRow(selectionModel); + + ASSERT_THAT(currentRow, Eq(2)); +} + +TEST_F(ListModelEditor, current_interaction_row_returns_current_row_when_nothing_selected) +{ + model.setListModel(listModelNode); + selectionModel.setCurrentIndex(index(2, 2), QItemSelectionModel::Current); + + int currentRow = ListModelEditorModel::currentInteractionRow(selectionModel); + + ASSERT_THAT(currentRow, Eq(2)); +} + +TEST_F(ListModelEditor, current_interaction_row_prefers_selected_index_to_current_index) +{ + model.setListModel(listModelNode); + selectionModel.select(itemSelection({{2, 2}}), QItemSelectionModel::Select); + selectionModel.setCurrentIndex(index(1, 1), QItemSelectionModel::Current); + + int currentRow = ListModelEditorModel::currentInteractionRow(selectionModel); + + ASSERT_THAT(currentRow, Eq(2)); +} + +TEST_F(ListModelEditor, current_interaction_row_prefers_selected_row_to_selected_index) +{ + model.setListModel(listModelNode); + selectionModel.select(itemSelection({{1, 1}}), QItemSelectionModel::Select); + selectionModel.select(rowSelection({2}), QItemSelectionModel::Select); + + int currentRow = ListModelEditorModel::currentInteractionRow(selectionModel); + + ASSERT_THAT(currentRow, Eq(2)); +} + +TEST_F(ListModelEditor, next_interaction_row_returns_zero_on_empty_selection) +{ + QItemSelectionModel emptySelection; + + int nextRow = ListModelEditorModel::nextInteractionRow(emptySelection); + + ASSERT_THAT(nextRow, Eq(0)); +} + +TEST_F(ListModelEditor, next_interaction_row_returns_1_when_first_row_is_selected) +{ + model.setListModel(listModelNode); + selectionModel.select(rowSelection({0}), QItemSelectionModel::Select); + + int nextRow = ListModelEditorModel::nextInteractionRow(selectionModel); + + ASSERT_THAT(nextRow, Eq(1)); +} + +TEST_F(ListModelEditor, next_interaction_row_returns_2_when_second_row_is_selected) +{ + model.setListModel(listModelNode); + selectionModel.select(rowSelection({1}), QItemSelectionModel::Select); + + int nextRow = ListModelEditorModel::nextInteractionRow(selectionModel); + + ASSERT_THAT(nextRow, Eq(2)); +} + +TEST_F(ListModelEditor, + next_interaction_row_returns_next_row_after_last_selected_row_when_multiple_rows_selected) +{ + model.setListModel(listModelNode); + selectionModel.select(rowSelection({1, 2}), QItemSelectionModel::Select); + + int nextRow = ListModelEditorModel::nextInteractionRow(selectionModel); + + ASSERT_THAT(nextRow, Eq(3)); +} + +TEST_F(ListModelEditor, + next_interaction_row_returns_next_row_after_last_selected_item_row_when_no_row_selected) +{ + model.setListModel(listModelNode); + selectionModel.select(itemSelection({{2, 2}, {1, 2}}), QItemSelectionModel::Select); + + int nextRow = ListModelEditorModel::nextInteractionRow(selectionModel); + + ASSERT_THAT(nextRow, Eq(2)); +} + +TEST_F(ListModelEditor, next_interaction_row_returns_next_row_after_current_row_when_nothing_selected) +{ + model.setListModel(listModelNode); + selectionModel.setCurrentIndex(index(2, 2), QItemSelectionModel::Current); + + int nextRow = ListModelEditorModel::nextInteractionRow(selectionModel); + + ASSERT_THAT(nextRow, Eq(3)); +} + +TEST_F(ListModelEditor, next_interaction_row_prefers_selected_index_to_current_index) +{ + model.setListModel(listModelNode); + selectionModel.select(itemSelection({{2, 2}}), QItemSelectionModel::Select); + selectionModel.setCurrentIndex(index(1, 1), QItemSelectionModel::Current); + + int nextRow = ListModelEditorModel::nextInteractionRow(selectionModel); + + ASSERT_THAT(nextRow, Eq(3)); +} + +TEST_F(ListModelEditor, next_interaction_row_prefers_selected_row_to_selected_index) +{ + model.setListModel(listModelNode); + selectionModel.select(itemSelection({{1, 1}}), QItemSelectionModel::Select); + selectionModel.select(rowSelection({2}), QItemSelectionModel::Select); + + int nextRow = ListModelEditorModel::nextInteractionRow(selectionModel); + + ASSERT_THAT(nextRow, Eq(3)); } TEST_F(ListModelEditor, change_added_row_propery) { model.setListModel(listModelNode); - model.addRow(); + model.addRow(rowCount()); model.setValue(3, 2, 22); @@ -332,7 +586,7 @@ TEST_F(ListModelEditor, change_added_row_propery_calls_variant_properties_change model.setListModel(listModelNode); ModelNode element4; ON_CALL(mockView, nodeReparented(_, _, _, _)).WillByDefault(SaveArg<0>(&element4)); - model.addRow(); + model.addRow(rowCount()); EXPECT_CALL(mockView, variantPropertiesChanged(ElementsAre(IsVariantProperty(element4, "value", 22)), @@ -937,7 +1191,7 @@ TEST_F(ListModelEditor, remove_last_row) { model.setListModel(emptyListModelNode); model.addColumn("mood"); - model.addRow(); + model.addRow(rowCount()); model.removeRows({index(0, 0)}); @@ -948,7 +1202,7 @@ TEST_F(ListModelEditor, remove_last_empty_row) { model.setListModel(emptyListModelNode); model.addColumn("mood"); - model.addRow(); + model.addRow(rowCount()); model.removeColumns({index(0, 0)}); model.removeRows({index(0, 0)}); @@ -960,7 +1214,7 @@ TEST_F(ListModelEditor, remove_last_column) { model.setListModel(emptyListModelNode); model.addColumn("mood"); - model.addRow(); + model.addRow(rowCount()); model.removeColumns({index(0, 0)}); @@ -971,7 +1225,7 @@ TEST_F(ListModelEditor, remove_last_empty_column) { model.setListModel(emptyListModelNode); model.addColumn("mood"); - model.addRow(); + model.addRow(rowCount()); model.removeRows({index(0, 0)}); model.removeColumns({index(0, 0)}); diff --git a/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp index 41ad91ee6e1..c315720c19e 100644 --- a/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp +++ b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -105,9 +106,10 @@ protected: } protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCache{"/path/foo.qml"}; NiceMock projectStorageMock{pathCache.sourceId, "/path"}; - QmlDesigner::Model model{{projectStorageMock, pathCache}, + QmlDesigner::Model model{{projectStorageMock, pathCache, projectStorageTriggerUpdateMock}, "Item", {QmlDesigner::Import::createLibraryImport("QML"), QmlDesigner::Import::createLibraryImport("QtQuick"), diff --git a/tests/unit/tests/unittests/metainfo/propertymetainfo-test.cpp b/tests/unit/tests/unittests/metainfo/propertymetainfo-test.cpp index b3e466de06c..820a580b1a7 100644 --- a/tests/unit/tests/unittests/metainfo/propertymetainfo-test.cpp +++ b/tests/unit/tests/unittests/metainfo/propertymetainfo-test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -41,9 +42,10 @@ protected: } protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCache{"/path/foo.qml"}; NiceMock projectStorageMock{pathCache.sourceId, "/path"}; - QmlDesigner::Model model{{projectStorageMock, pathCache}, + QmlDesigner::Model model{{projectStorageMock, pathCache, projectStorageTriggerUpdateMock}, "Item", {QmlDesigner::Import::createLibraryImport("QML"), QmlDesigner::Import::createLibraryImport("QtQuick"), diff --git a/tests/unit/tests/unittests/model/auxiliarypropertystorageview-test.cpp b/tests/unit/tests/unittests/model/auxiliarypropertystorageview-test.cpp index 2021ca4f5c7..d6719f5be92 100644 --- a/tests/unit/tests/unittests/model/auxiliarypropertystorageview-test.cpp +++ b/tests/unit/tests/unittests/model/auxiliarypropertystorageview-test.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -40,17 +41,18 @@ protected: inline static std::unique_ptr staticData; Sqlite::Database &database = staticData->database; + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/foo.qml"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; NiceMock resourceManagementMock; QmlDesigner::Imports imports = {QmlDesigner::Import::createLibraryImport("QtQuick")}; - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", imports, pathCacheMock.path.toQString(), std::make_unique( resourceManagementMock)}; - QmlDesigner::Model model2{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model2{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", imports, pathCacheMock.path.toQString(), diff --git a/tests/unit/tests/unittests/model/model-test.cpp b/tests/unit/tests/unittests/model/model-test.cpp index 31ce1a30d8e..3e9fd1bc5c3 100644 --- a/tests/unit/tests/unittests/model/model-test.cpp +++ b/tests/unit/tests/unittests/model/model-test.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -119,13 +120,14 @@ protected: } protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/foo.qml"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; NiceMock resourceManagementMock; QmlDesigner::Imports imports = {QmlDesigner::Import::createLibraryImport("QtQuick")}; NiceMock viewMock; QUrl fileUrl = QUrl::fromLocalFile(pathCacheMock.path.toQString()); - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", imports, QUrl::fromLocalFile(pathCacheMock.path.toQString()), @@ -147,60 +149,60 @@ class Model_Creation : public Model TEST_F(Model_Creation, root_node_has_item_type_name) { - auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, - "Item", - imports, - fileUrl, - std::make_unique( - resourceManagementMock)); + auto model = QmlDesigner::Model::create( + {projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + imports, + fileUrl, + std::make_unique(resourceManagementMock)); ASSERT_THAT(model->rootModelNode().type(), Eq("Item")); } TEST_F(Model_Creation, root_node_has_item_meta_info) { - auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, - "Item", - imports, - fileUrl, - std::make_unique( - resourceManagementMock)); + auto model = QmlDesigner::Model::create( + {projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + imports, + fileUrl, + std::make_unique(resourceManagementMock)); ASSERT_THAT(model->rootModelNode().metaInfo(), model->qtQuickItemMetaInfo()); } TEST_F(Model_Creation, file_url) { - auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, - "Item", - imports, - fileUrl, - std::make_unique( - resourceManagementMock)); + auto model = QmlDesigner::Model::create( + {projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + imports, + fileUrl, + std::make_unique(resourceManagementMock)); ASSERT_THAT(model->fileUrl().toLocalFile(), Eq(pathCacheMock.path.toQString())); } TEST_F(Model_Creation, file_url_source_id) { - auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, - "Item", - imports, - fileUrl, - std::make_unique( - resourceManagementMock)); + auto model = QmlDesigner::Model::create( + {projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + imports, + fileUrl, + std::make_unique(resourceManagementMock)); ASSERT_THAT(model->fileUrlSourceId(), pathCacheMock.sourceId); } TEST_F(Model_Creation, imports) { - auto model = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, - "Item", - imports, - fileUrl, - std::make_unique( - resourceManagementMock)); + auto model = QmlDesigner::Model::create( + {projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + imports, + fileUrl, + std::make_unique(resourceManagementMock)); ASSERT_THAT(model->imports(), UnorderedElementsAreArray(imports)); } @@ -645,7 +647,8 @@ TEST_F(Model_ResourceManagment, TEST_F(Model_ResourceManagment, by_default_remove_model_node_removes_node) { - QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock}, "QtQuick.Item"}; + QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "QtQuick.Item"}; NiceMock viewMock; newModel.attachView(&viewMock); auto node = createNodeWithParent(viewMock.rootModelNode()); @@ -657,7 +660,8 @@ TEST_F(Model_ResourceManagment, by_default_remove_model_node_removes_node) TEST_F(Model_ResourceManagment, by_default_remove_properties_removes_property) { - QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock}, "QtQuick.Item"}; + QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "QtQuick.Item"}; NiceMock viewMock; newModel.attachView(&viewMock); rootNode = viewMock.rootModelNode(); @@ -671,7 +675,9 @@ TEST_F(Model_ResourceManagment, by_default_remove_properties_removes_property) TEST_F(Model_ResourceManagment, by_default_remove_model_node_in_factory_method_calls_removes_node) { model.detachView(&viewMock); - auto newModel = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, + auto newModel = QmlDesigner::Model::create({projectStorageMock, + pathCacheMock, + projectStorageTriggerUpdateMock}, "Item", imports, pathCacheMock.path.toQString()); @@ -686,7 +692,9 @@ TEST_F(Model_ResourceManagment, by_default_remove_model_node_in_factory_method_c TEST_F(Model_ResourceManagment, by_default_remove_properties_in_factory_method_calls_remove_property) { model.detachView(&viewMock); - auto newModel = QmlDesigner::Model::create({projectStorageMock, pathCacheMock}, + auto newModel = QmlDesigner::Model::create({projectStorageMock, + pathCacheMock, + projectStorageTriggerUpdateMock}, "Item", imports, pathCacheMock.path.toQString()); @@ -780,7 +788,8 @@ TEST_F(Model_ResourceManagment, remove_model_nodes_bypasses_model_resource_manag TEST_F(Model_ResourceManagment, by_default_remove_model_nodes_in_factory_method_calls_removes_node) { - QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock}, "QtQuick.Item"}; + QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "QtQuick.Item"}; NiceMock viewMock; newModel.attachView(&viewMock); rootNode = viewMock.rootModelNode(); @@ -874,7 +883,8 @@ TEST_F(Model_ResourceManagment, remove_properties_bypasses_model_resource_manage TEST_F(Model_ResourceManagment, by_default_remove_properties_in_factory_method_calls_removes_properties) { model.detachView(&viewMock); - QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock}, "QtQuick.Item"}; + QmlDesigner::Model newModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "QtQuick.Item"}; newModel.attachView(&viewMock); rootNode = viewMock.rootModelNode(); auto property = createProperty(rootNode, "yi"); @@ -1056,6 +1066,18 @@ TEST_F(Model_Node, create_qualified_model_node_has_meta_info) ASSERT_THAT(node.metaInfo(), model.qtQmlModelsListModelMetaInfo()); } +TEST_F(Model_Node, change_node_type_changes_meta_info) +{ + projectStorageMock.createImportedTypeNameId(filePathId, + "QtObject", + model.qmlQtObjectMetaInfo().id()); + auto node = model.createModelNode("Item"); + + node.changeType("QtObject"); + + ASSERT_THAT(node.metaInfo(), model.qmlQtObjectMetaInfo()); +} + TEST_F(Model_Node, change_root_node_type_changes_meta_info) { projectStorageMock.createImportedTypeNameId(filePathId, @@ -1127,18 +1149,38 @@ TEST_F(Model_MetaInfo, get_invalid_meta_info_by_module_for_wrong_module) ASSERT_THAT(metaInfo, IsFalse()); } +TEST_F(Model_MetaInfo, get_module_ids_that_starts_with) +{ + ON_CALL(projectStorageMock, moduleIdsStartsWith(Eq("Q"), ModuleKind::QmlLibrary)) + .WillByDefault(Return(QmlDesigner::SmallModuleIds<128>{qtQuickModuleId})); + + auto moduleIds = model.moduleIdsStartsWith("Q", ModuleKind::QmlLibrary); + + ASSERT_THAT(moduleIds, Contains(qtQuickModuleId)); +} + TEST_F(Model_MetaInfo, add_project_storage_observer_to_project_storage) { EXPECT_CALL(projectStorageMock, addObserver(_)); - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + -1, + -1, + nullptr, + {}}; } TEST_F(Model_MetaInfo, remove_project_storage_observer_from_project_storage) { EXPECT_CALL(projectStorageMock, removeObserver(_)).Times(2); // the fixture model is calling it too - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + -1, + -1, + nullptr, + {}}; } TEST_F(Model_MetaInfo, refresh_meta_infos_callback_is_calling_abstract_view) @@ -1148,7 +1190,12 @@ TEST_F(Model_MetaInfo, refresh_meta_infos_callback_is_calling_abstract_view) ProjectStorageObserverMock observerMock; QmlDesigner::ProjectStorageObserver *observer = nullptr; ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; }); - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + -1, + -1, + nullptr, + {}}; model.attachView(&viewMock); EXPECT_CALL(viewMock, refreshMetaInfos(typeIds)); @@ -1163,7 +1210,12 @@ TEST_F(Model_MetaInfo, added_exported_type_names_are_changed_callback_is_calling ProjectStorageObserverMock observerMock; QmlDesigner::ProjectStorageObserver *observer = nullptr; ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; }); - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + -1, + -1, + nullptr, + {}}; model.attachView(&viewMock); EXPECT_CALL(viewMock, exportedTypeNamesChanged(added, IsEmpty())); @@ -1178,7 +1230,12 @@ TEST_F(Model_MetaInfo, removed_exported_type_names_are_changed_callback_is_calli ProjectStorageObserverMock observerMock; QmlDesigner::ProjectStorageObserver *observer = nullptr; ON_CALL(projectStorageMock, addObserver(_)).WillByDefault([&](auto *o) { observer = o; }); - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, "Item", -1, -1, nullptr, {}}; + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, + "Item", + -1, + -1, + nullptr, + {}}; model.attachView(&viewMock); EXPECT_CALL(viewMock, exportedTypeNamesChanged(IsEmpty(), removed)); @@ -1298,6 +1355,67 @@ TEST_F(Model_TypeAnnotation, item_library_entries) ElementsAre(u"/extra/file/path")))); } +TEST_F(Model_TypeAnnotation, directory_imports_item_library_entries) +{ + using namespace Qt::StringLiterals; + QmlDesigner::Storage::Info::ItemLibraryEntries storageEntries{{itemTypeId, + "Item", + "Item", + "/path/to/icon", + "basic category", + "QtQuick", + "It's a item", + "/path/to/template"}}; + storageEntries.front().properties.emplace_back("x", "double", Sqlite::ValueView::create(1)); + storageEntries.front().extraFilePaths.emplace_back("/extra/file/path"); + projectStorageMock.setDirectoryImportsItemLibraryEntries(pathCacheMock.sourceId, storageEntries); + + auto entries = model.directoryImportsItemLibraryEntries(); + + ASSERT_THAT(entries, + ElementsAre( + IsItemLibraryEntry(itemTypeId, + "Item", + u"Item", + u"/path/to/icon", + u"basic category", + u"QtQuick", + u"It's a item", + u"/path/to/template", + ElementsAre(IsItemLibraryProperty("x", "double"_L1, QVariant{1})), + ElementsAre(u"/extra/file/path")))); +} +TEST_F(Model_TypeAnnotation, all_item_library_entries) +{ + using namespace Qt::StringLiterals; + QmlDesigner::Storage::Info::ItemLibraryEntries storageEntries{{itemTypeId, + "Item", + "Item", + "/path/to/icon", + "basic category", + "QtQuick", + "It's a item", + "/path/to/template"}}; + storageEntries.front().properties.emplace_back("x", "double", Sqlite::ValueView::create(1)); + storageEntries.front().extraFilePaths.emplace_back("/extra/file/path"); + ON_CALL(projectStorageMock, allItemLibraryEntries()).WillByDefault(Return(storageEntries)); + + auto entries = model.allItemLibraryEntries(); + + ASSERT_THAT(entries, + ElementsAre( + IsItemLibraryEntry(itemTypeId, + "Item", + u"Item", + u"/path/to/icon", + u"basic category", + u"QtQuick", + u"It's a item", + u"/path/to/template", + ElementsAre(IsItemLibraryProperty("x", "double"_L1, QVariant{1})), + ElementsAre(u"/extra/file/path")))); +} + class Model_ViewManagement : public Model { protected: @@ -1355,7 +1473,7 @@ TEST_F(Model_ViewManagement, dont_call_modelAttached_if_node_instance_view_is_al TEST_F(Model_ViewManagement, detach_node_instance_view_from_other_model_before_attach_to_new_model) { InSequence s; - QmlDesigner::Model otherModel{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model otherModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", imports, fileUrl, @@ -1401,7 +1519,7 @@ TEST_F(Model_ViewManagement, attach_view_is_not_calling_modelAttached_if_it_is_a TEST_F(Model_ViewManagement, view_is_detached_before_it_is_attached_ot_new_model) { InSequence s; - QmlDesigner::Model otherModel{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model otherModel{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", imports, fileUrl, diff --git a/tests/unit/tests/unittests/model/modelnode-test.cpp b/tests/unit/tests/unittests/model/modelnode-test.cpp index 61d81f6178f..9214f24d4da 100644 --- a/tests/unit/tests/unittests/model/modelnode-test.cpp +++ b/tests/unit/tests/unittests/model/modelnode-test.cpp @@ -4,6 +4,7 @@ #include "../utils/googletest.h" #include "../mocks/projectstoragemock.h" +#include "../mocks/projectstoragetriggerupdatemock.h" #include "../mocks/sourcepathcachemock.h" #include @@ -15,9 +16,10 @@ namespace { class ModelNode : public testing::Test { protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCache{"/path/foo.qml"}; NiceMock projectStorageMock{pathCache.sourceId, "/path"}; - QmlDesigner::Model model{{projectStorageMock, pathCache}, "Item"}; + QmlDesigner::Model model{{projectStorageMock, pathCache, projectStorageTriggerUpdateMock}, "Item"}; QmlDesigner::ModelNode rootNode = model.rootModelNode(); }; diff --git a/tests/unit/tests/unittests/model/modelresourcemanagement-test.cpp b/tests/unit/tests/unittests/model/modelresourcemanagement-test.cpp index b020c7cfd0d..dea3501843e 100644 --- a/tests/unit/tests/unittests/model/modelresourcemanagement-test.cpp +++ b/tests/unit/tests/unittests/model/modelresourcemanagement-test.cpp @@ -6,6 +6,7 @@ #include "../mocks/abstractviewmock.h" #include "../mocks/modelresourcemanagementmock.h" #include "../mocks/projectstoragemock.h" +#include "../mocks/projectstoragetriggerupdatemock.h" #include "../mocks/sourcepathcachemock.h" #include @@ -71,10 +72,11 @@ protected: protected: NiceMock viewMock; + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCacheMock{"/path/foo.qml"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; QmlDesigner::ModelResourceManagement management; - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", {QmlDesigner::Import::createLibraryImport("QtQtuick")}, QUrl::fromLocalFile(pathCacheMock.path.toQString())}; diff --git a/tests/unit/tests/unittests/model/nodelistproperty-test.cpp b/tests/unit/tests/unittests/model/nodelistproperty-test.cpp index 023126f0f70..72df3f52365 100644 --- a/tests/unit/tests/unittests/model/nodelistproperty-test.cpp +++ b/tests/unit/tests/unittests/model/nodelistproperty-test.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -73,11 +74,13 @@ protected: } protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock pathCache{"/path/foo.qml"}; NiceMock projectStorageMock{pathCache.sourceId, "/path"}; QmlDesigner::ModelPointer model{ QmlDesigner::Model::create(QmlDesigner::ProjectStorageDependencies{projectStorageMock, - pathCache}, + pathCache, + projectStorageTriggerUpdateMock}, "Item", {QmlDesigner::Import::createLibraryImport("QtQuick")}, QUrl::fromLocalFile(pathCache.path.toQString()))}; diff --git a/tests/unit/tests/unittests/model/rewriterview-test.cpp b/tests/unit/tests/unittests/model/rewriterview-test.cpp index 8c62accd1d8..f2dbd028123 100644 --- a/tests/unit/tests/unittests/model/rewriterview-test.cpp +++ b/tests/unit/tests/unittests/model/rewriterview-test.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -26,13 +27,14 @@ protected: ~RewriterView() { model.setRewriterView(nullptr); } protected: + NiceMock projectStorageTriggerUpdateMock; NiceMock externalDependenciesMock; NiceMock textModifierMock; NiceMock pathCacheMock{"/path/foo.qml"}; NiceMock projectStorageMock{pathCacheMock.sourceId, "/path"}; NiceMock resourceManagementMock; QmlDesigner::Imports imports = {QmlDesigner::Import::createLibraryImport("QtQuick")}; - QmlDesigner::Model model{{projectStorageMock, pathCacheMock}, + QmlDesigner::Model model{{projectStorageMock, pathCacheMock, projectStorageTriggerUpdateMock}, "Item", imports, QUrl::fromLocalFile(pathCacheMock.path.toQString()), diff --git a/tests/unit/tests/unittests/projectstorage/directorypathcompressor-test.cpp b/tests/unit/tests/unittests/projectstorage/directorypathcompressor-test.cpp index 44ef11cbe4b..c42c3d29d5c 100644 --- a/tests/unit/tests/unittests/projectstorage/directorypathcompressor-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/directorypathcompressor-test.cpp @@ -12,8 +12,8 @@ namespace { -using QmlDesigner::SourceContextId; -using QmlDesigner::SourceContextIds; +using QmlDesigner::DirectoryPathId; +using QmlDesigner::DirectoryPathIds; class DirectoryPathCompressor : public testing::Test { @@ -21,61 +21,61 @@ protected: void SetUp() { compressor.setCallback(mockCompressorCallback.AsStdFunction()); } protected: - NiceMock> mockCompressorCallback; + NiceMock> mockCompressorCallback; QmlDesigner::DirectoryPathCompressor> compressor; NiceMock &mockTimer = compressor.timer(); - SourceContextId sourceContextId1{SourceContextId::create(1)}; - SourceContextId sourceContextId2{SourceContextId::create(2)}; + DirectoryPathId directoryPathId1{DirectoryPathId::create(1)}; + DirectoryPathId directoryPathId2{DirectoryPathId::create(2)}; }; TEST_F(DirectoryPathCompressor, add_file_path) { - compressor.addSourceContextId(sourceContextId1); + compressor.addDirectoryPathId(directoryPathId1); - ASSERT_THAT(compressor.sourceContextIds(), ElementsAre(sourceContextId1)); + ASSERT_THAT(compressor.directoryPathIds(), ElementsAre(directoryPathId1)); } TEST_F(DirectoryPathCompressor, clear__after_calling_callback) { - compressor.addSourceContextId(sourceContextId1); + compressor.addDirectoryPathId(directoryPathId1); compressor.timer().emitTimoutIfStarted(); - ASSERT_THAT(compressor.sourceContextIds(), IsEmpty()); + ASSERT_THAT(compressor.directoryPathIds(), IsEmpty()); } TEST_F(DirectoryPathCompressor, dont_clear_for_thrown_exception) { - compressor.addSourceContextId(sourceContextId1); - compressor.setCallback([](const SourceContextIds &) { throw std::exception{}; }); + compressor.addDirectoryPathId(directoryPathId1); + compressor.setCallback([](const DirectoryPathIds &) { throw std::exception{}; }); compressor.timer().emitTimoutIfStarted(); - ASSERT_THAT(compressor.sourceContextIds(), ElementsAre(sourceContextId1)); + ASSERT_THAT(compressor.directoryPathIds(), ElementsAre(directoryPathId1)); } TEST_F(DirectoryPathCompressor, call_restart_timer_after_adding_path) { EXPECT_CALL(mockTimer, start(20)); - compressor.addSourceContextId(sourceContextId1); + compressor.addDirectoryPathId(directoryPathId1); } TEST_F(DirectoryPathCompressor, call_time_out_after_adding_path) { - EXPECT_CALL(mockCompressorCallback, Call(ElementsAre(sourceContextId1, sourceContextId2))); + EXPECT_CALL(mockCompressorCallback, Call(ElementsAre(directoryPathId1, directoryPathId2))); - compressor.addSourceContextId(sourceContextId1); - compressor.addSourceContextId(sourceContextId2); + compressor.addDirectoryPathId(directoryPathId1); + compressor.addDirectoryPathId(directoryPathId2); } TEST_F(DirectoryPathCompressor, remove_duplicates) { - EXPECT_CALL(mockCompressorCallback, Call(ElementsAre(sourceContextId1, sourceContextId2))); + EXPECT_CALL(mockCompressorCallback, Call(ElementsAre(directoryPathId1, directoryPathId2))); - compressor.addSourceContextId(sourceContextId1); - compressor.addSourceContextId(sourceContextId2); - compressor.addSourceContextId(sourceContextId1); + compressor.addDirectoryPathId(directoryPathId1); + compressor.addDirectoryPathId(directoryPathId2); + compressor.addDirectoryPathId(directoryPathId1); } } // namespace diff --git a/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp b/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp index b948fb91ce1..aab9d2ff473 100644 --- a/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/projectstorage-test.cpp @@ -24,11 +24,11 @@ using QmlDesigner::FileStatuses; using QmlDesigner::FlagIs; using QmlDesigner::ModuleId; using QmlDesigner::PropertyDeclarationId; -using QmlDesigner::SourceContextId; -using QmlDesigner::SourceContextIds; +using QmlDesigner::DirectoryPathId; +using QmlDesigner::DirectoryPathIds; using QmlDesigner::SourceId; using QmlDesigner::SourceIds; -using QmlDesigner::SourceNameId; +using QmlDesigner::FileNameId; using QmlDesigner::Storage::ModuleKind; using QmlDesigner::Storage::Synchronization::SynchronizationPackage; using QmlDesigner::Storage::Synchronization::TypeAnnotations; @@ -1070,16 +1070,16 @@ protected: package.propertyEditorQmlPaths.emplace_back(qtQuickModuleId, "QtObject", sourceId1, - sourceContextIdPath6); + directoryPathIdPath6); package.propertyEditorQmlPaths.emplace_back(qtQuickModuleId, "Item", sourceId2, - sourceContextIdPath6); + directoryPathIdPath6); package.propertyEditorQmlPaths.emplace_back(qtQuickModuleId, "Item3D", sourceId3, - sourceContextIdPath6); - package.updatedPropertyEditorQmlPathDirectoryIds.emplace_back(sourceContextIdPath6); + directoryPathIdPath6); + package.updatedPropertyEditorQmlPathDirectoryIds.emplace_back(directoryPathIdPath6); return package; } @@ -1093,7 +1093,7 @@ protected: traits.visibleInLibrary = FlagIs::True; annotations.emplace_back(sourceId4, - sourceContextIdPath6, + directoryPathIdPath6, "Object", qmlModuleId, "/path/to/icon.png", @@ -1115,7 +1115,7 @@ protected: "properties":[["color", "color", "#blue"]]}])xy"); annotations.emplace_back(sourceId5, - sourceContextIdPath6, + directoryPathIdPath6, "Item", qtQuickModuleId, "/path/to/quick.png", @@ -1140,7 +1140,7 @@ protected: traits.visibleInLibrary = FlagIs::True; annotations.emplace_back(sourceId5, - sourceContextIdPath1, + directoryPathIdPath1, "Item", qtQuickModuleId, "/path/to/quick.png", @@ -1253,13 +1253,13 @@ protected: SourceId sourceId5{sourcePathCache.sourceId(path5)}; SourceId sourceId6{sourcePathCache.sourceId(path6)}; SourceId sourceIdPath1{sourcePathCache.sourceId(pathPath1)}; - SourceContextId sourceContextIdPath1{sourceIdPath1.contextId()}; + DirectoryPathId directoryPathIdPath1{sourceIdPath1.directoryPathId()}; SourceId sourceIdPath6{sourcePathCache.sourceId(pathPath6)}; - SourceContextId sourceContextIdPath6{sourceIdPath6.contextId()}; + DirectoryPathId directoryPathIdPath6{sourceIdPath6.directoryPathId()}; SourceId qmlProjectSourceId{sourcePathCache.sourceId("/path1/qmldir")}; - SourceContextId qmlProjectSourceContextId = qmlProjectSourceId.contextId(); + DirectoryPathId qmlProjectDirectoryPathId = qmlProjectSourceId.directoryPathId(); SourceId qtQuickProjectSourceId{sourcePathCache.sourceId("/path2/qmldir")}; - SourceContextId qtQuickProjectSourceContextId = qtQuickProjectSourceId.contextId(); + DirectoryPathId qtQuickProjectDirectoryPathId = qtQuickProjectSourceId.directoryPathId(); ModuleId qmlModuleId{storage.moduleId("Qml", ModuleKind::QmlLibrary)}; ModuleId qmlNativeModuleId{storage.moduleId("Qml", ModuleKind::CppLibrary)}; ModuleId qtQuickModuleId{storage.moduleId("QtQuick", ModuleKind::QmlLibrary)}; @@ -5827,284 +5827,308 @@ TEST_F(ProjectStorage, populate_module_cache) ASSERT_THAT(newStorage.module(id), IsModule("Qml", ModuleKind::QmlLibrary)); } +TEST_F(ProjectStorage, get_no_module_ids_if_they_starts_with_nothing) +{ + storage.moduleId("QtQml", ModuleKind::QmlLibrary); + + auto ids = storage.moduleIdsStartsWith("", ModuleKind::QmlLibrary); + + ASSERT_THAT(ids, IsEmpty()); +} + +TEST_F(ProjectStorage, get_module_ids_if_they_starts_with_New) +{ + auto quickId = storage.moduleId("NewQuick", ModuleKind::QmlLibrary); + storage.moduleId("NewQuick", ModuleKind::CppLibrary); + auto quick3dId = storage.moduleId("NewQuick3D", ModuleKind::QmlLibrary); + storage.moduleId("NewQml", ModuleKind::CppLibrary); + auto qmlId = storage.moduleId("NewQml", ModuleKind::QmlLibrary); + storage.moduleId("Foo", ModuleKind::QmlLibrary); + storage.moduleId("Zoo", ModuleKind::QmlLibrary); + + auto ids = storage.moduleIdsStartsWith("New", ModuleKind::QmlLibrary); + + ASSERT_THAT(ids, UnorderedElementsAre(qmlId, quickId, quick3dId)); +} + TEST_F(ProjectStorage, add_directory_infoes) { - Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectDirectoryPathId, sourceId1, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectDirectoryPathId, sourceId2, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectDirectoryPathId, sourceId3, qtQuickModuleId, Storage::Synchronization::FileType::QmlTypes}; storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId, qtQuickProjectSourceContextId}, + SynchronizationPackage{{qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}, {directoryInfo1, directoryInfo2, directoryInfo3}}); - ASSERT_THAT(storage.fetchDirectoryInfos({qmlProjectSourceContextId, qtQuickProjectSourceContextId}), + ASSERT_THAT(storage.fetchDirectoryInfos({qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}), UnorderedElementsAre(directoryInfo1, directoryInfo2, directoryInfo3)); } TEST_F(ProjectStorage, remove_directory_info) { - Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectDirectoryPathId, sourceId1, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectDirectoryPathId, sourceId2, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectDirectoryPathId, sourceId3, qtQuickModuleId, Storage::Synchronization::FileType::QmlTypes}; storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId, qtQuickProjectSourceContextId}, + SynchronizationPackage{{qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}, {directoryInfo1, directoryInfo2, directoryInfo3}}); storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId, qtQuickProjectSourceContextId}, + SynchronizationPackage{{qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}, {directoryInfo1}}); - ASSERT_THAT(storage.fetchDirectoryInfos({qmlProjectSourceContextId, qtQuickProjectSourceContextId}), + ASSERT_THAT(storage.fetchDirectoryInfos({qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}), UnorderedElementsAre(directoryInfo1)); } TEST_F(ProjectStorage, update_directory_info_file_type) { - Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectDirectoryPathId, sourceId1, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectDirectoryPathId, sourceId2, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo2b{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo2b{qmlProjectDirectoryPathId, sourceId2, qmlModuleId, Storage::Synchronization::FileType::QmlTypes}; - Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectDirectoryPathId, sourceId3, qtQuickModuleId, Storage::Synchronization::FileType::QmlTypes}; storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId, qtQuickProjectSourceContextId}, + SynchronizationPackage{{qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}, {directoryInfo1, directoryInfo2, directoryInfo3}}); storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId}, {directoryInfo1, directoryInfo2b}}); + SynchronizationPackage{{qmlProjectDirectoryPathId}, {directoryInfo1, directoryInfo2b}}); - ASSERT_THAT(storage.fetchDirectoryInfos({qmlProjectSourceContextId, qtQuickProjectSourceContextId}), + ASSERT_THAT(storage.fetchDirectoryInfos({qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}), UnorderedElementsAre(directoryInfo1, directoryInfo2b, directoryInfo3)); } TEST_F(ProjectStorage, update_directory_info_module_id) { - Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectDirectoryPathId, sourceId1, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectDirectoryPathId, sourceId3, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo2b{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo2b{qmlProjectDirectoryPathId, sourceId3, qtQuickModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectDirectoryPathId, sourceId2, qtQuickModuleId, Storage::Synchronization::FileType::QmlTypes}; storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId, qtQuickProjectSourceContextId}, + SynchronizationPackage{{qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}, {directoryInfo1, directoryInfo2, directoryInfo3}}); storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId}, {directoryInfo1, directoryInfo2b}}); + SynchronizationPackage{{qmlProjectDirectoryPathId}, {directoryInfo1, directoryInfo2b}}); - ASSERT_THAT(storage.fetchDirectoryInfos({qmlProjectSourceContextId, qtQuickProjectSourceContextId}), + ASSERT_THAT(storage.fetchDirectoryInfos({qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}), UnorderedElementsAre(directoryInfo1, directoryInfo2b, directoryInfo3)); } TEST_F(ProjectStorage, throw_for_invalid_source_id_in_directory_info) { - Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectDirectoryPathId, SourceId{}, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; ASSERT_THROW(storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId}, {directoryInfo1}}), + SynchronizationPackage{{qmlProjectDirectoryPathId}, {directoryInfo1}}), QmlDesigner::DirectoryInfoHasInvalidSourceId); } TEST_F(ProjectStorage, insert_directory_info_with_invalid_module_id) { - Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectDirectoryPathId, sourceId1, ModuleId{}, Storage::Synchronization::FileType::QmlDocument}; - storage.synchronize(SynchronizationPackage{{qmlProjectSourceContextId}, {directoryInfo1}}); + storage.synchronize(SynchronizationPackage{{qmlProjectDirectoryPathId}, {directoryInfo1}}); - ASSERT_THAT(storage.fetchDirectoryInfos({qmlProjectSourceContextId, qtQuickProjectSourceContextId}), + ASSERT_THAT(storage.fetchDirectoryInfos({qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}), UnorderedElementsAre(directoryInfo1)); } TEST_F(ProjectStorage, update_directory_info_with_invalid_module_id) { - Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectDirectoryPathId, sourceId1, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - storage.synchronize(SynchronizationPackage{{qmlProjectSourceContextId}, {directoryInfo1}}); + storage.synchronize(SynchronizationPackage{{qmlProjectDirectoryPathId}, {directoryInfo1}}); directoryInfo1.moduleId = ModuleId{}; - storage.synchronize(SynchronizationPackage{{qmlProjectSourceContextId}, {directoryInfo1}}); + storage.synchronize(SynchronizationPackage{{qmlProjectDirectoryPathId}, {directoryInfo1}}); - ASSERT_THAT(storage.fetchDirectoryInfos({qmlProjectSourceContextId, qtQuickProjectSourceContextId}), + ASSERT_THAT(storage.fetchDirectoryInfos({qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}), UnorderedElementsAre(directoryInfo1)); } -TEST_F(ProjectStorage, throw_for_updating_with_invalid_project_source_context_id_in_directory_info) +TEST_F(ProjectStorage, throw_for_updating_with_invalid_project_directory_path_id_in_directory_info) { Storage::Synchronization::DirectoryInfo directoryInfo1{ - SourceContextId{}, sourceId1, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; + DirectoryPathId{}, sourceId1, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; ASSERT_THROW(storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId}, {directoryInfo1}}), + SynchronizationPackage{{qmlProjectDirectoryPathId}, {directoryInfo1}}), QmlDesigner::DirectoryInfoHasInvalidProjectSourceId); } -TEST_F(ProjectStorage, fetch_directory_infos_by_directory_source_context_ids) +TEST_F(ProjectStorage, fetch_directory_infos_by_directory_directory_path_ids) { - Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectDirectoryPathId, sourceId1, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectDirectoryPathId, sourceId2, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectDirectoryPathId, sourceId3, qtQuickModuleId, Storage::Synchronization::FileType::QmlTypes}; storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId, qtQuickProjectSourceContextId}, + SynchronizationPackage{{qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}, {directoryInfo1, directoryInfo2, directoryInfo3}}); auto directoryInfos = storage.fetchDirectoryInfos( - {qmlProjectSourceContextId, qtQuickProjectSourceContextId}); + {qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}); ASSERT_THAT(directoryInfos, UnorderedElementsAre(directoryInfo1, directoryInfo2, directoryInfo3)); } -TEST_F(ProjectStorage, fetch_directory_infos_by_directory_source_context_id) +TEST_F(ProjectStorage, fetch_directory_infos_by_directory_directory_path_id) { - Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectDirectoryPathId, sourceId1, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectDirectoryPathId, sourceId2, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectDirectoryPathId, sourceId3, qtQuickModuleId, Storage::Synchronization::FileType::QmlTypes}; storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId, qtQuickProjectSourceContextId}, + SynchronizationPackage{{qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}, {directoryInfo1, directoryInfo2, directoryInfo3}}); - auto directoryInfo = storage.fetchDirectoryInfos(qmlProjectSourceContextId); + auto directoryInfo = storage.fetchDirectoryInfos(qmlProjectDirectoryPathId); ASSERT_THAT(directoryInfo, UnorderedElementsAre(directoryInfo1, directoryInfo2)); } -TEST_F(ProjectStorage, fetch_directory_infos_by_directory_source_context_id_and_file_type) +TEST_F(ProjectStorage, fetch_directory_infos_by_directory_directory_path_id_and_file_type) { - Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectDirectoryPathId, sourceId1, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectDirectoryPathId, sourceId2, ModuleId{}, Storage::Synchronization::FileType::Directory}; - Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectDirectoryPathId, sourceId3, qtQuickModuleId, Storage::Synchronization::FileType::QmlTypes}; - Storage::Synchronization::DirectoryInfo directoryInfo4{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo4{qmlProjectDirectoryPathId, sourceId4, ModuleId{}, Storage::Synchronization::FileType::Directory}; storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId, qtQuickProjectSourceContextId}, + SynchronizationPackage{{qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}, {directoryInfo1, directoryInfo2, directoryInfo3, directoryInfo4}}); - auto directoryInfo = storage.fetchDirectoryInfos(qmlProjectSourceContextId, + auto directoryInfo = storage.fetchDirectoryInfos(qmlProjectDirectoryPathId, Storage::Synchronization::FileType::Directory); ASSERT_THAT(directoryInfo, UnorderedElementsAre(directoryInfo2, directoryInfo4)); } -TEST_F(ProjectStorage, fetch_subdirectory_source_context_ids) +TEST_F(ProjectStorage, fetch_subdirectory_directory_path_ids) { - Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectDirectoryPathId, sourceId1, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - auto directory1Id = SourceId::create(SourceNameId{}, sourceId2.contextId()); - Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectSourceContextId, + auto directory1Id = SourceId::create(sourceId2.directoryPathId(), FileNameId{}); + Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectDirectoryPathId, directory1Id, ModuleId{}, Storage::Synchronization::FileType::Directory}; - Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectDirectoryPathId, sourceId3, qtQuickModuleId, Storage::Synchronization::FileType::QmlTypes}; - auto directory2Id = SourceId::create(SourceNameId{}, sourceId4.contextId()); - Storage::Synchronization::DirectoryInfo directoryInfo4{qmlProjectSourceContextId, + auto directory2Id = SourceId::create(sourceId4.directoryPathId(), FileNameId{}); + Storage::Synchronization::DirectoryInfo directoryInfo4{qmlProjectDirectoryPathId, directory2Id, ModuleId{}, Storage::Synchronization::FileType::Directory}; storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId, qtQuickProjectSourceContextId}, + SynchronizationPackage{{qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}, {directoryInfo1, directoryInfo2, directoryInfo3, directoryInfo4}}); - auto directoryInfo = storage.fetchSubdirectoryIds(qmlProjectSourceContextId); + auto directoryInfo = storage.fetchSubdirectoryIds(qmlProjectDirectoryPathId); ASSERT_THAT(directoryInfo, - UnorderedElementsAre(directory1Id.contextId(), directory2Id.contextId())); + UnorderedElementsAre(directory1Id.directoryPathId(), directory2Id.directoryPathId())); } TEST_F(ProjectStorage, fetch_directory_info_by_source_id) { - Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo1{qmlProjectDirectoryPathId, sourceId1, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo2{qmlProjectDirectoryPathId, sourceId2, qmlModuleId, Storage::Synchronization::FileType::QmlDocument}; - Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectSourceContextId, + Storage::Synchronization::DirectoryInfo directoryInfo3{qtQuickProjectDirectoryPathId, sourceId3, qtQuickModuleId, Storage::Synchronization::FileType::QmlTypes}; storage.synchronize( - SynchronizationPackage{{qmlProjectSourceContextId, qtQuickProjectSourceContextId}, + SynchronizationPackage{{qmlProjectDirectoryPathId, qtQuickProjectDirectoryPathId}, {directoryInfo1, directoryInfo2, directoryInfo3}}); auto directoryInfo = storage.fetchDirectoryInfo(sourceId2); @@ -8295,7 +8319,7 @@ TEST_F(ProjectStorage, synchronize_property_editor_adds_path) package.propertyEditorQmlPaths.emplace_back(qtQuickModuleId, "Item3D", sourceId3, - sourceContextIdPath6); + directoryPathIdPath6); storage.synchronize(package); @@ -8310,7 +8334,7 @@ TEST_F(ProjectStorage, synchronize_property_editor_with_non_existing_type_name) package.propertyEditorQmlPaths.emplace_back(qtQuickModuleId, "Item4D", sourceId4, - sourceContextIdPath6); + directoryPathIdPath6); storage.synchronize(package); @@ -8675,7 +8699,7 @@ TEST_F(ProjectStorage, synchronize_type_annotation_directory_source_id) storage.synchronize(package); - ASSERT_THAT(storage.typeAnnotationSourceIds(sourceContextIdPath6), + ASSERT_THAT(storage.typeAnnotationSourceIds(directoryPathIdPath6), UnorderedElementsAre(sourceId4, sourceId5)); } @@ -8687,7 +8711,7 @@ TEST_F(ProjectStorage, get_type_annotation_source_ids) package.typeAnnotations); storage.synchronize(package); - auto sourceIds = storage.typeAnnotationSourceIds(sourceContextIdPath6); + auto sourceIds = storage.typeAnnotationSourceIds(directoryPathIdPath6); ASSERT_THAT(sourceIds, UnorderedElementsAre(sourceId4, sourceId5)); } @@ -8702,7 +8726,7 @@ TEST_F(ProjectStorage, get_type_annotation_directory_source_ids) auto sourceIds = storage.typeAnnotationDirectoryIds(); - ASSERT_THAT(sourceIds, ElementsAre(sourceContextIdPath1, sourceContextIdPath6)); + ASSERT_THAT(sourceIds, ElementsAre(directoryPathIdPath1, directoryPathIdPath6)); } TEST_F(ProjectStorage, get_all_item_library_entries) @@ -8890,14 +8914,14 @@ TEST_F(ProjectStorage, get_item_library_entries_by_source_id) IsEmpty()))); } -TEST_F(ProjectStorage, get_local_file_item_library_entries_by_source_id) +TEST_F(ProjectStorage, get_directory_imports_item_library_entries_by_source_id) { auto package{createSimpleSynchronizationPackage()}; package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2); package.types[1].exportedTypes.emplace_back(pathToModuleId, "Object"); storage.synchronize(package); - auto entries = storage.itemLibraryEntries(sourceId2); + auto entries = storage.directoryImportsItemLibraryEntries(sourceId2); ASSERT_THAT(entries, UnorderedElementsAre(IsItemLibraryEntry(fetchTypeId(sourceId2, "QObject"), diff --git a/tests/unit/tests/unittests/projectstorage/projectstoragepathwatcher-test.cpp b/tests/unit/tests/unittests/projectstorage/projectstoragepathwatcher-test.cpp index ac591b8c909..a4b67aa7efb 100644 --- a/tests/unit/tests/unittests/projectstorage/projectstoragepathwatcher-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/projectstoragepathwatcher-test.cpp @@ -27,8 +27,8 @@ using QmlDesigner::ProjectChunkId; using QmlDesigner::ProjectChunkIds; using QmlDesigner::ProjectPartId; using QmlDesigner::ProjectPartIds; -using QmlDesigner::SourceContextId; -using QmlDesigner::SourceContextIds; +using QmlDesigner::DirectoryPathId; +using QmlDesigner::DirectoryPathIds; using QmlDesigner::SourceId; using QmlDesigner::SourceIds; using QmlDesigner::SourcePath; @@ -62,11 +62,11 @@ protected: return FileStatus{sourceId, 1, 1}; }); - ON_CALL(mockFileSystem, directoryEntries(Eq(sourceContextPath))) + ON_CALL(mockFileSystem, directoryEntries(Eq(directoryPath))) .WillByDefault(Return(SourceIds{sourceIds[0], sourceIds[1]})); - ON_CALL(mockFileSystem, directoryEntries(Eq(sourceContextPath2))) + ON_CALL(mockFileSystem, directoryEntries(Eq(directoryPath2))) .WillByDefault(Return(SourceIds{sourceIds[2], sourceIds[3]})); - ON_CALL(mockFileSystem, directoryEntries(Eq(sourceContextPath3))) + ON_CALL(mockFileSystem, directoryEntries(Eq(directoryPath3))) .WillByDefault(Return(SourceIds{sourceIds[4]})); } @@ -98,40 +98,40 @@ protected: SourcePathView path5{"/path3/path"}; QString path1QString = QString(path1.toStringView()); QString path2QString = QString(path2.toStringView()); - QString sourceContextPath = "/path"; - QString sourceContextPath2 = "/path2"; - QString sourceContextPath3 = "/path3"; - Utils::PathString sourceContextPathString = sourceContextPath; - Utils::PathString sourceContextPathString2 = sourceContextPath2; + QString directoryPath = "/path"; + QString directoryPath2 = "/path2"; + QString directoryPath3 = "/path3"; + Utils::PathString directoryPathString = directoryPath; + Utils::PathString directoryPathString2 = directoryPath2; SourceIds sourceIds = {pathCache.sourceId(path1), pathCache.sourceId(path2), pathCache.sourceId(path3), pathCache.sourceId(path4), pathCache.sourceId(path5)}; - SourceContextIds sourceContextIds = {sourceIds[0].contextId(), - sourceIds[2].contextId(), - sourceIds[4].contextId()}; + DirectoryPathIds directoryPathIds = {sourceIds[0].directoryPathId(), + sourceIds[2].directoryPathId(), + sourceIds[4].directoryPathId()}; ProjectChunkIds ids{projectChunkId1, projectChunkId2, projectChunkId3}; - WatcherEntry watcherEntry1{projectChunkId1, sourceContextIds[0], sourceIds[0]}; - WatcherEntry watcherEntry2{projectChunkId2, sourceContextIds[0], sourceIds[0]}; - WatcherEntry watcherEntry3{projectChunkId1, sourceContextIds[0], sourceIds[1]}; - WatcherEntry watcherEntry4{projectChunkId2, sourceContextIds[0], sourceIds[1]}; - WatcherEntry watcherEntry5{projectChunkId3, sourceContextIds[0], sourceIds[1]}; - WatcherEntry watcherEntry6{projectChunkId1, sourceContextIds[1], sourceIds[2]}; - WatcherEntry watcherEntry7{projectChunkId2, sourceContextIds[1], sourceIds[3]}; - WatcherEntry watcherEntry8{projectChunkId3, sourceContextIds[1], sourceIds[3]}; - WatcherEntry watcherEntry9{projectChunkId4, sourceContextIds[0], sourceIds[0]}; - WatcherEntry watcherEntry10{projectChunkId4, sourceContextIds[0], sourceIds[1]}; - WatcherEntry watcherEntry11{projectChunkId4, sourceContextIds[1], sourceIds[2]}; - WatcherEntry watcherEntry12{projectChunkId4, sourceContextIds[1], sourceIds[3]}; - WatcherEntry watcherEntry13{projectChunkId4, sourceContextIds[2], sourceIds[4]}; + WatcherEntry watcherEntry1{projectChunkId1, directoryPathIds[0], sourceIds[0]}; + WatcherEntry watcherEntry2{projectChunkId2, directoryPathIds[0], sourceIds[0]}; + WatcherEntry watcherEntry3{projectChunkId1, directoryPathIds[0], sourceIds[1]}; + WatcherEntry watcherEntry4{projectChunkId2, directoryPathIds[0], sourceIds[1]}; + WatcherEntry watcherEntry5{projectChunkId3, directoryPathIds[0], sourceIds[1]}; + WatcherEntry watcherEntry6{projectChunkId1, directoryPathIds[1], sourceIds[2]}; + WatcherEntry watcherEntry7{projectChunkId2, directoryPathIds[1], sourceIds[3]}; + WatcherEntry watcherEntry8{projectChunkId3, directoryPathIds[1], sourceIds[3]}; + WatcherEntry watcherEntry9{projectChunkId4, directoryPathIds[0], sourceIds[0]}; + WatcherEntry watcherEntry10{projectChunkId4, directoryPathIds[0], sourceIds[1]}; + WatcherEntry watcherEntry11{projectChunkId4, directoryPathIds[1], sourceIds[2]}; + WatcherEntry watcherEntry12{projectChunkId4, directoryPathIds[1], sourceIds[3]}; + WatcherEntry watcherEntry13{projectChunkId4, directoryPathIds[2], sourceIds[4]}; }; TEST_F(ProjectStoragePathWatcher, add_id_paths) { EXPECT_CALL(mockQFileSytemWatcher, addPaths( - UnorderedElementsAre(QString(sourceContextPath), QString(sourceContextPath2)))); + UnorderedElementsAre(QString(directoryPath), QString(directoryPath2)))); watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}}, {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}}); @@ -142,7 +142,7 @@ TEST_F(ProjectStoragePathWatcher, update_id_paths_calls_add_path_in_file_watcher watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}}, {projectChunkId2, {sourceIds[0], sourceIds[1]}}}); - EXPECT_CALL(mockQFileSytemWatcher, addPaths(UnorderedElementsAre(QString(sourceContextPath2)))); + EXPECT_CALL(mockQFileSytemWatcher, addPaths(UnorderedElementsAre(QString(directoryPath2)))); watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}}, {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}}); @@ -153,7 +153,7 @@ TEST_F(ProjectStoragePathWatcher, update_id_paths_and_remove_unused_paths_calls_ watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}}, {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}}); - EXPECT_CALL(mockQFileSytemWatcher, removePaths(UnorderedElementsAre(QString(sourceContextPath2)))); + EXPECT_CALL(mockQFileSytemWatcher, removePaths(UnorderedElementsAre(QString(directoryPath2)))); watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}}, {projectChunkId2, {sourceIds[0], sourceIds[1]}}}); @@ -226,7 +226,7 @@ TEST_F(ProjectStoragePathWatcher, add_empty_entries) TEST_F(ProjectStoragePathWatcher, add_entries_with_same_id_and_different_paths) { EXPECT_CALL(mockQFileSytemWatcher, - addPaths(ElementsAre(sourceContextPath, sourceContextPath2, sourceContextPath3))); + addPaths(ElementsAre(directoryPath, directoryPath2, directoryPath3))); watcher.updateIdPaths( {{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[4]}}}); @@ -234,7 +234,7 @@ TEST_F(ProjectStoragePathWatcher, add_entries_with_same_id_and_different_paths) TEST_F(ProjectStoragePathWatcher, add_entries_with_different_id_and_same_paths) { - EXPECT_CALL(mockQFileSytemWatcher, addPaths(ElementsAre(sourceContextPath))); + EXPECT_CALL(mockQFileSytemWatcher, addPaths(ElementsAre(directoryPath))); watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}}}); } @@ -294,7 +294,7 @@ TEST_F(ProjectStoragePathWatcher, remove_path_for_one_id) watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1]}}, {projectChunkId3, {sourceIds[0], sourceIds[1], sourceIds[3]}}}); - EXPECT_CALL(mockQFileSytemWatcher, removePaths(ElementsAre(sourceContextPath2))); + EXPECT_CALL(mockQFileSytemWatcher, removePaths(ElementsAre(directoryPath2))); watcher.removeIds({projectChunkId3.id}); } @@ -316,7 +316,7 @@ TEST_F(ProjectStoragePathWatcher, remove_all_paths_for_three_id) {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}}); EXPECT_CALL(mockQFileSytemWatcher, - removePaths(ElementsAre(sourceContextPath, sourceContextPath2))); + removePaths(ElementsAre(directoryPath, directoryPath2))); watcher.removeIds({projectChunkId1.id, projectChunkId2.id, projectChunkId3.id}); } @@ -327,7 +327,7 @@ TEST_F(ProjectStoragePathWatcher, remove_one_path_for_two_id) {projectChunkId2, {sourceIds[0], sourceIds[1]}}, {projectChunkId3, {sourceIds[3]}}}); - EXPECT_CALL(mockQFileSytemWatcher, removePaths(ElementsAre(sourceContextPath))); + EXPECT_CALL(mockQFileSytemWatcher, removePaths(ElementsAre(directoryPath))); watcher.removeIds({projectChunkId1.id, projectChunkId2.id}); } @@ -374,23 +374,50 @@ TEST_F(ProjectStoragePathWatcher, two_notify_file_changes) ElementsAre(IdPaths{projectChunkId1, {sourceIds[0], sourceIds[1]}}, IdPaths{projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}))); - mockQFileSytemWatcher.directoryChanged(sourceContextPath); - mockQFileSytemWatcher.directoryChanged(sourceContextPath2); + mockQFileSytemWatcher.directoryChanged(directoryPath); + mockQFileSytemWatcher.directoryChanged(directoryPath2); } -TEST_F(ProjectStoragePathWatcher, notify_for_path_changes) +TEST_F(ProjectStoragePathWatcher, notify_for_path_changes_if_modified_time_changes) { watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}}, {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}}); ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[0]))) .WillByDefault(Return(FileStatus{sourceIds[0], 1, 2})); - ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[3]))) .WillByDefault(Return(FileStatus{sourceIds[3], 1, 2})); EXPECT_CALL(notifier, pathsChanged(ElementsAre(sourceIds[0]))); - mockQFileSytemWatcher.directoryChanged(sourceContextPath); + mockQFileSytemWatcher.directoryChanged(directoryPath); +} + +TEST_F(ProjectStoragePathWatcher, notify_for_path_changes_if_size_get_bigger) +{ + watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}}, + {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}}); + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[0]))) + .WillByDefault(Return(FileStatus{sourceIds[0], 2, 1})); + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[3]))) + .WillByDefault(Return(FileStatus{sourceIds[3], 2, 1})); + + EXPECT_CALL(notifier, pathsChanged(ElementsAre(sourceIds[0]))); + + mockQFileSytemWatcher.directoryChanged(directoryPath); +} + +TEST_F(ProjectStoragePathWatcher, notify_for_path_changes_if_size_get_smaller) +{ + watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}}, + {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}}); + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[0]))) + .WillByDefault(Return(FileStatus{sourceIds[0], 0, 1})); + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[3]))) + .WillByDefault(Return(FileStatus{sourceIds[3], 0, 1})); + + EXPECT_CALL(notifier, pathsChanged(ElementsAre(sourceIds[0]))); + + mockQFileSytemWatcher.directoryChanged(directoryPath); } TEST_F(ProjectStoragePathWatcher, no_notify_for_unwatched_path_changes) @@ -399,7 +426,7 @@ TEST_F(ProjectStoragePathWatcher, no_notify_for_unwatched_path_changes) EXPECT_CALL(notifier, pathsChanged(IsEmpty())); - mockQFileSytemWatcher.directoryChanged(sourceContextPath); + mockQFileSytemWatcher.directoryChanged(directoryPath); } TEST_F(ProjectStoragePathWatcher, no_duplicate_path_changes) @@ -411,8 +438,52 @@ TEST_F(ProjectStoragePathWatcher, no_duplicate_path_changes) EXPECT_CALL(notifier, pathsChanged(ElementsAre(sourceIds[0]))); - mockQFileSytemWatcher.directoryChanged(sourceContextPath); - mockQFileSytemWatcher.directoryChanged(sourceContextPath); + mockQFileSytemWatcher.directoryChanged(directoryPath); + mockQFileSytemWatcher.directoryChanged(directoryPath); +} + +TEST_F(ProjectStoragePathWatcher, trigger_manual_two_notify_file_changes) +{ + watcher.updateIdPaths( + {{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}}, + {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3], sourceIds[4]}}, + {projectChunkId3, {sourceIds[4]}}}); + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[0]))) + .WillByDefault(Return(FileStatus{sourceIds[0], 1, 2})); + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[1]))) + .WillByDefault(Return(FileStatus{sourceIds[1], 1, 2})); + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[3]))) + .WillByDefault(Return(FileStatus{sourceIds[3], 1, 2})); + + EXPECT_CALL(notifier, + pathsWithIdsChanged( + ElementsAre(IdPaths{projectChunkId1, {sourceIds[0], sourceIds[1]}}, + IdPaths{projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}))); + + watcher.checkForChangeInDirectory({sourceIds[0].directoryPathId(), sourceIds[2].directoryPathId()}); +} + +TEST_F(ProjectStoragePathWatcher, trigger_manual_notify_for_path_changes) +{ + watcher.updateIdPaths({{projectChunkId1, {sourceIds[0], sourceIds[1], sourceIds[2]}}, + {projectChunkId2, {sourceIds[0], sourceIds[1], sourceIds[3]}}}); + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[0]))) + .WillByDefault(Return(FileStatus{sourceIds[0], 1, 2})); + ON_CALL(mockFileSystem, fileStatus(Eq(sourceIds[3]))) + .WillByDefault(Return(FileStatus{sourceIds[3], 1, 2})); + + EXPECT_CALL(notifier, pathsChanged(ElementsAre(sourceIds[0]))); + + watcher.checkForChangeInDirectory({sourceIds[0].directoryPathId()}); +} + +TEST_F(ProjectStoragePathWatcher, trigger_manual_no_notify_for_unwatched_path_changes) +{ + watcher.updateIdPaths({{projectChunkId1, {sourceIds[3]}}, {projectChunkId2, {sourceIds[3]}}}); + + EXPECT_CALL(notifier, pathsChanged(IsEmpty())); + + watcher.checkForChangeInDirectory({sourceIds[0].directoryPathId()}); } TEST_F(ProjectStoragePathWatcher, update_context_id_paths_adds_entry_in_new_directory) @@ -422,7 +493,7 @@ TEST_F(ProjectStoragePathWatcher, update_context_id_paths_adds_entry_in_new_dire {projectChunkId4, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3]}}, }); - watcher.updateContextIdPaths({{projectChunkId4, {sourceIds[4]}}}, {sourceContextIds[2]}); + watcher.updateContextIdPaths({{projectChunkId4, {sourceIds[4]}}}, {directoryPathIds[2]}); ASSERT_THAT(watcher.watchedEntries(), UnorderedElementsAre(watcherEntry1, @@ -444,7 +515,7 @@ TEST_F(ProjectStoragePathWatcher, update_context_id_paths_adds_entry_to_director watcher.updateContextIdPaths({{projectChunkId4, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3]}}}, - {sourceContextIds[1]}); + {directoryPathIds[1]}); ASSERT_THAT(watcher.watchedEntries(), UnorderedElementsAre(watcherEntry1, @@ -463,7 +534,7 @@ TEST_F(ProjectStoragePathWatcher, update_context_id_paths_removes_entry) {projectChunkId4, {sourceIds[0], sourceIds[1], sourceIds[2], sourceIds[3]}}, }); - watcher.updateContextIdPaths({{projectChunkId4, {sourceIds[3]}}}, {sourceContextIds[1]}); + watcher.updateContextIdPaths({{projectChunkId4, {sourceIds[3]}}}, {directoryPathIds[1]}); ASSERT_THAT(watcher.watchedEntries(), UnorderedElementsAre(watcherEntry1, diff --git a/tests/unit/tests/unittests/projectstorage/projectstorageupdater-test.cpp b/tests/unit/tests/unittests/projectstorage/projectstorageupdater-test.cpp index ed063b5291e..191429fa47a 100644 --- a/tests/unit/tests/unittests/projectstorage/projectstorageupdater-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/projectstorageupdater-test.cpp @@ -19,17 +19,55 @@ #include #include +namespace QmlDesigner { + +static std::string toString(ProjectStorageUpdater::FileState state) +{ + using FileState = ProjectStorageUpdater::FileState; + switch (state) { + case FileState::Added: + return "added"; + case FileState::Changed: + return "changed"; + case FileState::Removed: + return "removed"; + case FileState::NotExists: + return "not_exists"; + case FileState::NotExistsUnchanged: + return "not_exists_unchanged"; + case FileState::Unchanged: + return "unchanged"; + } + + return ""; +} + +[[maybe_unused]] static std::ostream &operator<<(std::ostream &out, + ProjectStorageUpdater::FileState state) +{ + return out << toString(state); +} + +[[maybe_unused]] static std::ostream &operator<<(std::ostream &out, + ProjectStorageUpdater::Update update) +{ + return out << "(" << update.projectDirectory << "," << update.qtDirectories << "," + << update.propertyEditorResourcesPath << "," << update.typeAnnotationPaths << ")"; +} +} // namespace QmlDesigner + namespace { +using namespace Qt::StringLiterals; + namespace Storage = QmlDesigner::Storage; +using QmlDesigner::DirectoryPathId; +using QmlDesigner::FileNameId; using QmlDesigner::FileStatus; -using QmlDesigner::ModuleId; -using QmlDesigner::SourceContextId; -using QmlDesigner::SourceId; -using QmlDesigner::SourceNameId; -namespace Storage = QmlDesigner::Storage; using QmlDesigner::IdPaths; +using QmlDesigner::ModuleId; +using QmlDesigner::SourceId; using Storage::Import; using Storage::IsInsideProject; using Storage::ModuleKind; @@ -49,6 +87,8 @@ using Storage::Synchronization::Type; using Storage::TypeTraits; using Storage::TypeTraitsKind; using Storage::Version; +using FileState = QmlDesigner::ProjectStorageUpdater::FileState; +using Update = QmlDesigner::ProjectStorageUpdater::Update; MATCHER_P5(IsStorageType, typeName, @@ -138,11 +178,11 @@ MATCHER(PackageIsEmpty, std::string(negation ? "isn't empty" : "is empty")) && package.typeAnnotations.empty() && package.updatedTypeAnnotationSourceIds.empty(); } -template +template auto IsPropertyEditorQmlPath(const ModuleIdMatcher &moduleIdMatcher, const TypeNameMatcher &typeNameMatcher, const SourceIdMatcher &pathIdMatcher, - const SourceContextIdMatcher &directoryIdMatcher) + const DirectoryPathIdMatcher &directoryIdMatcher) { return AllOf( Field("PropertyEditorQmlPath::moduleId", &PropertyEditorQmlPath::moduleId, moduleIdMatcher), @@ -153,7 +193,7 @@ auto IsPropertyEditorQmlPath(const ModuleIdMatcher &moduleIdMatcher, directoryIdMatcher)); } -class ProjectStorageUpdater : public testing::Test +class BaseProjectStorageUpdater : public testing::Test { public: struct StaticData @@ -170,26 +210,210 @@ public: static void TearDownTestSuite() { staticData.reset(); } + BaseProjectStorageUpdater() + { + ON_CALL(projectStorageMock, moduleId(_, _)).WillByDefault([&](const auto &name, const auto &kind) { + return storage.moduleId(name, kind); + }); + } + + ~BaseProjectStorageUpdater() { storage.resetForTestsOnly(); } + + void setFilesUnchanged(const QmlDesigner::SourceIds &sourceIds) + { + for (auto sourceId : sourceIds) { + ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, 2, 421})); + ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, 2, 421})); + } + } + + void setFilesChanged(const QmlDesigner::SourceIds &sourceIds) + { + for (auto sourceId : sourceIds) { + ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, 1, 21})); + ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, 2, 421})); + } + } + + void setFilesAdded(const QmlDesigner::SourceIds &sourceIds) + { + for (auto sourceId : sourceIds) { + ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, 1, 21})); + ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{})); + } + } + + void setFilesRemoved(const QmlDesigner::SourceIds &sourceIds) + { + for (auto sourceId : sourceIds) { + ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, -1, -1})); + ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, 1, 21})); + } + } + + void setFilesNotExists(const QmlDesigner::SourceIds &sourceIds) + { + for (auto sourceId : sourceIds) { + ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, -1, -1})); + ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{SourceId{}, -1, -1})); + } + } + + void setFilesNotExistsUnchanged(const QmlDesigner::SourceIds &sourceIds) + { + for (auto sourceId : sourceIds) { + ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, -1, -1})); + ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) + .WillByDefault(Return(FileStatus{sourceId, -1, -1})); + } + } + + void setFiles(FileState state, const QmlDesigner::SourceIds &sourceIds) + { + switch (state) { + case FileState::Unchanged: + setFilesUnchanged(sourceIds); + break; + case FileState::Changed: + setFilesChanged(sourceIds); + break; + case FileState::Added: + setFilesAdded(sourceIds); + break; + case FileState::Removed: + setFilesRemoved(sourceIds); + break; + case FileState::NotExists: + setFilesNotExists(sourceIds); + break; + case FileState::NotExistsUnchanged: + setFilesNotExistsUnchanged(sourceIds); + } + } + + void setFileNames(QStringView directoryPath, + const QStringList &fileNames, + const QStringList &nameFilters) + { + ON_CALL(fileSystemMock, fileNames(Eq(directoryPath), UnorderedElementsAreArray(nameFilters))) + .WillByDefault(Return(fileNames)); + } + + void setQmlFileNames(QStringView directoryPath, const QStringList &qmlFileNames) + { + setFileNames(directoryPath, qmlFileNames, {"*.qml"}); + } + + void setDirectoryInfos(DirectoryPathId directorySourceId, const DirectoryInfos &directoryInfos) + { + ON_CALL(projectStorageMock, fetchDirectoryInfos(Eq(directorySourceId))) + .WillByDefault(Return(directoryInfos)); + for (const DirectoryInfo &directoryInfo : directoryInfos) { + ON_CALL(projectStorageMock, fetchDirectoryInfo(Eq(directoryInfo.sourceId))) + .WillByDefault(Return(std::optional{directoryInfo})); + } + } + + void setContent(QStringView path, const QString &content) + { + ON_CALL(fileSystemMock, contentAsQString(Eq(path))).WillByDefault(Return(content)); + } + + void setExpectedContent(QStringView path, const QString &content) + { + EXPECT_CALL(fileSystemMock, contentAsQString(Eq(path))).WillRepeatedly(Return(content)); + } + + void setFileSystemSubdirectories(QStringView directoryPath, const QStringList &subdirectoryPaths) + { + ON_CALL(fileSystemMock, subdirectories(Eq(directoryPath))).WillByDefault(Return(subdirectoryPaths)); + } + + void setStorageSubdirectories(DirectoryPathId directoryId, + const QmlDesigner::SmallDirectoryPathIds<32> &subdirectoryIds) + { + ON_CALL(projectStorageMock, fetchSubdirectoryIds(Eq(directoryId))) + .WillByDefault(Return(subdirectoryIds)); + } + + auto moduleId(Utils::SmallStringView name, ModuleKind kind) const + { + return storage.moduleId(name, kind); + } + + SourceId createDirectorySourceId(Utils::SmallStringView path) const + { + auto directoryId = sourcePathCache.directoryPathId(path); + return SourceId::create(directoryId, FileNameId{}); + } + + SourceId createDirectorySourceIdFromQString(const QString &path) const + { + return createDirectorySourceId(Utils::PathString{path}); + } + +protected: + NiceMock fileSystemMock; + NiceMock projectStorageMock; + NiceMock qmlTypesParserMock; + NiceMock qmlDocumentParserMock; + QmlDesigner::FileStatusCache fileStatusCache{fileSystemMock}; + inline static std::unique_ptr staticData; + Sqlite::Database &database = staticData->database; + QmlDesigner::ProjectStorage &storage = staticData->storage; + QmlDesigner::SourcePathCache sourcePathCache{ + staticData->sourcePathStorage}; + NiceMock patchWatcherMock; + NiceMock errorNotifierMock; + QmlDesigner::ProjectPartId projectPartId = QmlDesigner::ProjectPartId::create(1); + QmlDesigner::ProjectPartId otherProjectPartId = QmlDesigner::ProjectPartId::create(2); + QmlDesigner::ProjectPartId qtPartId = QmlDesigner::ProjectPartId::create(10); + QmlDesigner::ProjectStorageUpdater updater{fileSystemMock, + projectStorageMock, + fileStatusCache, + sourcePathCache, + qmlDocumentParserMock, + qmlTypesParserMock, + patchWatcherMock, + errorNotifierMock, + projectPartId, + qtPartId}; +}; + +class ProjectStorageUpdater : public BaseProjectStorageUpdater +{ +public: ProjectStorageUpdater() { setFilesChanged({qmltypesPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId1}); setFilesAdded({qmltypes2PathSourceId, qmlDocumentSourceId2, qmlDocumentSourceId3}); - setFilesDontChanged({directoryPathSourceId, - path1SourceId, - path2SourceId, - path3SourceId, - firstSourceId, - secondSourceId, - thirdSourceId, - qmltypes1SourceId, - qmltypes2SourceId, - itemLibraryPathSourceId}); - setFilesDontExistsUnchanged({createDirectorySourceId("/path/designer"), - createDirectorySourceId("/root/designer"), - createDirectorySourceId("/path/one/designer"), - createDirectorySourceId("/path/two/designer"), - createDirectorySourceId("/path/three/designer")}); + setFilesUnchanged({directoryPathSourceId, + path1SourceId, + path2SourceId, + path3SourceId, + firstSourceId, + secondSourceId, + thirdSourceId, + qmltypes1SourceId, + qmltypes2SourceId, + itemLibraryPathSourceId}); + setFilesNotExistsUnchanged({createDirectorySourceId("/path/designer"), + createDirectorySourceId("/root/designer"), + createDirectorySourceId("/path/one/designer"), + createDirectorySourceId("/path/two/designer"), + createDirectorySourceId("/path/three/designer")}); setFilesAdded({qmldir1SourceId, qmldir2SourceId, qmldir3SourceId}); @@ -197,10 +421,6 @@ public: setQmlFileNames(u"/path", {"First.qml", "First2.qml", "Second.qml"}); - ON_CALL(projectStorageMock, moduleId(_, _)).WillByDefault([&](const auto &name, const auto &kind) { - return storage.moduleId(name, kind); - }); - firstType.prototype = ImportedType{"Object"}; firstType.traits = TypeTraitsKind::Reference; secondType.prototype = ImportedType{"Object2"}; @@ -246,174 +466,25 @@ public: }); } - ~ProjectStorageUpdater() { storage.resetForTestsOnly(); } - - void setFilesDontChanged(const QmlDesigner::SourceIds &sourceIds) - { - for (auto sourceId : sourceIds) { - ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) - .WillByDefault(Return(FileStatus{sourceId, 2, 421})); - ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) - .WillByDefault(Return(FileStatus{sourceId, 2, 421})); - } - } - - void setFilesChanged(const QmlDesigner::SourceIds &sourceIds) - { - for (auto sourceId : sourceIds) { - ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) - .WillByDefault(Return(FileStatus{sourceId, 1, 21})); - ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) - .WillByDefault(Return(FileStatus{sourceId, 2, 421})); - } - } - - void setFilesAdded(const QmlDesigner::SourceIds &sourceIds) - { - for (auto sourceId : sourceIds) { - ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) - .WillByDefault(Return(FileStatus{sourceId, 1, 21})); - ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) - .WillByDefault(Return(FileStatus{})); - } - } - - void setFilesRemoved(const QmlDesigner::SourceIds &sourceIds) - { - for (auto sourceId : sourceIds) { - ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) - .WillByDefault(Return(FileStatus{sourceId, -1, -1})); - ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) - .WillByDefault(Return(FileStatus{sourceId, 1, 21})); - } - } - - void setFilesDontExists(const QmlDesigner::SourceIds &sourceIds) - { - for (auto sourceId : sourceIds) { - ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) - .WillByDefault(Return(FileStatus{sourceId, -1, -1})); - ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) - .WillByDefault(Return(FileStatus{SourceId{}, -1, -1})); - } - } - - void setFilesDontExistsUnchanged(const QmlDesigner::SourceIds &sourceIds) - { - for (auto sourceId : sourceIds) { - ON_CALL(fileSystemMock, fileStatus(Eq(sourceId))) - .WillByDefault(Return(FileStatus{sourceId, -1, -1})); - ON_CALL(projectStorageMock, fetchFileStatus(Eq(sourceId))) - .WillByDefault(Return(FileStatus{sourceId, -1, -1})); - } - } - - void setFileNames(QStringView directoryPath, - const QStringList &fileNames, - const QStringList &nameFilters) - { - ON_CALL(fileSystemMock, fileNames(Eq(directoryPath), UnorderedElementsAreArray(nameFilters))) - .WillByDefault(Return(fileNames)); - } - - void setQmlFileNames(QStringView directoryPath, const QStringList &qmlFileNames) - { - setFileNames(directoryPath, qmlFileNames, {"*.qml"}); - } - - void setDirectoryInfos(SourceContextId directorySourceId, const DirectoryInfos &directoryInfos) - { - ON_CALL(projectStorageMock, fetchDirectoryInfos(Eq(directorySourceId))) - .WillByDefault(Return(directoryInfos)); - for (const DirectoryInfo &directoryInfo : directoryInfos) { - ON_CALL(projectStorageMock, fetchDirectoryInfo(Eq(directoryInfo.sourceId))) - .WillByDefault(Return(std::optional{directoryInfo})); - } - } - - void setContent(QStringView path, const QString &content) - { - ON_CALL(fileSystemMock, contentAsQString(Eq(path))).WillByDefault(Return(content)); - } - - void setExpectedContent(QStringView path, const QString &content) - { - EXPECT_CALL(fileSystemMock, contentAsQString(Eq(path))).WillRepeatedly(Return(content)); - } - - void setSubdirectoryPaths(QStringView directoryPath, const QStringList &subdirectoryPaths) - { - ON_CALL(fileSystemMock, subdirectories(Eq(directoryPath))).WillByDefault(Return(subdirectoryPaths)); - } - - void setSubdirectorySourceIds(SourceContextId directoryId, - const QmlDesigner::SmallSourceContextIds<32> &subdirectoryIds) - { - ON_CALL(projectStorageMock, fetchSubdirectoryIds(Eq(directoryId))) - .WillByDefault(Return(subdirectoryIds)); - } - - auto moduleId(Utils::SmallStringView name, ModuleKind kind) const - { - return storage.moduleId(name, kind); - } - - SourceId createDirectorySourceId(Utils::SmallStringView path) const - { - auto directoryId = sourcePathCache.sourceContextId(path); - return SourceId::create(SourceNameId{}, directoryId); - } - - SourceId createDirectorySourceIdFromQString(const QString &path) const - { - return createDirectorySourceId(Utils::PathString{path}); - } - protected: - NiceMock fileSystemMock; - NiceMock projectStorageMock; - NiceMock qmlTypesParserMock; - NiceMock qmlDocumentParserMock; - QmlDesigner::FileStatusCache fileStatusCache{fileSystemMock}; - inline static std::unique_ptr staticData; - Sqlite::Database &database = staticData->database; - QmlDesigner::ProjectStorage &storage = staticData->storage; - QmlDesigner::SourcePathCache sourcePathCache{ - staticData->sourcePathStorage}; - NiceMock patchWatcherMock; - NiceMock errorNotifierMock; - QmlDesigner::ProjectPartId projectPartId = QmlDesigner::ProjectPartId::create(1); - QmlDesigner::ProjectPartId otherProjectPartId = QmlDesigner::ProjectPartId::create(2); - QmlDesigner::ProjectPartId qtPartId = QmlDesigner::ProjectPartId::create(10); - QmlDesigner::ProjectStorageUpdater updater{fileSystemMock, - projectStorageMock, - fileStatusCache, - sourcePathCache, - qmlDocumentParserMock, - qmlTypesParserMock, - patchWatcherMock, - errorNotifierMock, - projectPartId, - qtPartId}; SourceId qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes"); SourceId qmltypes2PathSourceId = sourcePathCache.sourceId("/path/example2.qmltypes"); SourceId qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir"); - SourceContextId directoryPathId = qmlDirPathSourceId.contextId(); - SourceId directoryPathSourceId = SourceId::create(QmlDesigner::SourceNameId{}, directoryPathId); + DirectoryPathId directoryPathId = qmlDirPathSourceId.directoryPathId(); + SourceId directoryPathSourceId = SourceId::create(directoryPathId, QmlDesigner::FileNameId{}); SourceId annotationDirectorySourceId = createDirectorySourceId("/path/designer"); SourceId qmlDocumentSourceId1 = sourcePathCache.sourceId("/path/First.qml"); SourceId qmlDocumentSourceId2 = sourcePathCache.sourceId("/path/First2.qml"); SourceId qmlDocumentSourceId3 = sourcePathCache.sourceId("/path/Second.qml"); const QString itemLibraryPath = QDir::cleanPath( UNITTEST_DIR "/../../../../share/qtcreator/qmldesigner/itemLibrary/"); - SourceContextId itemLibraryPathSourceContextId = sourcePathCache.sourceContextId( + DirectoryPathId itemLibraryPathDirectoryPathId = sourcePathCache.directoryPathId( Utils::PathString{itemLibraryPath}); - SourceId itemLibraryPathSourceId = SourceId::create(SourceNameId{}, - itemLibraryPathSourceContextId); + SourceId itemLibraryPathSourceId = SourceId::create(itemLibraryPathDirectoryPathId, FileNameId{}); const QString qmlImportsPath = QDir::cleanPath(UNITTEST_DIR "/projectstorage/data/qml"); - SourceContextId qmlImportsPathSourceContextId = sourcePathCache.sourceContextId( + DirectoryPathId qmlImportsPathDirectoryPathId = sourcePathCache.directoryPathId( Utils::PathString{itemLibraryPath}); - SourceId qmlImportsPathSourceId = SourceId::create(SourceNameId{}, qmlImportsPathSourceContextId); + SourceId qmlImportsPathSourceId = SourceId::create(qmlImportsPathDirectoryPathId, FileNameId{}); ModuleId qmlModuleId{storage.moduleId("Qml", ModuleKind::QmlLibrary)}; ModuleId qmlCppNativeModuleId{storage.moduleId("Qml", ModuleKind::CppLibrary)}; ModuleId exampleModuleId{storage.moduleId("Example", ModuleKind::QmlLibrary)}; @@ -465,12 +536,12 @@ protected: QmlDesigner::SourceType::Qml}; QmlDesigner::ProjectChunkId otherQmltypesProjectChunkId{otherProjectPartId, QmlDesigner::SourceType::QmlTypes}; - SourceContextId path1SourceContextId = sourcePathCache.sourceContextId("/path/one"); - SourceId path1SourceId = SourceId::create(QmlDesigner::SourceNameId{}, path1SourceContextId); - SourceContextId path2SourceContextId = sourcePathCache.sourceContextId("/path/two"); - SourceId path2SourceId = SourceId::create(QmlDesigner::SourceNameId{}, path2SourceContextId); - SourceContextId path3SourceContextId = sourcePathCache.sourceContextId("/path/three"); - SourceId path3SourceId = SourceId::create(QmlDesigner::SourceNameId{}, path3SourceContextId); + DirectoryPathId path1DirectoryPathId = sourcePathCache.directoryPathId("/path/one"); + SourceId path1SourceId = SourceId::create(path1DirectoryPathId, QmlDesigner::FileNameId{}); + DirectoryPathId path2DirectoryPathId = sourcePathCache.directoryPathId("/path/two"); + SourceId path2SourceId = SourceId::create(path2DirectoryPathId, QmlDesigner::FileNameId{}); + DirectoryPathId path3DirectoryPathId = sourcePathCache.directoryPathId("/path/three"); + SourceId path3SourceId = SourceId::create(path3DirectoryPathId, QmlDesigner::FileNameId{}); SourceId qmldir1SourceId = sourcePathCache.sourceId("/path/one/qmldir"); SourceId qmldir2SourceId = sourcePathCache.sourceId("/path/two/qmldir"); SourceId qmldir3SourceId = sourcePathCache.sourceId("/path/three/qmldir"); @@ -481,16 +552,25 @@ protected: SourceId qmltypes2SourceId = sourcePathCache.sourceId("/path/two/example2.qmltypes"); }; -TEST_F(ProjectStorageUpdater, get_content_for_qml_dir_paths_if_file_status_is_different) +class ProjectStorageUpdater_get_content_for_qml_dir_paths : public ProjectStorageUpdater { +public: + ProjectStorageUpdater_get_content_for_qml_dir_paths() + { + setFilesChanged({qmlDir1PathSourceId}); + setFilesAdded({qmlDir2PathSourceId}); + setFilesUnchanged({qmlDir3PathSourceId, path3SourceId}); + } + SourceId qmlDir1PathSourceId = sourcePathCache.sourceId("/path/one/qmldir"); SourceId qmlDir2PathSourceId = sourcePathCache.sourceId("/path/two/qmldir"); SourceId qmlDir3PathSourceId = sourcePathCache.sourceId("/path/three/qmldir"); SourceId path3SourceId = createDirectorySourceId("/path/three"); +}; + +TEST_F(ProjectStorageUpdater_get_content_for_qml_dir_paths, file_status_is_different) +{ QStringList directories = {"/path/one", "/path/two", "/path/three"}; - setFilesChanged({qmlDir1PathSourceId}); - setFilesAdded({qmlDir2PathSourceId}); - setFilesDontChanged({qmlDir3PathSourceId, path3SourceId}); EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/one/qmldir")))); EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/two/qmldir")))); @@ -498,18 +578,10 @@ TEST_F(ProjectStorageUpdater, get_content_for_qml_dir_paths_if_file_status_is_di updater.update({.qtDirectories = directories}); } -TEST_F(ProjectStorageUpdater, - get_content_for_qml_dir_paths_if_file_status_is_different_for_subdirectories) +TEST_F(ProjectStorageUpdater_get_content_for_qml_dir_paths, file_status_is_different_for_subdirectories) { - SourceId qmlDir1PathSourceId = sourcePathCache.sourceId("/path/one/qmldir"); - SourceId qmlDir2PathSourceId = sourcePathCache.sourceId("/path/two/qmldir"); - SourceId qmlDir3PathSourceId = sourcePathCache.sourceId("/path/three/qmldir"); - SourceId path3SourceId = createDirectorySourceId("/path/three"); QStringList directories = {"/path/one"}; - setSubdirectoryPaths(u"/path/one", {"/path/two", "/path/three"}); - setFilesChanged({qmlDir1PathSourceId}); - setFilesAdded({qmlDir2PathSourceId}); - setFilesDontChanged({qmlDir3PathSourceId, path3SourceId}); + setFileSystemSubdirectories(u"/path/one", {"/path/two", "/path/three"}); EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/one/qmldir")))); EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/two/qmldir")))); @@ -517,47 +589,31 @@ TEST_F(ProjectStorageUpdater, updater.update({.qtDirectories = directories}); } -TEST_F(ProjectStorageUpdater, request_file_status_from_file_system) +class ProjectStorageUpdater_get_content_for_qml_types : public BaseProjectStorageUpdater { - EXPECT_CALL(fileSystemMock, fileStatus(Ne(directoryPathSourceId))).Times(AnyNumber()); +public: + ProjectStorageUpdater_get_content_for_qml_types() + { + setQmlFileNames(u"/path", {}); + setExpectedContent(u"/path/qmldir", qmldir); + setContent(u"/path/example.qmltypes", qmltypes); + setFilesUnchanged({directoryPathSourceId}); + setFilesChanged({qmlDirPathSourceId}); + } - EXPECT_CALL(fileSystemMock, fileStatus(Eq(directoryPathSourceId))); - - updater.update({.qtDirectories = directories}); -} - -TEST_F(ProjectStorageUpdater, request_file_status_from_file_system_for_subdirectories) -{ - EXPECT_CALL(fileSystemMock, - fileStatus(AllOf(Ne(directoryPathSourceId), Ne(path1SourceId), Ne(path2SourceId)))) - .Times(AnyNumber()); - setSubdirectoryPaths(u"/path", {"/path/one", "/path/two"}); - - EXPECT_CALL(fileSystemMock, fileStatus(Eq(path1SourceId))); - EXPECT_CALL(fileSystemMock, fileStatus(Eq(path2SourceId))); - EXPECT_CALL(fileSystemMock, fileStatus(Eq(directoryPathSourceId))); - - updater.update({.qtDirectories = directories}); -} - -TEST_F(ProjectStorageUpdater, get_content_for_qml_types) -{ +public: QString qmldir{R"(module Example typeinfo example.qmltypes)"}; - setQmlFileNames(u"/path", {}); - setExpectedContent(u"/path/qmldir", qmldir); + QString qmltypes{"Module {\ndependencies: [module1]}"}; + QStringList directories = {"/path"}; + SourceId qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes"); + SourceId qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir"); + DirectoryPathId directoryPathId = qmlDirPathSourceId.directoryPathId(); + SourceId directoryPathSourceId = SourceId::create(directoryPathId, QmlDesigner::FileNameId{}); +}; - EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))); - - updater.update({.qtDirectories = directories}); -} - -TEST_F(ProjectStorageUpdater, get_content_for_qml_types_if_project_storage_file_status_is_invalid) +TEST_F(ProjectStorageUpdater_get_content_for_qml_types, added_qml_types_file_provides_content) { - QString qmldir{R"(module Example - typeinfo example.qmltypes)"}; - setQmlFileNames(u"/path", {}); - setExpectedContent(u"/path/qmldir", qmldir); setFilesAdded({qmltypesPathSourceId}); EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))); @@ -565,16 +621,62 @@ TEST_F(ProjectStorageUpdater, get_content_for_qml_types_if_project_storage_file_ updater.update({.qtDirectories = directories}); } -TEST_F(ProjectStorageUpdater, parse_qml_types) +TEST_F(ProjectStorageUpdater_get_content_for_qml_types, changed_qml_types_file_provides_content) { - QString qmldir{R"(module Example + setFilesChanged({qmltypesPathSourceId}); + + EXPECT_CALL(fileSystemMock, contentAsQString(Eq(QString("/path/example.qmltypes")))); + + updater.update({.qtDirectories = directories}); +} + +TEST_F(ProjectStorageUpdater_get_content_for_qml_types, removed_qml_types_file_does_not_provide_content) +{ + EXPECT_CALL(fileSystemMock, contentAsQString(_)).Times(AnyNumber()); + setFilesRemoved({qmltypesPathSourceId}); + + EXPECT_CALL(fileSystemMock, contentAsQString(Eq("/path/example.qmltypes"_L1))).Times(0); + + updater.update({.qtDirectories = directories}); +} + +TEST_F(ProjectStorageUpdater_get_content_for_qml_types, removed_qml_types_file_notifies_about_error) +{ + setFilesRemoved({qmltypesPathSourceId}); + + EXPECT_CALL(errorNotifierMock, qmltypesFileMissing(Eq("/path/example.qmltypes"_L1))); + + updater.update({.qtDirectories = directories}); +} + +class ProjectStorageUpdater_parse_qml_types : public BaseProjectStorageUpdater +{ +public: + ProjectStorageUpdater_parse_qml_types() + { + QString qmldir{R"(module Example typeinfo example.qmltypes typeinfo example2.qmltypes)"}; - setContent(u"/path/qmldir", qmldir); + setContent(u"/root/path/qmldir", qmldir); + setContent(u"/root/path/example.qmltypes", qmltypes); + setContent(u"/root/path/example2.qmltypes", qmltypes2); + } + +public: QString qmltypes{"Module {\ndependencies: []}"}; QString qmltypes2{"Module {\ndependencies: [foo]}"}; - setContent(u"/path/example.qmltypes", qmltypes); - setContent(u"/path/example2.qmltypes", qmltypes2); + ModuleId exampleCppNativeModuleId{storage.moduleId("Example", ModuleKind::CppLibrary)}; + SourceId qmltypesPathSourceId = sourcePathCache.sourceId("/root/path/example.qmltypes"); + SourceId qmltypes2PathSourceId = sourcePathCache.sourceId("/root/path/example2.qmltypes"); + SourceId qmlDirPathSourceId = sourcePathCache.sourceId("/root/path/qmldir"); + DirectoryPathId directoryPathId = qmlDirPathSourceId.directoryPathId(); + SourceId directoryPathSourceId = SourceId::create(directoryPathId, QmlDesigner::FileNameId{}); +}; + +TEST_F(ProjectStorageUpdater_parse_qml_types, add_directory) +{ + setFilesAdded( + {directoryPathSourceId, qmlDirPathSourceId, qmltypesPathSourceId, qmltypes2PathSourceId}); EXPECT_CALL(qmlTypesParserMock, parse(qmltypes, @@ -589,25 +691,17 @@ TEST_F(ProjectStorageUpdater, parse_qml_types) Field("DirectoryInfo::moduleId", &DirectoryInfo::moduleId, exampleCppNativeModuleId), IsInsideProject::No)); - updater.update({.qtDirectories = directories}); + updater.update({.qtDirectories = {"/root/path"}}); } -TEST_F(ProjectStorageUpdater, parse_added_qml_types) +TEST_F(ProjectStorageUpdater_parse_qml_types, add_qmltypes) { - QString qmldir{R"(module Example - typeinfo example.qmltypes - typeinfo example2.qmltypes)"}; - setContent(u"/path/qmldir", qmldir); - QString qmltypes{"Module {\ndependencies: []}"}; - QString qmltypes2{"Module {\ndependencies: [foo]}"}; - setContent(u"/path/example.qmltypes", qmltypes); - setContent(u"/path/example2.qmltypes", qmltypes2); - setFilesAdded({directoryPathSourceId, - qmlDirPathSourceId, - qmltypesPathSourceId, - qmltypes2PathSourceId, - qmlDocumentSourceId2, - qmlDocumentSourceId3}); + setDirectoryInfos( + directoryPathId, + {{directoryPathId, qmltypesPathSourceId, exampleCppNativeModuleId, FileType::QmlTypes}, + {directoryPathId, qmltypes2PathSourceId, exampleCppNativeModuleId, FileType::QmlTypes}}); + setFilesUnchanged({directoryPathSourceId, qmlDirPathSourceId}); + setFilesAdded({qmltypesPathSourceId, qmltypes2PathSourceId}); EXPECT_CALL(qmlTypesParserMock, parse(qmltypes, @@ -622,32 +716,13 @@ TEST_F(ProjectStorageUpdater, parse_added_qml_types) Field("DirectoryInfo::moduleId", &DirectoryInfo::moduleId, exampleCppNativeModuleId), IsInsideProject::No)); - updater.update({.qtDirectories = directories}); + updater.update({.qtDirectories = {"/root/path"}}); } -TEST_F(ProjectStorageUpdater, parse_qml_types_in_project) +TEST_F(ProjectStorageUpdater_parse_qml_types, add_directory_inide_project) { - QString qmldir{R"(module Example - typeinfo example.qmltypes)"}; - setContent(u"/path/qmldir", qmldir); - QString qmltypes{"Module {\ndependencies: []}"}; - setContent(u"/path/example.qmltypes", qmltypes); - - EXPECT_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _, IsInsideProject::Yes)); - - updater.update({.projectDirectory = "/path"}); -} - -TEST_F(ProjectStorageUpdater, parse_qml_types_inside_project) -{ - QString qmldir{R"(module Example - typeinfo example.qmltypes - typeinfo example2.qmltypes)"}; - setContent(u"/path/qmldir", qmldir); - QString qmltypes{"Module {\ndependencies: []}"}; - QString qmltypes2{"Module {\ndependencies: [foo]}"}; - setContent(u"/path/example.qmltypes", qmltypes); - setContent(u"/path/example2.qmltypes", qmltypes2); + setFilesAdded( + {directoryPathSourceId, qmlDirPathSourceId, qmltypesPathSourceId, qmltypes2PathSourceId}); EXPECT_CALL(qmlTypesParserMock, parse(qmltypes, @@ -662,21 +737,14 @@ TEST_F(ProjectStorageUpdater, parse_qml_types_inside_project) Field("DirectoryInfo::moduleId", &DirectoryInfo::moduleId, exampleCppNativeModuleId), IsInsideProject::Yes)); - updater.update({.projectDirectory = "/path"}); + updater.update({.projectDirectory = "/root/path"}); } -TEST_F(ProjectStorageUpdater, parse_qml_types_in_subdirectories) +TEST_F(ProjectStorageUpdater_parse_qml_types, add_subdirectories) { - QString qmldir{R"(module Example - typeinfo example.qmltypes - typeinfo example2.qmltypes)"}; - setContent(u"/path/qmldir", qmldir); - QString qmltypes{"Module {\ndependencies: []}"}; - QString qmltypes2{"Module {\ndependencies: [foo]}"}; - setContent(u"/path/example.qmltypes", qmltypes); - setContent(u"/path/example2.qmltypes", qmltypes2); - QStringList directories = {"/root"}; - setSubdirectoryPaths(u"/root", {"/path"}); + setFilesAdded( + {directoryPathSourceId, qmlDirPathSourceId, qmltypesPathSourceId, qmltypes2PathSourceId}); + setFileSystemSubdirectories(u"/root", {"/root/path"}); EXPECT_CALL(qmlTypesParserMock, parse(qmltypes, @@ -691,58 +759,94 @@ TEST_F(ProjectStorageUpdater, parse_qml_types_in_subdirectories) Field("DirectoryInfo::moduleId", &DirectoryInfo::moduleId, exampleCppNativeModuleId), IsInsideProject::No)); - updater.update({.qtDirectories = directories}); + updater.update({.qtDirectories = {"/root"}}); } -TEST_F(ProjectStorageUpdater, synchronize_is_empty_for_no_change) +class ProjectStorageUpdater_synchronize_empty : public BaseProjectStorageUpdater { - setFilesDontChanged({qmltypesPathSourceId, qmltypes2PathSourceId, qmlDirPathSourceId}); +public: + ProjectStorageUpdater_synchronize_empty() + { + QString qmldir{R"(module Example + typeinfo example.qmltypes + typeinfo example2.qmltypes)"}; + setContent(u"/root/path/qmldir", qmldir); + setContent(u"/root/path/example.qmltypes", qmltypes); + setContent(u"/root/path/example2.qmltypes", qmltypes2); + setFileSystemSubdirectories(u"/root", {"/root/path"}); + } + +public: + QString qmltypes{"Module {\ndependencies: []}"}; + QString qmltypes2{"Module {\ndependencies: [foo]}"}; + SourceId qmltypesPathSourceId = sourcePathCache.sourceId("/root/path/example.qmltypes"); + SourceId qmltypes2PathSourceId = sourcePathCache.sourceId("/root/path/example2.qmltypes"); + SourceId qmlDirPathSourceId = sourcePathCache.sourceId("/root/path/qmldir"); + DirectoryPathId directoryPathId = qmlDirPathSourceId.directoryPathId(); + SourceId directoryPathSourceId = SourceId::create(directoryPathId, QmlDesigner::FileNameId{}); + SourceId annotationDirectoryId = createDirectorySourceId("/root/path/designer"); + SourceId rootQmlDirPathSourceId = sourcePathCache.sourceId("/root/qmldir"); + SourceId rootDirectoryPathSourceId = createDirectorySourceId("/root"); + SourceId rootAnnotationDirectoryId = createDirectorySourceId("/root/designer"); + SourceId ignoreInQdsSourceId = sourcePathCache.sourceId("/root/path/ignore-in-qds"); +}; + +TEST_F(ProjectStorageUpdater_synchronize_empty, for_no_change_for_qt) +{ + setFilesUnchanged( + {qmltypesPathSourceId, qmltypes2PathSourceId, qmlDirPathSourceId, directoryPathSourceId}); + setFilesNotExistsUnchanged({annotationDirectoryId}); EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty())); - updater.update({.qtDirectories = directories}); + updater.update({.qtDirectories = {"/root/path"}}); } -TEST_F(ProjectStorageUpdater, synchronize_is_empty_for_no_change_in_subdirectory) +TEST_F(ProjectStorageUpdater_synchronize_empty, for_no_change_for_project) { - SourceId qmlDirRootPathSourceId = sourcePathCache.sourceId("/root/qmldir"); - SourceId rootPathSourceId = createDirectorySourceId("/root"); - setFilesDontChanged({qmltypesPathSourceId, - qmltypes2PathSourceId, - qmlDirPathSourceId, - qmlDirRootPathSourceId, - rootPathSourceId}); - QStringList directories = {"/root"}; - setSubdirectoryPaths(u"/root", {"/path"}); + setFilesUnchanged( + {qmltypesPathSourceId, qmltypes2PathSourceId, qmlDirPathSourceId, directoryPathSourceId}); + setFilesNotExistsUnchanged({annotationDirectoryId}); EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty())); - updater.update({.qtDirectories = directories}); + updater.update({.projectDirectory = "/root/path"}); } -TEST_F(ProjectStorageUpdater, synchronize_is_empty_for_ignored_subdirectory) +TEST_F(ProjectStorageUpdater_synchronize_empty, for_no_change_in_subdirectory) +{ + setFilesUnchanged({qmltypesPathSourceId, + qmltypes2PathSourceId, + qmlDirPathSourceId, + rootDirectoryPathSourceId, + directoryPathSourceId}); + setFilesNotExistsUnchanged( + {annotationDirectoryId, rootQmlDirPathSourceId, rootAnnotationDirectoryId, ignoreInQdsSourceId}); + + EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty())); + + updater.update({.qtDirectories = {"/root"}}); +} + +TEST_F(ProjectStorageUpdater_synchronize_empty, for_ignored_subdirectory) { - SourceId qmlDirRootPathSourceId = sourcePathCache.sourceId("/root/qmldir"); - SourceId ignoreInQdsSourceId = sourcePathCache.sourceId("/path/ignore-in-qds"); - SourceId rootPathSourceId = createDirectorySourceId("/root"); setFilesChanged({qmltypesPathSourceId, qmltypes2PathSourceId, qmlDirPathSourceId}); - setFilesDontChanged({rootPathSourceId, qmlDirRootPathSourceId, ignoreInQdsSourceId}); - setSubdirectoryPaths(u"/root", {"/path"}); + setFilesUnchanged({rootDirectoryPathSourceId, directoryPathSourceId, ignoreInQdsSourceId}); + setFilesNotExistsUnchanged( + {rootAnnotationDirectoryId, annotationDirectoryId, rootQmlDirPathSourceId}); EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty())); updater.update({.projectDirectory = "/root"}); } -TEST_F(ProjectStorageUpdater, synchronize_is_empty_for_added_ignored_subdirectory) +TEST_F(ProjectStorageUpdater_synchronize_empty, not_for_added_ignored_subdirectory) { - SourceId qmlDirRootPathSourceId = sourcePathCache.sourceId("/root/qmldir"); - SourceId ignoreInQdsSourceId = sourcePathCache.sourceId("/path/ignore-in-qds"); - SourceId rootPathSourceId = createDirectorySourceId("/root"); setFilesChanged({qmltypesPathSourceId, qmltypes2PathSourceId, qmlDirPathSourceId}); + setFilesUnchanged({rootDirectoryPathSourceId, directoryPathSourceId}); setFilesAdded({ignoreInQdsSourceId}); - setFilesDontChanged({rootPathSourceId, qmlDirRootPathSourceId}); - setSubdirectoryPaths(u"/root", {"/path"}); + setFilesNotExistsUnchanged( + {rootAnnotationDirectoryId, annotationDirectoryId, rootQmlDirPathSourceId}); EXPECT_CALL( projectStorageMock, @@ -762,57 +866,51 @@ TEST_F(ProjectStorageUpdater, synchronize_is_empty_for_added_ignored_subdirector updater.update({.projectDirectory = "/root"}); } -TEST_F(ProjectStorageUpdater, synchronize_qml_types) +class ProjectStorageUpdater_synchronize_subdirectories : public BaseProjectStorageUpdater { - Storage::Import import{qmlModuleId, Storage::Version{2, 3}, qmltypesPathSourceId}; - QString qmltypes{"Module {\ndependencies: []}"}; - setQmlFileNames(u"/path", {}); - setContent(u"/path/example.qmltypes", qmltypes); - ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _, _)) - .WillByDefault([&](auto, auto &imports, auto &types, auto, auto) { - types.push_back(objectType); - imports.push_back(import); - }); +public: + ProjectStorageUpdater_synchronize_subdirectories() + { + setFileSystemSubdirectories(u"/root", {"/root/one", "/root/two"}); + setFileSystemSubdirectories(u"/root/one", {"/root/one/three"}); + } - EXPECT_CALL(projectStorageMock, moduleId(Eq("Example"), ModuleKind::QmlLibrary)); - EXPECT_CALL(projectStorageMock, moduleId(Eq("Example"), ModuleKind::CppLibrary)); - EXPECT_CALL(projectStorageMock, moduleId(Eq("/path"), ModuleKind::PathLibrary)); - EXPECT_CALL(projectStorageMock, - synchronize( - AllOf(Field("SynchronizationPackage::imports", - &SynchronizationPackage::imports, - ElementsAre(import)), - Field("SynchronizationPackage::types", - &SynchronizationPackage::types, - ElementsAre(Eq(objectType))), - Field("SynchronizationPackage::updatedSourceIds", - &SynchronizationPackage::updatedSourceIds, - UnorderedElementsAre(qmlDirPathSourceId, qmltypesPathSourceId)), - Field("SynchronizationPackage::fileStatuses", - &SynchronizationPackage::fileStatuses, - UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21), - IsFileStatus(qmltypesPathSourceId, 1, 21))), - Field("SynchronizationPackage::directoryInfos", - &SynchronizationPackage::directoryInfos, - UnorderedElementsAre(IsDirectoryInfo(directoryPathId, - qmltypesPathSourceId, - exampleCppNativeModuleId, - FileType::QmlTypes))), - Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", - &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, - UnorderedElementsAre(directoryPathId))))); +public: + SourceId rootDirectoryPathSourceId = createDirectorySourceId("/root"); + DirectoryPathId rootDirectoryPathId = rootDirectoryPathSourceId.directoryPathId(); + SourceId path1SourceId = createDirectorySourceId("/root/one"); + DirectoryPathId path1DirectoryPathId = path1SourceId.directoryPathId(); + SourceId path2SourceId = createDirectorySourceId("/root/two"); + DirectoryPathId path2DirectoryPathId = path2SourceId.directoryPathId(); + SourceId path3SourceId = createDirectorySourceId("/root/one/three"); + DirectoryPathId path3DirectoryPathId = path3SourceId.directoryPathId(); +}; - updater.update({.qtDirectories = directories}); +TEST_F(ProjectStorageUpdater_synchronize_subdirectories, added_qt_subdircectories) +{ + setFilesAdded({rootDirectoryPathSourceId, path1SourceId, path2SourceId, path3SourceId}); + + EXPECT_CALL( + projectStorageMock, + synchronize(AllOf( + Field("SynchronizationPackage::directoryInfos", + &SynchronizationPackage::directoryInfos, + UnorderedElementsAre( + IsDirectoryInfo(rootDirectoryPathId, path1SourceId, ModuleId{}, FileType::Directory), + IsDirectoryInfo(rootDirectoryPathId, path2SourceId, ModuleId{}, FileType::Directory), + IsDirectoryInfo(path1DirectoryPathId, path3SourceId, ModuleId{}, FileType::Directory))), + Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", + &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, + UnorderedElementsAre(rootDirectoryPathId, + path1DirectoryPathId, + path2DirectoryPathId, + path3DirectoryPathId))))); + + updater.update({.qtDirectories = {"/root"}}); } -TEST_F(ProjectStorageUpdater, synchronize_subdircectories) +TEST_F(ProjectStorageUpdater_synchronize_subdirectories, changed_qt_subdircectories) { - QStringList directories = {"/root"}; - setSubdirectoryPaths(u"/root", {"/path/one", "/path/two"}); - setSubdirectoryPaths(u"/path/one", {"/path/three"}); - SourceContextId rootDirectoryPathId = sourcePathCache.sourceContextId("/root"); - SourceId rootDirectoryPathSourceId = SourceId::create(QmlDesigner::SourceNameId{}, - rootDirectoryPathId); setFilesChanged({rootDirectoryPathSourceId, path1SourceId, path2SourceId, path3SourceId}); EXPECT_CALL( @@ -823,56 +921,113 @@ TEST_F(ProjectStorageUpdater, synchronize_subdircectories) UnorderedElementsAre( IsDirectoryInfo(rootDirectoryPathId, path1SourceId, ModuleId{}, FileType::Directory), IsDirectoryInfo(rootDirectoryPathId, path2SourceId, ModuleId{}, FileType::Directory), - IsDirectoryInfo(path1SourceContextId, path3SourceId, ModuleId{}, FileType::Directory))), + IsDirectoryInfo(path1DirectoryPathId, path3SourceId, ModuleId{}, FileType::Directory))), Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, UnorderedElementsAre(rootDirectoryPathId, - path1SourceContextId, - path2SourceContextId, - path3SourceContextId))))); + path1DirectoryPathId, + path2DirectoryPathId, + path3DirectoryPathId))))); - updater.update({.qtDirectories = directories}); + updater.update({.qtDirectories = {"/root"}}); } -TEST_F(ProjectStorageUpdater, synchronize_subdircectories_even_for_no_changes) +TEST_F(ProjectStorageUpdater_synchronize_subdirectories, added_project_subdircectories) +{ + setFilesAdded({rootDirectoryPathSourceId, path1SourceId, path2SourceId, path3SourceId}); + + EXPECT_CALL( + projectStorageMock, + synchronize(AllOf( + Field("SynchronizationPackage::directoryInfos", + &SynchronizationPackage::directoryInfos, + UnorderedElementsAre( + IsDirectoryInfo(rootDirectoryPathId, path1SourceId, ModuleId{}, FileType::Directory), + IsDirectoryInfo(rootDirectoryPathId, path2SourceId, ModuleId{}, FileType::Directory), + IsDirectoryInfo(path1DirectoryPathId, path3SourceId, ModuleId{}, FileType::Directory))), + Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", + &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, + UnorderedElementsAre(rootDirectoryPathId, + path1DirectoryPathId, + path2DirectoryPathId, + path3DirectoryPathId))))); + + updater.update({.projectDirectory = "/root"}); +} + +TEST_F(ProjectStorageUpdater_synchronize_subdirectories, changed_project_subdircectories) +{ + setFilesChanged({rootDirectoryPathSourceId, path1SourceId, path2SourceId, path3SourceId}); + + EXPECT_CALL( + projectStorageMock, + synchronize(AllOf( + Field("SynchronizationPackage::directoryInfos", + &SynchronizationPackage::directoryInfos, + UnorderedElementsAre( + IsDirectoryInfo(rootDirectoryPathId, path1SourceId, ModuleId{}, FileType::Directory), + IsDirectoryInfo(rootDirectoryPathId, path2SourceId, ModuleId{}, FileType::Directory), + IsDirectoryInfo(path1DirectoryPathId, path3SourceId, ModuleId{}, FileType::Directory))), + Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", + &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, + UnorderedElementsAre(rootDirectoryPathId, + path1DirectoryPathId, + path2DirectoryPathId, + path3DirectoryPathId))))); + + updater.update({.projectDirectory = "/root"}); +} + +TEST_F(ProjectStorageUpdater_synchronize_subdirectories, qt_subdirectories_if_root_is_not_changed) { - QStringList directories = {"/root"}; - setSubdirectoryPaths(u"/root", {"/path/one", "/path/two"}); - setSubdirectoryPaths(u"/path/one", {"/path/three"}); - auto rootDirectoryPathSourceId = createDirectorySourceId("/root"); setFilesChanged({path1SourceId, path2SourceId, path3SourceId}); - setFilesDontChanged({rootDirectoryPathSourceId}); + setFilesUnchanged({rootDirectoryPathSourceId}); EXPECT_CALL(projectStorageMock, synchronize(AllOf(Field("SynchronizationPackage::directoryInfos", &SynchronizationPackage::directoryInfos, - UnorderedElementsAre(IsDirectoryInfo(path1SourceContextId, + UnorderedElementsAre(IsDirectoryInfo(path1DirectoryPathId, path3SourceId, ModuleId{}, FileType::Directory))), Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, - UnorderedElementsAre(path1SourceContextId, - path2SourceContextId, - path3SourceContextId))))); + UnorderedElementsAre(path1DirectoryPathId, + path2DirectoryPathId, + path3DirectoryPathId))))); - updater.update({.qtDirectories = directories}); + updater.update({.qtDirectories = {"/root"}}); } -TEST_F(ProjectStorageUpdater, synchronize_subdircectories_for_deleted_subdirecties) +TEST_F(ProjectStorageUpdater_synchronize_subdirectories, project_subdirectories_if_root_is_not_changed) +{ + setFilesChanged({path1SourceId, path2SourceId, path3SourceId}); + setFilesUnchanged({rootDirectoryPathSourceId}); + + EXPECT_CALL(projectStorageMock, + synchronize(AllOf(Field("SynchronizationPackage::directoryInfos", + &SynchronizationPackage::directoryInfos, + UnorderedElementsAre(IsDirectoryInfo(path1DirectoryPathId, + path3SourceId, + ModuleId{}, + FileType::Directory))), + Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", + &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, + UnorderedElementsAre(path1DirectoryPathId, + path2DirectoryPathId, + path3DirectoryPathId))))); + + updater.update({.projectDirectory = "/root"}); +} + +TEST_F(ProjectStorageUpdater_synchronize_subdirectories, for_deleted_qt_subdirecties) { - QStringList directories = {"/root"}; - setSubdirectoryPaths(u"/root", {"/path/two"}); - SourceContextId rootDirectoryPathId = sourcePathCache.sourceContextId("/root"); - SourceId rootDirectoryPathSourceId = SourceId::create(QmlDesigner::SourceNameId{}, - rootDirectoryPathId); setFilesChanged({rootDirectoryPathSourceId}); - setFilesDontExists({ - path1SourceId, - path3SourceId, - }); - setSubdirectorySourceIds(rootDirectoryPathId, {path1SourceContextId, path2SourceContextId}); - setSubdirectorySourceIds(path1SourceContextId, {path3SourceContextId}); + setFilesRemoved({path1SourceId, path3SourceId}); + setFilesUnchanged({path2SourceId}); + setStorageSubdirectories(rootDirectoryPathId, {path1DirectoryPathId, path2DirectoryPathId}); + setStorageSubdirectories(path1DirectoryPathId, {path3DirectoryPathId}); + setFileSystemSubdirectories(u"/root", {"/root/two"}); EXPECT_CALL(projectStorageMock, synchronize(AllOf(Field("SynchronizationPackage::directoryInfos", @@ -884,19 +1039,285 @@ TEST_F(ProjectStorageUpdater, synchronize_subdircectories_for_deleted_subdirecti Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, UnorderedElementsAre(rootDirectoryPathId, - path1SourceContextId, - path2SourceContextId, - path3SourceContextId))))); + path1DirectoryPathId, + path3DirectoryPathId))))); - updater.update({.qtDirectories = directories}); + updater.update({.qtDirectories = {"/root"}}); } -TEST_F(ProjectStorageUpdater, synchronize_qml_types_throws_if_qmltpes_does_not_exists) +TEST_F(ProjectStorageUpdater_synchronize_subdirectories, for_deleted_project_subdirecties) { - Storage::Import import{qmlModuleId, Storage::Version{2, 3}, qmltypesPathSourceId}; - setFilesDontExists({qmltypesPathSourceId}); + setFilesChanged({rootDirectoryPathSourceId}); + setFilesRemoved({path1SourceId, path3SourceId}); + setFilesUnchanged({path2SourceId}); + setStorageSubdirectories(rootDirectoryPathId, {path1DirectoryPathId, path2DirectoryPathId}); + setStorageSubdirectories(path1DirectoryPathId, {path3DirectoryPathId}); + setFileSystemSubdirectories(u"/root", {"/root/two"}); - ASSERT_THROW(updater.update({.qtDirectories = directories}), QmlDesigner::CannotParseQmlTypesFile); + EXPECT_CALL(projectStorageMock, + synchronize(AllOf(Field("SynchronizationPackage::directoryInfos", + &SynchronizationPackage::directoryInfos, + UnorderedElementsAre(IsDirectoryInfo(rootDirectoryPathId, + path2SourceId, + ModuleId{}, + FileType::Directory))), + Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", + &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, + UnorderedElementsAre(rootDirectoryPathId, + path1DirectoryPathId, + path3DirectoryPathId))))); + + updater.update({.projectDirectory = {"/root"}}); +} + +class synchronize_qml_types : public BaseProjectStorageUpdater +{ +public: + synchronize_qml_types() + + { + setQmlFileNames(u"/path", {}); + + QString qmltypes{"Module {\ndependencies: []}"}; + setContent(u"/path/example.qmltypes", qmltypes); + setContent(u"/path/qmldir", "module Example\ntypeinfo example.qmltypes\n"); + ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _, _)) + .WillByDefault([&](auto, auto &imports, auto &types, auto, auto) { + types.push_back(objectType); + imports.push_back(import); + }); + setFilesNotExistsUnchanged({annotationDirectorySourceId}); + } + +public: + SourceId qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes"); + SourceId qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir"); + DirectoryPathId directoryPathId = qmlDirPathSourceId.directoryPathId(); + SourceId directoryPathSourceId = SourceId::create(directoryPathId, QmlDesigner::FileNameId{}); + SourceId annotationDirectorySourceId = createDirectorySourceId("/path/designer"); + ModuleId qmlModuleId{storage.moduleId("Qml", ModuleKind::QmlLibrary)}; + ModuleId exampleModuleId{storage.moduleId("Example", ModuleKind::QmlLibrary)}; + ModuleId exampleCppNativeModuleId{storage.moduleId("Example", ModuleKind::CppLibrary)}; + Storage::Import import{qmlModuleId, Storage::Version{2, 3}, qmltypesPathSourceId}; + Type objectType{"QObject", + ImportedType{}, + ImportedType{}, + Storage::TypeTraitsKind::Reference, + qmltypesPathSourceId, + {ExportedType{exampleModuleId, "Object"}, ExportedType{exampleModuleId, "Obj"}}}; +}; + +using ChangeQmlTypesParameters = std::tuple; + +class synchronize_changed_qml_types : public synchronize_qml_types, + public testing::WithParamInterface +{ +public: + synchronize_changed_qml_types() + : state{std::get<1>(GetParam())} + , directoryState{std::get<2>(GetParam())} + , qmldirState{std::get<3>(GetParam())} + , update{std::get<0>(GetParam())} + + { + if (qmldirState == FileState::Unchanged) { + setDirectoryInfos( + directoryPathId, + {{directoryPathId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes}}); + } + + if (state == FileState::Added) + directoryState = FileState::Changed; + } + +public: + FileState state; + FileState directoryState; + FileState qmldirState; + const Update &update; +}; + +auto updateStatesName = [](const testing::TestParamInfo &info) { + std::string name = toString(std::get<1>(info.param)); + + name += "_qmltypes_file_in_"; + + if (std::get<0>(info.param).projectDirectory.isEmpty()) + name += "qt_"; + else + name += "project_"; + + name += toString(std::get<2>(info.param)); + + name += "_directory_"; + + name += toString(std::get<3>(info.param)); + + name += "_qmldir"; + + return name; +}; + +INSTANTIATE_TEST_SUITE_P(ProjectStorageUpdater, + synchronize_changed_qml_types, + testing::Combine(testing::Values(Update{.qtDirectories = {"/path"}}, + Update{.projectDirectory = "/path"}), + testing::Values(FileState::Added, FileState::Changed), + testing::Values(FileState::Changed, FileState::Unchanged), + testing::Values(FileState::Changed, FileState::Unchanged)), + updateStatesName); + +TEST_P(synchronize_changed_qml_types, from_qt_directory_update_types) +{ + setFiles(directoryState, {directoryPathSourceId}); + setFiles(qmldirState, {qmlDirPathSourceId}); + setFiles(state, {qmltypesPathSourceId}); + + EXPECT_CALL(projectStorageMock, + synchronize(AllOf(Field("SynchronizationPackage::imports", + &SynchronizationPackage::imports, + ElementsAre(import)), + Field("SynchronizationPackage::types", + &SynchronizationPackage::types, + ElementsAre(Eq(objectType))), + Field("SynchronizationPackage::updatedSourceIds", + &SynchronizationPackage::updatedSourceIds, + Contains(qmltypesPathSourceId))))); + + updater.update(update); +} + +TEST_P(synchronize_changed_qml_types, from_qt_directory_update_file_status) +{ + setFiles(directoryState, {directoryPathSourceId}); + setFiles(qmldirState, {qmlDirPathSourceId}); + setFiles(state, {qmltypesPathSourceId}); + + EXPECT_CALL(projectStorageMock, + synchronize(AllOf(Field("SynchronizationPackage::fileStatuses", + &SynchronizationPackage::fileStatuses, + Contains(IsFileStatus(qmltypesPathSourceId, 1, 21))), + Field("SynchronizationPackage::updatedFileStatusSourceIds", + &SynchronizationPackage::updatedFileStatusSourceIds, + Contains(qmltypesPathSourceId))))); + + updater.update(update); +} + +TEST_P(synchronize_changed_qml_types, from_qt_directory_update_directory_infos) +{ + bool directoryUnchanged = directoryState == FileState::Unchanged + && qmldirState == FileState::Unchanged; + setFiles(directoryState, {directoryPathSourceId}); + setFiles(qmldirState, {qmlDirPathSourceId}); + setFiles(state, {qmltypesPathSourceId}); + + EXPECT_CALL(projectStorageMock, + synchronize( + AllOf(Field("SynchronizationPackage::directoryInfos", + &SynchronizationPackage::directoryInfos, + Conditional(directoryUnchanged, + IsEmpty(), + Contains(IsDirectoryInfo(directoryPathId, + qmltypesPathSourceId, + exampleCppNativeModuleId, + FileType::QmlTypes)))), + Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", + &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, + Conditional(directoryUnchanged, IsEmpty(), Contains(directoryPathId)))))); + + updater.update(update); +} + +using NonExistingQmlTypesParameters = std::tuple; + +class synchronize_non_existing_qml_types + : public synchronize_qml_types, + public testing::WithParamInterface +{ +public: + synchronize_non_existing_qml_types() + : state{std::get<1>(GetParam())} + , update{std::get<0>(GetParam())} + + { + setDirectoryInfos(directoryPathId, + {{directoryPathId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes}}); + } + +public: + FileState state; + const Update &update; +}; + +auto updateStateName = [](const testing::TestParamInfo &info) { + std::string name = toString(std::get<1>(info.param)); + + if (std::get<0>(info.param).projectDirectory.isEmpty()) + name += "_qt"; + else + name += "_project"; + + return name; +}; + +INSTANTIATE_TEST_SUITE_P(ProjectStorageUpdater, + synchronize_non_existing_qml_types, + testing::Combine(testing::Values(Update{.qtDirectories = {"/path"}}, + Update{.projectDirectory = "/path"}), + testing::Values(FileState::Removed, FileState::NotExists)), + updateStateName); + +TEST_P(synchronize_non_existing_qml_types, notfies_error) +{ + setFilesUnchanged({directoryPathSourceId, qmlDirPathSourceId}); + setFiles(state, {qmltypesPathSourceId}); + + EXPECT_CALL(errorNotifierMock, qmltypesFileMissing(Eq("/path/example.qmltypes"_L1))); + + updater.update(update); +} + +TEST_P(synchronize_non_existing_qml_types, notfies_error_if_direcory_and_qmldir_file_is_changed) +{ + setFilesChanged({directoryPathSourceId, qmlDirPathSourceId}); + setFiles(state, {qmltypesPathSourceId}); + + EXPECT_CALL(errorNotifierMock, qmltypesFileMissing(Eq("/path/example.qmltypes"_L1))); + + updater.update(update); +} + +TEST_P(synchronize_non_existing_qml_types, updates_source_ids) +{ + setFilesUnchanged({directoryPathSourceId, qmlDirPathSourceId}); + setFiles(state, {qmltypesPathSourceId}); + + EXPECT_CALL(projectStorageMock, + synchronize(AllOf(Field("SynchronizationPackage::updatedSourceIds", + &SynchronizationPackage::updatedSourceIds, + Contains(qmltypesPathSourceId))))); + + updater.update(update); +} + +TEST_P(synchronize_non_existing_qml_types, updates_directory_info) +{ + setFilesChanged({directoryPathSourceId, qmlDirPathSourceId}); + setFiles(state, {qmltypesPathSourceId}); + + EXPECT_CALL(projectStorageMock, + synchronize(AllOf(Field("SynchronizationPackage::directoryInfos", + &SynchronizationPackage::directoryInfos, + Not(Contains(IsDirectoryInfo(directoryPathId, + qmltypesPathSourceId, + exampleCppNativeModuleId, + FileType::QmlTypes)))), + Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", + &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, + Contains(directoryPathId))))); + + updater.update(update); } TEST_F(ProjectStorageUpdater, synchronize_qml_types_are_empty_if_file_does_not_changed) @@ -905,7 +1326,7 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_types_are_empty_if_file_does_not_c setContent(u"/path/example.qmltypes", qmltypes); ON_CALL(qmlTypesParserMock, parse(qmltypes, _, _, _, _)) .WillByDefault([&](auto, auto &, auto &types, auto, auto) { types.push_back(objectType); }); - setFilesDontChanged({qmltypesPathSourceId, qmltypes2PathSourceId, qmlDirPathSourceId}); + setFilesUnchanged({qmltypesPathSourceId, qmltypes2PathSourceId, qmlDirPathSourceId}); EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty())); @@ -1252,7 +1673,7 @@ TEST_F(ProjectStorageUpdater, synchronize_add_only_qml_document_in_directory) FirstType 1.0 First.qml)"}; setContent(u"/path/qmldir", qmldir); setFilesChanged({directoryPathSourceId}); - setFilesDontChanged({qmlDirPathSourceId, qmlDocumentSourceId1}); + setFilesUnchanged({qmlDirPathSourceId, qmlDocumentSourceId1}); setFilesAdded({qmlDocumentSourceId2}); setDirectoryInfos(directoryPathId, {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}}); @@ -1320,7 +1741,7 @@ TEST_F(ProjectStorageUpdater, synchronize_removes_qml_document) )"}; setContent(u"/path/qmldir", qmldir); setFilesChanged({qmlDirPathSourceId}); - setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); + setFilesUnchanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); setFilesRemoved({qmlDocumentSourceId3}); setDirectoryInfos(directoryPathId, {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}, @@ -1390,7 +1811,7 @@ TEST_F(ProjectStorageUpdater, synchronize_removes_qml_document_in_qmldir_only) )"}; setContent(u"/path/qmldir", qmldir); setFilesChanged({qmlDirPathSourceId}); - setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); + setFilesUnchanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); setDirectoryInfos(directoryPathId, {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}, {directoryPathId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}}); @@ -1454,7 +1875,7 @@ TEST_F(ProjectStorageUpdater, synchronize_add_qml_document_to_qmldir) )"}; setContent(u"/path/qmldir", qmldir); setFilesChanged({qmlDirPathSourceId}); - setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); + setFilesUnchanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); setDirectoryInfos(directoryPathId, {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}, {directoryPathId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}}); @@ -1517,7 +1938,7 @@ TEST_F(ProjectStorageUpdater, synchronize_remove_qml_document_from_qmldir) FirstType 1.0 First.qml )"}; setContent(u"/path/qmldir", qmldir); - setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); + setFilesUnchanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); setFilesChanged({qmlDirPathSourceId}); setDirectoryInfos(directoryPathId, {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}, @@ -1581,7 +2002,7 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_documents_dont_update_if_up_to_dat FirstType 2.2 First2.qml SecondType 2.2 Second.qml)"}; setContent(u"/path/qmldir", qmldir); - setFilesDontChanged({qmlDocumentSourceId3}); + setFilesUnchanged({qmlDocumentSourceId3}); EXPECT_CALL( projectStorageMock, @@ -1647,62 +2068,6 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_documents_dont_update_if_up_to_dat updater.update({.qtDirectories = directories}); } -TEST_F(ProjectStorageUpdater, synchroniz_if_qmldir_file_has_not_changed) -{ - setDirectoryInfos(directoryPathId, - {{directoryPathId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes}, - {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}, - {directoryPathId, qmlDocumentSourceId1, exampleModuleId, FileType::QmlDocument}, - {directoryPathId, qmlDocumentSourceId2, exampleModuleId, FileType::QmlDocument}}); - setFilesDontChanged({qmlDirPathSourceId}); - - EXPECT_CALL(projectStorageMock, - synchronize(AllOf( - Field("SynchronizationPackage::imports", - &SynchronizationPackage::imports, - UnorderedElementsAre(import1, import2, import4, import5)), - Field("SynchronizationPackage::types", - &SynchronizationPackage::types, - UnorderedElementsAre( - Eq(objectType), - Eq(itemType), - AllOf(IsStorageType("First.qml", - ImportedType{"Object"}, - TypeTraitsKind::Reference, - qmlDocumentSourceId1, - ChangeLevel::ExcludeExportedTypes), - Field("Type::exportedTypes", &Type::exportedTypes, IsEmpty())), - AllOf(IsStorageType("First2.qml", - ImportedType{"Object2"}, - TypeTraitsKind::Reference, - qmlDocumentSourceId2, - ChangeLevel::ExcludeExportedTypes), - Field("Type::exportedTypes", &Type::exportedTypes, IsEmpty())))), - Field("SynchronizationPackage::updatedSourceIds", - &SynchronizationPackage::updatedSourceIds, - UnorderedElementsAre(qmltypesPathSourceId, - qmltypes2PathSourceId, - qmlDocumentSourceId1, - qmlDocumentSourceId2)), - Field("SynchronizationPackage::fileStatuses", - &SynchronizationPackage::fileStatuses, - UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 1, 21), - IsFileStatus(qmltypes2PathSourceId, 1, 21), - IsFileStatus(qmlDocumentSourceId1, 1, 21), - IsFileStatus(qmlDocumentSourceId2, 1, 21))), - Field("SynchronizationPackage::updatedFileStatusSourceIds", - &SynchronizationPackage::updatedFileStatusSourceIds, - UnorderedElementsAre(qmltypesPathSourceId, - qmltypes2PathSourceId, - qmlDocumentSourceId1, - qmlDocumentSourceId2)), - Field("SynchronizationPackage::directoryInfos", - &SynchronizationPackage::directoryInfos, - IsEmpty())))); - - updater.update({.qtDirectories = directories}); -} - TEST_F(ProjectStorageUpdater, synchroniz_if_qmldir_file_has_not_changed_and_some_updated_files) { setDirectoryInfos(directoryPathId, @@ -1710,7 +2075,7 @@ TEST_F(ProjectStorageUpdater, synchroniz_if_qmldir_file_has_not_changed_and_some {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}, {directoryPathId, qmlDocumentSourceId1, exampleModuleId, FileType::QmlDocument}, {directoryPathId, qmlDocumentSourceId2, exampleModuleId, FileType::QmlDocument}}); - setFilesDontChanged({qmlDirPathSourceId, qmltypes2PathSourceId, qmlDocumentSourceId2}); + setFilesUnchanged({qmlDirPathSourceId, qmltypes2PathSourceId, qmlDocumentSourceId2}); EXPECT_CALL(projectStorageMock, synchronize(AllOf( @@ -1752,10 +2117,12 @@ TEST_F(ProjectStorageUpdater, synchroniz_if_qmldir_file_not_changed_and_some_rem {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}, {directoryPathId, qmlDocumentSourceId1, exampleModuleId, FileType::QmlDocument}, {directoryPathId, qmlDocumentSourceId2, exampleModuleId, FileType::QmlDocument}}); - setFilesDontChanged({qmlDirPathSourceId, qmltypes2PathSourceId, qmlDocumentSourceId2}); + setFilesUnchanged({qmlDirPathSourceId, qmltypes2PathSourceId, qmlDocumentSourceId2}); setFilesRemoved({qmltypesPathSourceId, qmlDocumentSourceId1}); - ASSERT_THROW(updater.update({.qtDirectories = directories}), QmlDesigner::CannotParseQmlTypesFile); + EXPECT_CALL(errorNotifierMock, qmltypesFileMissing(Eq(u"/path/example.qmltypes"_s))); + + updater.update({.qtDirectories = directories}); } TEST_F(ProjectStorageUpdater, synchroniz_if_qmldir_file_has_changed_and_some_removed_files) @@ -1770,7 +2137,7 @@ TEST_F(ProjectStorageUpdater, synchroniz_if_qmldir_file_has_changed_and_some_rem {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}, {directoryPathId, qmlDocumentSourceId1, exampleModuleId, FileType::QmlDocument}, {directoryPathId, qmlDocumentSourceId2, exampleModuleId, FileType::QmlDocument}}); - setFilesDontChanged({qmltypes2PathSourceId, qmlDocumentSourceId2}); + setFilesUnchanged({qmltypes2PathSourceId, qmlDocumentSourceId2}); setFilesRemoved({qmltypesPathSourceId, qmlDocumentSourceId1}); EXPECT_CALL( @@ -2259,7 +2626,7 @@ TEST_F(ProjectStorageUpdater, update_path_watcher_directories) TEST_F(ProjectStorageUpdater, update_path_watcher_directory_does_not_exists) { - setFilesDontExists({path2SourceId}); + setFilesNotExists({path2SourceId}); EXPECT_CALL(patchWatcherMock, updateIdPaths(Contains(IdPaths{qtPartId, @@ -2271,7 +2638,7 @@ TEST_F(ProjectStorageUpdater, update_path_watcher_directory_does_not_exists) TEST_F(ProjectStorageUpdater, update_path_watcher_directory_does_not_changed) { - setFilesDontChanged({qmldir1SourceId, qmldir2SourceId, path1SourceId, path2SourceId}); + setFilesUnchanged({qmldir1SourceId, qmldir2SourceId, path1SourceId, path2SourceId}); EXPECT_CALL(patchWatcherMock, updateIdPaths(Contains(IdPaths{qtPartId, @@ -2304,7 +2671,7 @@ TEST_F(ProjectStorageUpdater, update_path_watcher_qmldirs) TEST_F(ProjectStorageUpdater, update_path_watcher_qmldir_does_not_exists) { - setFilesDontExists({qmldir2SourceId}); + setFilesNotExists({qmldir2SourceId}); EXPECT_CALL(patchWatcherMock, updateIdPaths(Contains(IdPaths{qtPartId, @@ -2316,7 +2683,7 @@ TEST_F(ProjectStorageUpdater, update_path_watcher_qmldir_does_not_exists) TEST_F(ProjectStorageUpdater, update_path_watcher_qmldir_does_not_changed) { - setFilesDontChanged({qmldir1SourceId, qmldir2SourceId, path1SourceId, path2SourceId}); + setFilesUnchanged({qmldir1SourceId, qmldir2SourceId, path1SourceId, path2SourceId}); EXPECT_CALL(patchWatcherMock, updateIdPaths(Contains(IdPaths{qtPartId, @@ -2362,7 +2729,7 @@ TEST_F(ProjectStorageUpdater, update_path_watcher_only_qml_files_dont_changed) setQmlFileNames(u"/path/one", {"First.qml", "Second.qml"}); setQmlFileNames(u"/path/two", {"Third.qml"}); setContent(u"/path/one/qmldir", qmldir1); - setFilesDontChanged({firstSourceId, secondSourceId, thirdSourceId}); + setFilesUnchanged({firstSourceId, secondSourceId, thirdSourceId}); EXPECT_CALL(patchWatcherMock, updateIdPaths(Contains(IdPaths{qtPartId, @@ -2374,13 +2741,13 @@ TEST_F(ProjectStorageUpdater, update_path_watcher_only_qml_files_dont_changed) TEST_F(ProjectStorageUpdater, update_path_watcher_only_qml_files_changed) { - setFilesDontChanged({qmldir1SourceId, qmldir2SourceId, path1SourceId, path2SourceId}); + setFilesUnchanged({qmldir1SourceId, qmldir2SourceId, path1SourceId, path2SourceId}); setFilesChanged({firstSourceId, secondSourceId, thirdSourceId}); - setDirectoryInfos(path1SourceContextId, - {{path1SourceContextId, firstSourceId, exampleModuleId, FileType::QmlDocument}, - {path1SourceContextId, secondSourceId, exampleModuleId, FileType::QmlDocument}}); - setDirectoryInfos(path2SourceContextId, - {{path2SourceContextId, thirdSourceId, ModuleId{}, FileType::QmlDocument}}); + setDirectoryInfos(path1DirectoryPathId, + {{path1DirectoryPathId, firstSourceId, exampleModuleId, FileType::QmlDocument}, + {path1DirectoryPathId, secondSourceId, exampleModuleId, FileType::QmlDocument}}); + setDirectoryInfos(path2DirectoryPathId, + {{path2DirectoryPathId, thirdSourceId, ModuleId{}, FileType::QmlDocument}}); EXPECT_CALL(patchWatcherMock, updateIdPaths(Contains(IdPaths{qtPartId, @@ -2392,18 +2759,18 @@ TEST_F(ProjectStorageUpdater, update_path_watcher_only_qml_files_changed) TEST_F(ProjectStorageUpdater, update_path_watcher_qml_files_and_directories_dont_changed) { - setFilesDontChanged({qmldir1SourceId, - qmldir2SourceId, - path1SourceId, - path2SourceId, - firstSourceId, - secondSourceId, - thirdSourceId}); - setDirectoryInfos(path1SourceContextId, - {{path1SourceContextId, firstSourceId, exampleModuleId, FileType::QmlDocument}, - {path1SourceContextId, secondSourceId, exampleModuleId, FileType::QmlDocument}}); - setDirectoryInfos(path2SourceContextId, - {{path2SourceContextId, thirdSourceId, ModuleId{}, FileType::QmlDocument}}); + setFilesUnchanged({qmldir1SourceId, + qmldir2SourceId, + path1SourceId, + path2SourceId, + firstSourceId, + secondSourceId, + thirdSourceId}); + setDirectoryInfos(path1DirectoryPathId, + {{path1DirectoryPathId, firstSourceId, exampleModuleId, FileType::QmlDocument}, + {path1DirectoryPathId, secondSourceId, exampleModuleId, FileType::QmlDocument}}); + setDirectoryInfos(path2DirectoryPathId, + {{path2DirectoryPathId, thirdSourceId, ModuleId{}, FileType::QmlDocument}}); EXPECT_CALL(patchWatcherMock, updateIdPaths(Contains(IdPaths{qtPartId, @@ -2422,7 +2789,7 @@ TEST_F(ProjectStorageUpdater, update_path_watcher_qmltypes_files_in_qmldir) setContent(u"/path/one/qmldir", qmldir1); setContent(u"/path/two/qmldir", qmldir2); - setFilesDontChanged({firstSourceId, secondSourceId, thirdSourceId}); + setFilesUnchanged({firstSourceId, secondSourceId, thirdSourceId}); EXPECT_CALL(patchWatcherMock, updateIdPaths(Contains(IdPaths{qtPartId, @@ -2440,7 +2807,7 @@ TEST_F(ProjectStorageUpdater, update_path_watcher_only_qmltypes_files_in_qmldir_ typeinfo example2.qmltypes)"}; setContent(u"/path/one/qmldir", qmldir1); setContent(u"/path/two/qmldir", qmldir2); - setFilesDontChanged({qmltypes1SourceId, qmltypes2SourceId}); + setFilesUnchanged({qmltypes1SourceId, qmltypes2SourceId}); EXPECT_CALL(patchWatcherMock, updateIdPaths(Contains(IdPaths{qtPartId, @@ -2452,12 +2819,12 @@ TEST_F(ProjectStorageUpdater, update_path_watcher_only_qmltypes_files_in_qmldir_ TEST_F(ProjectStorageUpdater, update_path_watcher_only_qmltypes_files_changed) { - setFilesDontChanged({qmldir1SourceId, qmldir2SourceId, path1SourceId, path2SourceId}); + setFilesUnchanged({qmldir1SourceId, qmldir2SourceId, path1SourceId, path2SourceId}); setFilesChanged({qmltypes1SourceId, qmltypes2SourceId}); - setDirectoryInfos(path1SourceContextId, - {{path1SourceContextId, qmltypes1SourceId, exampleModuleId, FileType::QmlTypes}}); - setDirectoryInfos(path2SourceContextId, - {{path2SourceContextId, qmltypes2SourceId, exampleModuleId, FileType::QmlTypes}}); + setDirectoryInfos(path1DirectoryPathId, + {{path1DirectoryPathId, qmltypes1SourceId, exampleModuleId, FileType::QmlTypes}}); + setDirectoryInfos(path2DirectoryPathId, + {{path2DirectoryPathId, qmltypes2SourceId, exampleModuleId, FileType::QmlTypes}}); EXPECT_CALL(patchWatcherMock, updateIdPaths(Contains(IdPaths{qtPartId, @@ -2469,16 +2836,16 @@ TEST_F(ProjectStorageUpdater, update_path_watcher_only_qmltypes_files_changed) TEST_F(ProjectStorageUpdater, update_path_watcher_qmltypes_files_and_directories_dont_changed) { - setFilesDontChanged({qmldir1SourceId, - qmldir2SourceId, - path1SourceId, - path2SourceId, - qmltypes1SourceId, - qmltypes2SourceId}); - setDirectoryInfos(path1SourceContextId, - {{path1SourceContextId, qmltypes1SourceId, exampleModuleId, FileType::QmlTypes}}); - setDirectoryInfos(path2SourceContextId, - {{path2SourceContextId, qmltypes2SourceId, exampleModuleId, FileType::QmlTypes}}); + setFilesUnchanged({qmldir1SourceId, + qmldir2SourceId, + path1SourceId, + path2SourceId, + qmltypes1SourceId, + qmltypes2SourceId}); + setDirectoryInfos(path1DirectoryPathId, + {{path1DirectoryPathId, qmltypes1SourceId, exampleModuleId, FileType::QmlTypes}}); + setDirectoryInfos(path2DirectoryPathId, + {{path2DirectoryPathId, qmltypes2SourceId, exampleModuleId, FileType::QmlTypes}}); EXPECT_CALL(patchWatcherMock, updateIdPaths(Contains(IdPaths{qtPartId, @@ -2490,7 +2857,7 @@ TEST_F(ProjectStorageUpdater, update_path_watcher_qmltypes_files_and_directories TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir) { - setFilesDontExists({qmlDirPathSourceId}); + setFilesNotExists({qmlDirPathSourceId}); setFilesChanged({directoryPathSourceId}); EXPECT_CALL( @@ -2559,7 +2926,7 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir) TEST_F(ProjectStorageUpdater, warn_about_non_existing_qml_document) { - setFilesDontExists({qmlDocumentSourceId1}); + setFilesNotExists({qmlDocumentSourceId1}); setFilesAdded({directoryPathSourceId}); QString qmldir{R"(module Example FirstType 1.0 First.qml @@ -2579,7 +2946,7 @@ TEST_F(ProjectStorageUpdater, warn_about_non_existing_qml_document) TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_parsed_type_if_qml_document_does_not_exists) { - setFilesDontExists({qmlDocumentSourceId1}); + setFilesNotExists({qmlDocumentSourceId1}); setFilesAdded({directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId2}); QString qmldir{R"(module Example FirstType 1.0 First.qml @@ -2694,10 +3061,10 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir_if_direct TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir_add_qml_document) { - setFilesDontExistsUnchanged({qmlDirPathSourceId}); + setFilesNotExistsUnchanged({qmlDirPathSourceId}); setFilesChanged({directoryPathSourceId}); setFilesAdded({qmlDocumentSourceId3}); - setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); + setFilesUnchanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); setDirectoryInfos(directoryPathId, {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}, {directoryPathId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}}); @@ -2752,10 +3119,10 @@ TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir_add_qml_d TEST_F(ProjectStorageUpdater, synchronize_qml_documents_without_qmldir_removes_qml_document) { - setFilesDontExists({qmlDirPathSourceId}); + setFilesNotExists({qmlDirPathSourceId}); setFilesChanged({directoryPathSourceId}); setFilesRemoved({qmlDocumentSourceId3}); - setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); + setFilesUnchanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); setQmlFileNames(u"/path", {"First.qml", "First2.qml"}); setDirectoryInfos(directoryPathId, {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}, @@ -2802,7 +3169,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_directories) SecondType 2.2 Second.qml)"}; setContent(u"/path/qmldir", qmldir); setFilesChanged({directoryPathSourceId}); - setFilesDontChanged({qmlDirPathSourceId}); + setFilesUnchanged({qmlDirPathSourceId}); EXPECT_CALL( projectStorageMock, @@ -2876,13 +3243,13 @@ TEST_F(ProjectStorageUpdater, watcher_updates_subdirectories) FirstType 2.2 First2.qml SecondType 2.2 Second.qml)"}; setContent(u"/path/qmldir", qmldir); - SourceContextId rootPathId = sourcePathCache.sourceContextId("/root"); - SourceId rootPathSourceId = SourceId::create(QmlDesigner::SourceNameId{}, rootPathId); + DirectoryPathId rootPathId = sourcePathCache.directoryPathId("/root"); + SourceId rootPathSourceId = SourceId::create(rootPathId, QmlDesigner::FileNameId{}); SourceId rootQmldirPathSourceId = sourcePathCache.sourceId("/root/qmldir"); setFilesChanged({directoryPathSourceId, rootPathSourceId}); - setFilesDontChanged({qmlDirPathSourceId, rootQmldirPathSourceId}); - setSubdirectoryPaths(u"/root", {"/path"}); - setSubdirectorySourceIds(rootPathId, {directoryPathId}); + setFilesUnchanged({qmlDirPathSourceId, rootQmldirPathSourceId}); + setFileSystemSubdirectories(u"/root", {"/path"}); + setStorageSubdirectories(rootPathId, {directoryPathId}); EXPECT_CALL( projectStorageMock, @@ -2988,8 +3355,8 @@ TEST_F(ProjectStorageUpdater, watcher_watches_directories_after_directory_change SecondType 2.2 Second.qml)"}; setContent(u"/path/qmldir", qmldir); setFilesChanged({directoryPathSourceId}); - setFilesDontChanged({qmlDirPathSourceId}); - auto directorySourceContextId = directoryPathSourceId.contextId(); + setFilesUnchanged({qmlDirPathSourceId}); + auto directoryDirectoryPathId = directoryPathSourceId.directoryPathId(); EXPECT_CALL(patchWatcherMock, updateContextIdPaths( @@ -2999,7 +3366,7 @@ TEST_F(ProjectStorageUpdater, watcher_watches_directories_after_directory_change IdPaths{qtPartId, QmlDesigner::SourceType::Qml, {qmlDocumentSourceId1, qmlDocumentSourceId2, qmlDocumentSourceId3}}), - UnorderedElementsAre(directorySourceContextId))); + UnorderedElementsAre(directoryDirectoryPathId))); updater.pathsWithIdsChanged({{directoryProjectChunkId, {directoryPathSourceId}}}); } @@ -3104,7 +3471,7 @@ TEST_F(ProjectStorageUpdater, watcher_watches_directories_after_qmldir_changes) FirstType 2.2 First2.qml SecondType 2.2 Second.qml)"}; setContent(u"/path/qmldir", qmldir); - auto directorySourceContextId = qmlDirPathSourceId.contextId(); + auto directoryDirectoryPathId = qmlDirPathSourceId.directoryPathId(); EXPECT_CALL(patchWatcherMock, updateContextIdPaths( @@ -3114,7 +3481,7 @@ TEST_F(ProjectStorageUpdater, watcher_watches_directories_after_qmldir_changes) IdPaths{qtPartId, QmlDesigner::SourceType::Qml, {qmlDocumentSourceId1, qmlDocumentSourceId2, qmlDocumentSourceId3}}), - UnorderedElementsAre(directorySourceContextId))); + UnorderedElementsAre(directoryDirectoryPathId))); updater.pathsWithIdsChanged({{qmldirProjectChunkId, {qmlDirPathSourceId}}}); } @@ -3138,7 +3505,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_add_only_qml_document_in_directory FirstType 1.0 First.qml)"}; setContent(u"/path/qmldir", qmldir); setFilesChanged({directoryPathSourceId}); - setFilesDontChanged({qmlDirPathSourceId, qmlDocumentSourceId1}); + setFilesUnchanged({qmlDirPathSourceId, qmlDocumentSourceId1}); setFilesAdded({qmlDocumentSourceId2}); setDirectoryInfos(directoryPathId, {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}}); @@ -3206,7 +3573,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_removes_qml_document) )"}; setContent(u"/path/qmldir", qmldir); setFilesChanged({qmlDirPathSourceId}); - setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); + setFilesUnchanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); setFilesRemoved({qmlDocumentSourceId3}); setDirectoryInfos(directoryPathId, {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}, @@ -3276,7 +3643,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_removes_qml_document_in_qmldir_onl )"}; setContent(u"/path/qmldir", qmldir); setFilesChanged({qmlDirPathSourceId}); - setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); + setFilesUnchanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); setDirectoryInfos(directoryPathId, {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}, {directoryPathId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}}); @@ -3340,7 +3707,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_directories_add_qml_document_to_qm )"}; setContent(u"/path/qmldir", qmldir); setFilesChanged({qmlDirPathSourceId}); - setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); + setFilesUnchanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); setDirectoryInfos(directoryPathId, {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}, {directoryPathId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}}); @@ -3403,7 +3770,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_directories_remove_qml_document_fr FirstType 1.0 First.qml )"}; setContent(u"/path/qmldir", qmldir); - setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); + setFilesUnchanged({qmlDocumentSourceId1, qmlDocumentSourceId2}); setFilesChanged({qmlDirPathSourceId}); setDirectoryInfos(directoryPathId, {{directoryPathId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}, @@ -3467,7 +3834,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_directories_dont_update_qml_docume FirstType 2.2 First2.qml SecondType 2.2 Second.qml)"}; setContent(u"/path/qmldir", qmldir); - setFilesDontChanged({qmlDocumentSourceId3}); + setFilesUnchanged({qmlDocumentSourceId3}); EXPECT_CALL( projectStorageMock, @@ -3540,7 +3907,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_qmldirs_dont_update_qml_documents_ FirstType 2.2 First2.qml SecondType 2.2 Second.qml)"}; setContent(u"/path/qmldir", qmldir); - setFilesDontChanged({qmlDocumentSourceId3}); + setFilesUnchanged({qmlDocumentSourceId3}); EXPECT_CALL( projectStorageMock, @@ -3613,7 +3980,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_directory_but_not_qmldir) {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}, {directoryPathId, qmlDocumentSourceId1, exampleModuleId, FileType::QmlDocument}, {directoryPathId, qmlDocumentSourceId2, exampleModuleId, FileType::QmlDocument}}); - setFilesDontChanged({qmlDirPathSourceId}); + setFilesUnchanged({qmlDirPathSourceId}); EXPECT_CALL(projectStorageMock, synchronize(AllOf( @@ -3704,7 +4071,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_qml_documents) TEST_F(ProjectStorageUpdater, watcher_updates_removed_qml_documents) { - setFilesDontExistsUnchanged({annotationDirectorySourceId, qmlDirPathSourceId}); + setFilesNotExistsUnchanged({annotationDirectorySourceId, qmlDirPathSourceId}); setFilesRemoved({qmlDocumentSourceId2}); setFilesChanged({qmlDocumentSourceId1}); @@ -3761,7 +4128,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_qmltypes) setDirectoryInfos(directoryPathId, {{directoryPathId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes}, {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}}); - setFilesDontChanged( + setFilesUnchanged( {directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2}); EXPECT_CALL(projectStorageMock, @@ -3790,12 +4157,12 @@ TEST_F(ProjectStorageUpdater, watcher_updates_qmltypes) {{qmltypesProjectChunkId, {qmltypesPathSourceId, qmltypes2PathSourceId}}}); } -TEST_F(ProjectStorageUpdater, watcher_updates_removed_qmltypes_without_updated_qmldir) +TEST_F(ProjectStorageUpdater, DISABLED_watcher_updates_removed_qmltypes_without_updated_qmldir) { setDirectoryInfos(directoryPathId, {{directoryPathId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes}, {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}}); - setFilesDontChanged( + setFilesUnchanged( {directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2}); setFilesRemoved({qmltypesPathSourceId}); @@ -3810,7 +4177,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_removed_qmltypes_with_updated_qmld setDirectoryInfos(directoryPathId, {{directoryPathId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes}, {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}}); - setFilesDontChanged( + setFilesUnchanged( {directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2}); setFilesRemoved({qmltypesPathSourceId}); updater.pathsWithIdsChanged( @@ -3858,7 +4225,7 @@ TEST_F(ProjectStorageUpdater, watcher_dont_watches_directories_after_qmltypes_ch setDirectoryInfos(directoryPathId, {{directoryPathId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes}, {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}}); - setFilesDontChanged( + setFilesUnchanged( {directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2}); EXPECT_CALL(patchWatcherMock, updateContextIdPaths(_, _)).Times(0); @@ -3872,7 +4239,7 @@ TEST_F(ProjectStorageUpdater, watcher_dont_updates_qmltypes_for_other_projects) setDirectoryInfos(directoryPathId, {{directoryPathId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes}, {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}}); - setFilesDontChanged( + setFilesUnchanged( {directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2}); EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty())); @@ -3889,7 +4256,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_directories_and_but_not_included_q SecondType 2.2 Second.qml)"}; setContent(u"/path/qmldir", qmldir); setFilesChanged({directoryPathSourceId}); - setFilesDontChanged({qmlDirPathSourceId}); + setFilesUnchanged({qmlDirPathSourceId}); EXPECT_CALL( projectStorageMock, @@ -3965,7 +4332,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_qmldir_and_but_not_included_qml_do FirstType 2.2 First2.qml SecondType 2.2 Second.qml)"}; setContent(u"/path/qmldir", qmldir); - setFilesDontChanged({directoryPathSourceId}); + setFilesUnchanged({directoryPathSourceId}); setFilesChanged({qmlDirPathSourceId}); EXPECT_CALL( @@ -4052,7 +4419,7 @@ TEST_F(ProjectStorageUpdater, watcher_updates_qmldir_and_but_not_included_qmltyp typeinfo example.qmltypes typeinfo example2.qmltypes)"}; setContent(u"/path/qmldir", qmldir); - setFilesDontChanged({directoryPathSourceId}); + setFilesUnchanged({directoryPathSourceId}); setFilesChanged({qmlDirPathSourceId, qmltypesPathSourceId, qmltypes2PathSourceId, @@ -4170,7 +4537,7 @@ TEST_F(ProjectStorageUpdater, input_is_reused_next_call_if_an_error_happens) setDirectoryInfos(directoryPathId, {{directoryPathId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes}, {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}}); - setFilesDontChanged({directoryPathSourceId, qmlDirPathSourceId}); + setFilesUnchanged({directoryPathSourceId, qmlDirPathSourceId}); ON_CALL(projectStorageMock, synchronize(_)) .WillByDefault(Throw(QmlDesigner::TypeHasInvalidSourceId{})); updater.pathsWithIdsChanged( @@ -4235,7 +4602,7 @@ TEST_F(ProjectStorageUpdater, input_is_reused_next_call_if_an_error_happens_and_ setDirectoryInfos(directoryPathId, {{directoryPathId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes}, {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}}); - setFilesDontChanged({directoryPathSourceId, qmlDirPathSourceId}); + setFilesUnchanged({directoryPathSourceId, qmlDirPathSourceId}); ON_CALL(projectStorageMock, synchronize(_)) .WillByDefault(Throw(QmlDesigner::TypeHasInvalidSourceId{})); updater.pathsWithIdsChanged( @@ -4304,7 +4671,7 @@ TEST_F(ProjectStorageUpdater, input_is_reused_next_call_if_an_error_happens_and_ {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}, {directoryPathId, qmlDocumentSourceId1, QmlDesigner::ModuleId{}, FileType::QmlDocument}, {directoryPathId, qmlDocumentSourceId1, QmlDesigner::ModuleId{}, FileType::QmlDocument}}); - setFilesDontChanged({directoryPathSourceId, qmlDirPathSourceId}); + setFilesUnchanged({directoryPathSourceId, qmlDirPathSourceId}); ON_CALL(projectStorageMock, synchronize(_)) .WillByDefault(Throw(QmlDesigner::TypeHasInvalidSourceId{})); updater.pathsWithIdsChanged( @@ -4370,7 +4737,7 @@ TEST_F(ProjectStorageUpdater, input_is_cleared_after_successful_update) setDirectoryInfos(directoryPathId, {{directoryPathId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes}, {directoryPathId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}}); - setFilesDontChanged({directoryPathSourceId, qmlDirPathSourceId}); + setFilesUnchanged({directoryPathSourceId, qmlDirPathSourceId}); updater.pathsWithIdsChanged( {{qmltypesProjectChunkId, {qmltypesPathSourceId, qmltypes2PathSourceId}}}); @@ -4425,9 +4792,9 @@ TEST_F(ProjectStorageUpdater, update_property_editor_panes) }); auto sourceId = sourcePathCache.sourceId( QmlDesigner::SourcePath{propertyEditorQmlPath + "/QML/QtObjectPane.qml"}); - auto directoryId = sourcePathCache.sourceContextId( + auto directoryId = sourcePathCache.directoryPathId( QmlDesigner::SourcePath{propertyEditorQmlPath + "/QML"}); - auto directorySourceId = SourceId::create(QmlDesigner::SourceNameId{}, directoryId); + auto directorySourceId = SourceId::create(directoryId, QmlDesigner::FileNameId{}); setFilesChanged({directorySourceId}); auto qmlModuleId = storage.moduleId("QML", ModuleKind::QmlLibrary); @@ -4460,15 +4827,14 @@ TEST_F(ProjectStorageUpdater, update_property_editor_specifics) }); auto textSourceId = sourcePathCache.sourceId( QmlDesigner::SourcePath{propertyEditorQmlPath + "/QtQuick/TextSpecifics.qml"}); - auto qtQuickDirectoryId = sourcePathCache.sourceContextId( + auto qtQuickDirectoryId = sourcePathCache.directoryPathId( QmlDesigner::SourcePath{propertyEditorQmlPath + "/QtQuick"}); - auto qtQuickDirectorySourceId = SourceId::create(QmlDesigner::SourceNameId{}, qtQuickDirectoryId); + auto qtQuickDirectorySourceId = SourceId::create(qtQuickDirectoryId, QmlDesigner::FileNameId{}); auto buttonSourceId = sourcePathCache.sourceId( QmlDesigner::SourcePath{propertyEditorQmlPath + "/QtQuick/Controls/ButtonSpecifics.qml"}); - auto controlsDirectoryId = sourcePathCache.sourceContextId( + auto controlsDirectoryId = sourcePathCache.directoryPathId( QmlDesigner::SourcePath{propertyEditorQmlPath + "/QtQuick/Controls"}); - auto controlsDirectorySourceId = SourceId::create(QmlDesigner::SourceNameId{}, - controlsDirectoryId); + auto controlsDirectorySourceId = SourceId::create(controlsDirectoryId, QmlDesigner::FileNameId{}); setFilesChanged({qtQuickDirectorySourceId, controlsDirectorySourceId}); auto qtQuickModuleId = storage.moduleId("QtQuick", ModuleKind::QmlLibrary); auto controlsModuleId = storage.moduleId("QtQuick.Controls", ModuleKind::QmlLibrary); @@ -4520,7 +4886,7 @@ TEST_F(ProjectStorageUpdater, update_type_annotations) synchronize(AllOf(Field("SynchronizationPackage::typeAnnotations", &SynchronizationPackage::typeAnnotations, IsSupersetOf({IsTypeAnnotation(qtQuickSourceId, - itemLibraryPathSourceContextId, + itemLibraryPathDirectoryPathId, "Item", qtQuickModuleId, StartsWith(itemLibraryPath), @@ -4528,7 +4894,7 @@ TEST_F(ProjectStorageUpdater, update_type_annotations) _, _), IsTypeAnnotation(qtQuickControlSourceId, - itemLibraryPathSourceContextId, + itemLibraryPathDirectoryPathId, "Button", qtQuickControlsModuleId, StartsWith(itemLibraryPath), @@ -4548,7 +4914,7 @@ TEST_F(ProjectStorageUpdater, update_added_type_annotation) QmlDesigner::SourcePath{itemLibraryPath + "/quick.metainfo"}); auto qtQuickControlSourceId = sourcePathCache.sourceId( QmlDesigner::SourcePath{itemLibraryPath + "/qtquickcontrols2.metainfo"}); - setFilesDontChanged({itemLibraryPathSourceId}); + setFilesUnchanged({itemLibraryPathSourceId}); setFilesAdded({qtQuickSourceId, qtQuickControlSourceId}); auto qtQuickModuleId = moduleId("QtQuick", ModuleKind::QmlLibrary); auto qtQuickControlsModuleId = moduleId("QtQuick.Controls.Basic", ModuleKind::QmlLibrary); @@ -4559,7 +4925,7 @@ TEST_F(ProjectStorageUpdater, update_added_type_annotation) synchronize(AllOf(Field("SynchronizationPackage::typeAnnotations", &SynchronizationPackage::typeAnnotations, IsSupersetOf({IsTypeAnnotation(qtQuickSourceId, - itemLibraryPathSourceContextId, + itemLibraryPathDirectoryPathId, "Item", qtQuickModuleId, StartsWith(itemLibraryPath), @@ -4567,7 +4933,7 @@ TEST_F(ProjectStorageUpdater, update_added_type_annotation) _, _), IsTypeAnnotation(qtQuickControlSourceId, - itemLibraryPathSourceContextId, + itemLibraryPathDirectoryPathId, "Button", qtQuickControlsModuleId, StartsWith(itemLibraryPath), @@ -4587,7 +4953,7 @@ TEST_F(ProjectStorageUpdater, update_changed_type_annotation) QmlDesigner::SourcePath{itemLibraryPath + "/quick.metainfo"}); auto qtQuickControlSourceId = sourcePathCache.sourceId( QmlDesigner::SourcePath{itemLibraryPath + "/qtquickcontrols2.metainfo"}); - setFilesDontChanged({itemLibraryPathSourceId}); + setFilesUnchanged({itemLibraryPathSourceId}); setFilesChanged({qtQuickSourceId, qtQuickControlSourceId}); auto qtQuickModuleId = moduleId("QtQuick", ModuleKind::QmlLibrary); auto qtQuickControlsModuleId = moduleId("QtQuick.Controls.Basic", ModuleKind::QmlLibrary); @@ -4598,7 +4964,7 @@ TEST_F(ProjectStorageUpdater, update_changed_type_annotation) synchronize(AllOf(Field("SynchronizationPackage::typeAnnotations", &SynchronizationPackage::typeAnnotations, IsSupersetOf({IsTypeAnnotation(qtQuickSourceId, - itemLibraryPathSourceContextId, + itemLibraryPathDirectoryPathId, "Item", qtQuickModuleId, StartsWith(itemLibraryPath), @@ -4606,7 +4972,7 @@ TEST_F(ProjectStorageUpdater, update_changed_type_annotation) _, _), IsTypeAnnotation(qtQuickControlSourceId, - itemLibraryPathSourceContextId, + itemLibraryPathDirectoryPathId, "Button", qtQuickControlsModuleId, StartsWith(itemLibraryPath), @@ -4652,12 +5018,12 @@ TEST_F(ProjectStorageUpdater, update_type_annotations_removed_meta_info_file) auto qtQuickControlSourceId = sourcePathCache.sourceId( QmlDesigner::SourcePath{itemLibraryPath + "/qtquickcontrols2.metainfo"}); ON_CALL(projectStorageMock, typeAnnotationDirectoryIds()) - .WillByDefault(Return(QmlDesigner::SmallSourceContextIds<64>{itemLibraryPathSourceContextId})); - ON_CALL(projectStorageMock, typeAnnotationSourceIds(itemLibraryPathSourceContextId)) + .WillByDefault(Return(QmlDesigner::SmallDirectoryPathIds<64>{itemLibraryPathDirectoryPathId})); + ON_CALL(projectStorageMock, typeAnnotationSourceIds(itemLibraryPathDirectoryPathId)) .WillByDefault(Return(QmlDesigner::SmallSourceIds<4>{qtQuickSourceId, qtQuickControlSourceId})); setFilesChanged({itemLibraryPathSourceId}); setFilesRemoved({qtQuickSourceId}); - setFilesDontChanged({qtQuickControlSourceId}); + setFilesUnchanged({qtQuickControlSourceId}); EXPECT_CALL(projectStorageMock, synchronize(AllOf(Field("SynchronizationPackage::typeAnnotations", @@ -4684,10 +5050,10 @@ TEST_F(ProjectStorageUpdater, update_type_annotations_removed_directory) auto qtQuickControlSourceId = sourcePathCache.sourceId( QmlDesigner::SourcePath{itemLibraryPath + "/qtquickcontrols2.metainfo"}); ON_CALL(projectStorageMock, typeAnnotationDirectoryIds()) - .WillByDefault(Return(QmlDesigner::SmallSourceContextIds<64>{ - itemLibraryPathSourceContextId, + .WillByDefault(Return(QmlDesigner::SmallDirectoryPathIds<64>{ + itemLibraryPathDirectoryPathId, })); - ON_CALL(projectStorageMock, typeAnnotationSourceIds(itemLibraryPathSourceContextId)) + ON_CALL(projectStorageMock, typeAnnotationSourceIds(itemLibraryPathDirectoryPathId)) .WillByDefault(Return(QmlDesigner::SmallSourceIds<4>{qtQuickSourceId, qtQuickControlSourceId})); setFilesRemoved({itemLibraryPathSourceId, qtQuickSourceId, qtQuickControlSourceId}); @@ -4704,10 +5070,10 @@ TEST_F(ProjectStorageUpdater, update_type_annotations_removed_directory) TEST_F(ProjectStorageUpdater, synchronize_added_property_editor_qml_paths_directory) { - setSubdirectoryPaths(u"/path/one", {"/path/one/designer"}); - SourceContextId designer1DirectoryId = sourcePathCache.sourceContextId("/path/one/designer"); - SourceId designer1SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer1DirectoryId); - setFilesDontChanged({path1SourceId}); + setFileSystemSubdirectories(u"/path/one", {"/path/one/designer"}); + DirectoryPathId designer1DirectoryId = sourcePathCache.directoryPathId("/path/one/designer"); + SourceId designer1SourceId = SourceId::create(designer1DirectoryId, QmlDesigner::FileNameId{}); + setFilesUnchanged({path1SourceId}); setFilesAdded({designer1SourceId}); EXPECT_CALL(projectStorageMock, @@ -4731,17 +5097,17 @@ TEST_F(ProjectStorageUpdater, synchronize_added_property_editor_qml_paths_direct IsEmpty()), Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, - UnorderedElementsAre(path1SourceContextId))))); + UnorderedElementsAre(path1DirectoryPathId))))); updater.update({.projectDirectory = "/path/one"}); } TEST_F(ProjectStorageUpdater, synchronize_changed_property_editor_qml_paths_directory) { - setSubdirectoryPaths(u"/path/one", {"/path/one/designer"}); - SourceContextId designer1DirectoryId = sourcePathCache.sourceContextId("/path/one/designer"); - SourceId designer1SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer1DirectoryId); - setFilesDontChanged({path1SourceId}); + setFileSystemSubdirectories(u"/path/one", {"/path/one/designer"}); + DirectoryPathId designer1DirectoryId = sourcePathCache.directoryPathId("/path/one/designer"); + SourceId designer1SourceId = SourceId::create(designer1DirectoryId, QmlDesigner::FileNameId{}); + setFilesUnchanged({path1SourceId}); setFilesChanged({designer1SourceId}); EXPECT_CALL(projectStorageMock, @@ -4765,18 +5131,18 @@ TEST_F(ProjectStorageUpdater, synchronize_changed_property_editor_qml_paths_dire IsEmpty()), Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, - UnorderedElementsAre(path1SourceContextId))))); + UnorderedElementsAre(path1DirectoryPathId))))); updater.update({.projectDirectory = "/path/one"}); } TEST_F(ProjectStorageUpdater, dont_synchronize_empty_property_editor_qml_paths_directory) { - setSubdirectoryPaths(u"/path/two", {}); - SourceContextId designer2DirectoryId = sourcePathCache.sourceContextId("/path/two/designer"); - SourceId designer2SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer2DirectoryId); + setFileSystemSubdirectories(u"/path/two", {}); + DirectoryPathId designer2DirectoryId = sourcePathCache.directoryPathId("/path/two/designer"); + SourceId designer2SourceId = SourceId::create(designer2DirectoryId, QmlDesigner::FileNameId{}); setFilesChanged({path2SourceId}); - setFilesDontExists({designer2SourceId}); + setFilesNotExists({designer2SourceId}); EXPECT_CALL(projectStorageMock, synchronize( @@ -4798,16 +5164,16 @@ TEST_F(ProjectStorageUpdater, dont_synchronize_empty_property_editor_qml_paths_d IsEmpty()), Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, - UnorderedElementsAre(path2SourceContextId))))); + UnorderedElementsAre(path2DirectoryPathId))))); updater.update({.projectDirectory = "/path/two"}); } TEST_F(ProjectStorageUpdater, remove_property_editor_qml_paths_if_designer_directory_is_removed) { - SourceContextId designer1DirectoryId = sourcePathCache.sourceContextId("/path/one/designer"); - SourceId designer1SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer1DirectoryId); - setFilesDontChanged({path1SourceId, qmldir1SourceId}); + DirectoryPathId designer1DirectoryId = sourcePathCache.directoryPathId("/path/one/designer"); + SourceId designer1SourceId = SourceId::create(designer1DirectoryId, QmlDesigner::FileNameId{}); + setFilesUnchanged({path1SourceId, qmldir1SourceId}); setFilesRemoved({designer1SourceId}); EXPECT_CALL(projectStorageMock, @@ -4829,7 +5195,7 @@ TEST_F(ProjectStorageUpdater, remove_property_editor_qml_paths_if_designer_direc IsEmpty()), Field("SynchronizationPackage::updatedDirectoryInfoDirectoryIds", &SynchronizationPackage::updatedDirectoryInfoDirectoryIds, - UnorderedElementsAre(path1SourceContextId))))); + UnorderedElementsAre(path1DirectoryPathId))))); updater.update({.projectDirectory = "/path/one"}); } @@ -4837,19 +5203,19 @@ TEST_F(ProjectStorageUpdater, remove_property_editor_qml_paths_if_designer_direc TEST_F(ProjectStorageUpdater, synchronize_property_editor_qml_paths_directory_if_designer_directory_is_changed) { - setSubdirectoryPaths(u"/path/one", {"/path/one/designer"}); + setFileSystemSubdirectories(u"/path/one", {"/path/one/designer"}); QString qmldir{R"(module Bar)"}; setContent(u"/path/one/qmldir", qmldir); - SourceContextId designer1DirectoryId = sourcePathCache.sourceContextId("/path/one/designer"); + DirectoryPathId designer1DirectoryId = sourcePathCache.directoryPathId("/path/one/designer"); SourceId propertyEditorSpecificSourceId = sourcePathCache.sourceId( "/path/one/designer/FooSpecifics.qml"); SourceId propertyEditorSpecificDynamicSourceId = sourcePathCache.sourceId( "/path/one/designer/HuoSpecificsDynamic.qml"); SourceId propertyEditorPaneSourceId = sourcePathCache.sourceId( "/path/one/designer/CaoPane.qml"); - SourceId designer1SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer1DirectoryId); + SourceId designer1SourceId = SourceId::create(designer1DirectoryId, QmlDesigner::FileNameId{}); setFilesChanged({designer1SourceId}); - setFilesDontChanged({path1SourceId, qmldir1SourceId}); + setFilesUnchanged({path1SourceId, qmldir1SourceId}); auto barModuleId = storage.moduleId("Bar", ModuleKind::QmlLibrary); setFileNames(u"/path/one/designer", {"FooSpecifics.qml", "HuoSpecificsDynamic.qml", "CaoPane.qml"}, @@ -4881,19 +5247,19 @@ TEST_F(ProjectStorageUpdater, TEST_F(ProjectStorageUpdater, synchronize_property_editor_qml_paths_directory_if_qml_directory_is_changed) { - setSubdirectoryPaths(u"/path/one", {"/path/one/designer"}); + setFileSystemSubdirectories(u"/path/one", {"/path/one/designer"}); QString qmldir{R"(module Bar)"}; setContent(u"/path/one/qmldir", qmldir); - SourceContextId designer1DirectoryId = sourcePathCache.sourceContextId("/path/one/designer"); + DirectoryPathId designer1DirectoryId = sourcePathCache.directoryPathId("/path/one/designer"); SourceId propertyEditorSpecificSourceId = sourcePathCache.sourceId( "/path/one/designer/FooSpecifics.qml"); SourceId propertyEditorSpecificDynamicSourceId = sourcePathCache.sourceId( "/path/one/designer/HuoSpecificsDynamic.qml"); SourceId propertyEditorPaneSourceId = sourcePathCache.sourceId( "/path/one/designer/CaoPane.qml"); - SourceId designer1SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer1DirectoryId); + SourceId designer1SourceId = SourceId::create(designer1DirectoryId, QmlDesigner::FileNameId{}); setFilesChanged({path1SourceId}); - setFilesDontChanged({qmldir1SourceId, designer1SourceId}); + setFilesUnchanged({qmldir1SourceId, designer1SourceId}); auto barModuleId = storage.moduleId("Bar", ModuleKind::QmlLibrary); setFileNames(u"/path/one/designer", {"FooSpecifics.qml", "HuoSpecificsDynamic.qml", "CaoPane.qml"}, @@ -4924,19 +5290,19 @@ TEST_F(ProjectStorageUpdater, TEST_F(ProjectStorageUpdater, synchronize_property_editor_qml_paths_directory_if_qmldir_is_changed) { - setSubdirectoryPaths(u"/path/one", {"/path/one/designer"}); + setFileSystemSubdirectories(u"/path/one", {"/path/one/designer"}); QString qmldir{R"(module Bar)"}; setContent(u"/path/one/qmldir", qmldir); - SourceContextId designer1DirectoryId = sourcePathCache.sourceContextId("/path/one/designer"); + DirectoryPathId designer1DirectoryId = sourcePathCache.directoryPathId("/path/one/designer"); SourceId propertyEditorSpecificSourceId = sourcePathCache.sourceId( "/path/one/designer/FooSpecifics.qml"); SourceId propertyEditorSpecificDynamicSourceId = sourcePathCache.sourceId( "/path/one/designer/HuoSpecificsDynamic.qml"); SourceId propertyEditorPaneSourceId = sourcePathCache.sourceId( "/path/one/designer/CaoPane.qml"); - SourceId designer1SourceId = SourceId::create(QmlDesigner::SourceNameId{}, designer1DirectoryId); + SourceId designer1SourceId = SourceId::create(designer1DirectoryId, QmlDesigner::FileNameId{}); setFilesChanged({qmldir1SourceId}); - setFilesDontChanged({path1SourceId, designer1SourceId}); + setFilesUnchanged({path1SourceId, designer1SourceId}); auto barModuleId = storage.moduleId("Bar", ModuleKind::QmlLibrary); setFileNames(u"/path/one/designer", {"FooSpecifics.qml", "HuoSpecificsDynamic.qml", "CaoPane.qml"}, diff --git a/tests/unit/tests/unittests/projectstorage/qmldocumentparser-test.cpp b/tests/unit/tests/unittests/projectstorage/qmldocumentparser-test.cpp index 848d76082bb..fb1df11c115 100644 --- a/tests/unit/tests/unittests/projectstorage/qmldocumentparser-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/qmldocumentparser-test.cpp @@ -18,7 +18,7 @@ namespace { namespace Storage = QmlDesigner::Storage; namespace Synchronization = Storage::Synchronization; using QmlDesigner::ModuleId; -using QmlDesigner::SourceContextId; +using QmlDesigner::DirectoryPathId; using QmlDesigner::SourceId; using QmlDesigner::Storage::ModuleKind; using Storage::TypeTraits; @@ -158,8 +158,8 @@ protected: QmlDesigner::QmlDocumentParser parser{storage, sourcePathCache}; Storage::Imports imports; SourceId qmlFileSourceId{sourcePathCache.sourceId("/path/to/qmlfile.qml")}; - SourceContextId qmlFileSourceContextId{qmlFileSourceId.contextId()}; - Utils::PathString directoryPath{sourcePathCache.sourceContextPath(qmlFileSourceContextId)}; + DirectoryPathId qmlFileDirectoryPathId{qmlFileSourceId.directoryPathId()}; + Utils::PathString directoryPath{sourcePathCache.directoryPath(qmlFileDirectoryPathId)}; ModuleId directoryModuleId{storage.moduleId(directoryPath, ModuleKind::PathLibrary)}; }; diff --git a/tests/unit/tests/unittests/projectstorage/qmltypesparser-test.cpp b/tests/unit/tests/unittests/projectstorage/qmltypesparser-test.cpp index d25dc12a83a..089e65b9188 100644 --- a/tests/unit/tests/unittests/projectstorage/qmltypesparser-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/qmltypesparser-test.cpp @@ -17,7 +17,7 @@ namespace { namespace Storage = QmlDesigner::Storage; namespace Synchronization = QmlDesigner::Storage::Synchronization; using QmlDesigner::ModuleId; -using QmlDesigner::SourceContextId; +using QmlDesigner::DirectoryPathId; using QmlDesigner::SourceId; using QmlDesigner::Storage::ModuleKind; @@ -196,11 +196,11 @@ protected: Synchronization::Types types; SourceId qmltypesFileSourceId{sourcePathCache.sourceId("path/to/types.qmltypes")}; ModuleId qtQmlNativeModuleId = storage.moduleId("QtQml", ModuleKind::CppLibrary); - Synchronization::DirectoryInfo directoryInfo{qmltypesFileSourceId.contextId(), + Synchronization::DirectoryInfo directoryInfo{qmltypesFileSourceId.directoryPathId(), qmltypesFileSourceId, qtQmlNativeModuleId, Synchronization::FileType::QmlTypes}; - SourceContextId qmltypesFileSourceContextId{qmltypesFileSourceId.contextId()}; + DirectoryPathId qmltypesFileDirectoryPathId{qmltypesFileSourceId.directoryPathId()}; }; TEST_F(QmlTypesParser, imports) @@ -893,7 +893,7 @@ TEST_F(QmlTypesParser, default_property) TEST_F(QmlTypesParser, skip_template_item) { ModuleId moduleId = storage.moduleId("QtQuick.Templates", ModuleKind::CppLibrary); - Synchronization::DirectoryInfo directoryInfo{qmltypesFileSourceId.contextId(), + Synchronization::DirectoryInfo directoryInfo{qmltypesFileSourceId.directoryPathId(), qmltypesFileSourceId, moduleId, Synchronization::FileType::QmlTypes}; diff --git a/tests/unit/tests/unittests/projectstorage/typeannotationreader-test.cpp b/tests/unit/tests/unittests/projectstorage/typeannotationreader-test.cpp index d802289dabb..f6ea2472f51 100644 --- a/tests/unit/tests/unittests/projectstorage/typeannotationreader-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/typeannotationreader-test.cpp @@ -53,7 +53,7 @@ protected: QmlDesigner::ProjectStorage &storage = staticData->storage; QmlDesigner::Storage::TypeAnnotationReader reader{storage}; QmlDesigner::SourceId sourceId = QmlDesigner::SourceId::create(33); - QmlDesigner::SourceContextId directoryId = QmlDesigner::SourceContextId::create(77); + QmlDesigner::DirectoryPathId directoryId = QmlDesigner::DirectoryPathId::create(77); QmlDesigner::Storage::TypeTraits traits; }; diff --git a/tests/unit/tests/unittests/sourcepathstorage/sourcepathcache-test.cpp b/tests/unit/tests/unittests/sourcepathstorage/sourcepathcache-test.cpp index ea10cde418e..70c9062e3fd 100644 --- a/tests/unit/tests/unittests/sourcepathstorage/sourcepathcache-test.cpp +++ b/tests/unit/tests/unittests/sourcepathstorage/sourcepathcache-test.cpp @@ -10,13 +10,13 @@ namespace { -using QmlDesigner::SourceContextId; +using QmlDesigner::DirectoryPathId; using QmlDesigner::SourceId; using QmlDesigner::SourceIds; -using QmlDesigner::SourceNameId; +using QmlDesigner::FileNameId; using Cache = QmlDesigner::SourcePathCache>; using NFP = QmlDesigner::SourcePath; -using QmlDesigner::Cache::SourceName; +using QmlDesigner::Cache::FileName; using QmlDesigner::SourcePathView; using QmlDesigner::SourcePathViews; @@ -25,48 +25,48 @@ class SourcePathCache : public testing::Test protected: SourcePathCache() { - ON_CALL(storageMock, fetchSourceContextId(Eq("/path/to"))).WillByDefault(Return(sourceContextId5)); - ON_CALL(storageMock, fetchSourceContextId(Eq("/path2/to"))).WillByDefault(Return(sourceContextId6)); - ON_CALL(storageMock, fetchSourceNameId(Eq("file.cpp"))).WillByDefault(Return(sourceNameId42)); - ON_CALL(storageMock, fetchSourceNameId(Eq("file2.cpp"))).WillByDefault(Return(sourceNameId63)); - ON_CALL(storageMock, fetchSourceContextPath(sourceContextId5)) + ON_CALL(storageMock, fetchDirectoryPathId(Eq("/path/to"))).WillByDefault(Return(directoryPathId5)); + ON_CALL(storageMock, fetchDirectoryPathId(Eq("/path2/to"))).WillByDefault(Return(directoryPathId6)); + ON_CALL(storageMock, fetchFileNameId(Eq("file.cpp"))).WillByDefault(Return(fileNameId42)); + ON_CALL(storageMock, fetchFileNameId(Eq("file2.cpp"))).WillByDefault(Return(fileNameId63)); + ON_CALL(storageMock, fetchDirectoryPath(directoryPathId5)) .WillByDefault(Return(Utils::PathString("/path/to"))); - ON_CALL(storageMock, fetchSourceName(sourceNameId42)).WillByDefault(Return("file.cpp")); - ON_CALL(storageMockFilled, fetchAllSourceNames()) - .WillByDefault(Return(std::vector( - {{"file.cpp", sourceNameId42}, {"file2.cpp", sourceNameId63}}))); - ON_CALL(storageMockFilled, fetchAllSourceContexts()) - .WillByDefault(Return(std::vector( - {{"/path2/to", sourceContextId6}, {"/path/to", sourceContextId5}}))); - ON_CALL(storageMockFilled, fetchSourceContextId(Eq("/path/to"))) - .WillByDefault(Return(sourceContextId5)); - ON_CALL(storageMockFilled, fetchSourceNameId(Eq("file.cpp"))).WillByDefault(Return(sourceNameId42)); + ON_CALL(storageMock, fetchFileName(fileNameId42)).WillByDefault(Return("file.cpp")); + ON_CALL(storageMockFilled, fetchAllFileNames()) + .WillByDefault(Return(std::vector( + {{"file.cpp", fileNameId42}, {"file2.cpp", fileNameId63}}))); + ON_CALL(storageMockFilled, fetchAllDirectoryPaths()) + .WillByDefault(Return(std::vector( + {{"/path2/to", directoryPathId6}, {"/path/to", directoryPathId5}}))); + ON_CALL(storageMockFilled, fetchDirectoryPathId(Eq("/path/to"))) + .WillByDefault(Return(directoryPathId5)); + ON_CALL(storageMockFilled, fetchFileNameId(Eq("file.cpp"))).WillByDefault(Return(fileNameId42)); } protected: - SourceNameId sourceNameId42 = SourceNameId::create(42); - SourceNameId sourceNameId63 = SourceNameId::create(63); - SourceContextId sourceContextId5 = SourceContextId::create(5); - SourceContextId sourceContextId6 = SourceContextId::create(6); - SourceId sourceId542 = SourceId::create(sourceNameId42, sourceContextId5); - SourceId sourceId563 = SourceId::create(sourceNameId63, sourceContextId5); - SourceId sourceId642 = SourceId::create(sourceNameId42, sourceContextId6); + FileNameId fileNameId42 = FileNameId::create(42); + FileNameId fileNameId63 = FileNameId::create(63); + DirectoryPathId directoryPathId5 = DirectoryPathId::create(5); + DirectoryPathId directoryPathId6 = DirectoryPathId::create(6); + SourceId sourceId542 = SourceId::create(directoryPathId5, fileNameId42); + SourceId sourceId563 = SourceId::create(directoryPathId5, fileNameId63); + SourceId sourceId642 = SourceId::create(directoryPathId6, fileNameId42); NiceMock storageMock; Cache cache{storageMock}; NiceMock storageMockFilled; Cache cacheNotFilled{storageMockFilled}; }; -TEST_F(SourcePathCache, source_id_with_out_any_entry_call_source_context_id) +TEST_F(SourcePathCache, source_id_with_out_any_entry_call_directory_path_id) { - EXPECT_CALL(storageMock, fetchSourceContextId(Eq("/path/to"))); + EXPECT_CALL(storageMock, fetchDirectoryPathId(Eq("/path/to"))); cache.sourceId(SourcePathView("/path/to/file.cpp")); } TEST_F(SourcePathCache, source_id_with_out_any_entry_calls) { - EXPECT_CALL(storageMock, fetchSourceNameId(Eq("file.cpp"))); + EXPECT_CALL(storageMock, fetchFileNameId(Eq("file.cpp"))); cache.sourceId(SourcePathView("/path/to/file.cpp")); } @@ -78,11 +78,11 @@ TEST_F(SourcePathCache, source_id_of_source_id_with_out_any_entry) ASSERT_THAT(sourceId, sourceId542); } -TEST_F(SourcePathCache, source_id_with_source_context_id_and_source_name) +TEST_F(SourcePathCache, source_id_with_directory_path_id_and_file_name) { - auto sourceContextId = cache.sourceContextId("/path/to"_sv); + auto directoryPathId = cache.directoryPathId("/path/to"_sv); - auto sourceId = cache.sourceId(sourceContextId, "file.cpp"_sv); + auto sourceId = cache.sourceId(directoryPathId, "file.cpp"_sv); ASSERT_THAT(sourceId, sourceId542); } @@ -91,18 +91,19 @@ TEST_F(SourcePathCache, if_entry_exists_dont_call_in_strorage) { cache.sourceId(SourcePathView("/path/to/file.cpp")); - EXPECT_CALL(storageMock, fetchSourceContextId(Eq("/path/to"))).Times(0); - EXPECT_CALL(storageMock, fetchSourceNameId(Eq("file.cpp"))).Times(0); + EXPECT_CALL(storageMock, fetchDirectoryPathId(Eq("/path/to"))).Times(0); + EXPECT_CALL(storageMock, fetchFileNameId(Eq("file.cpp"))).Times(0); cache.sourceId(SourcePathView("/path/to/file.cpp")); } -TEST_F(SourcePathCache, if_directory_entry_exists_dont_call_fetch_source_context_id_but_still_call_fetch_source_id) +TEST_F(SourcePathCache, + if_directory_entry_exists_dont_call_fetch_directory_path_id_but_still_call_fetch_source_id) { cache.sourceId(SourcePathView("/path/to/file2.cpp")); - EXPECT_CALL(storageMock, fetchSourceContextId(Eq("/path/to"))).Times(0); - EXPECT_CALL(storageMock, fetchSourceNameId(Eq("file.cpp"))); + EXPECT_CALL(storageMock, fetchDirectoryPathId(Eq("/path/to"))).Times(0); + EXPECT_CALL(storageMock, fetchFileNameId(Eq("file.cpp"))); cache.sourceId(SourcePathView("/path/to/file.cpp")); } @@ -116,7 +117,7 @@ TEST_F(SourcePathCache, get_source_id_with_cached_value) ASSERT_THAT(sourceId, sourceId542); } -TEST_F(SourcePathCache, get_source_id_with_source_context_id_cached) +TEST_F(SourcePathCache, get_source_id_with_directory_path_id_cached) { cache.sourceId(SourcePathView("/path/to/file.cpp")); @@ -166,135 +167,135 @@ TEST_F(SourcePathCache, duplicate_file_paths_are_equal) ASSERT_THAT(sourcePath2Id, Eq(sourcePath1Id)); } -TEST_F(SourcePathCache, source_context_id_calls_fetch_source_context_id) +TEST_F(SourcePathCache, directory_path_id_calls_fetch_directory_path_id) { - EXPECT_CALL(storageMock, fetchSourceContextId(Eq("/path/to"))); + EXPECT_CALL(storageMock, fetchDirectoryPathId(Eq("/path/to"))); - cache.sourceContextId(Utils::SmallString("/path/to")); + cache.directoryPathId(Utils::SmallString("/path/to")); } -TEST_F(SourcePathCache, second_source_context_id_calls_not_fetch_source_context_id) +TEST_F(SourcePathCache, second_directory_path_id_calls_not_fetch_directory_path_id) { - cache.sourceContextId(Utils::SmallString("/path/to")); + cache.directoryPathId(Utils::SmallString("/path/to")); - EXPECT_CALL(storageMock, fetchSourceContextId(Eq("/path/to"))).Times(0); + EXPECT_CALL(storageMock, fetchDirectoryPathId(Eq("/path/to"))).Times(0); - cache.sourceContextId(Utils::SmallString("/path/to")); + cache.directoryPathId(Utils::SmallString("/path/to")); } -TEST_F(SourcePathCache, source_context_id_with_trailing_slash) +TEST_F(SourcePathCache, directory_path_id_with_trailing_slash) { - EXPECT_CALL(storageMock, fetchSourceContextId(Eq("/path/to"))); + EXPECT_CALL(storageMock, fetchDirectoryPathId(Eq("/path/to"))); - cache.sourceContextId(Utils::SmallString("/path/to/")); + cache.directoryPathId(Utils::SmallString("/path/to/")); } -TEST_F(SourcePathCache, source_context_id) +TEST_F(SourcePathCache, directory_path_id) { - auto id = cache.sourceContextId(Utils::SmallString("/path/to")); + auto id = cache.directoryPathId(Utils::SmallString("/path/to")); - ASSERT_THAT(id, Eq(sourceContextId5)); + ASSERT_THAT(id, Eq(directoryPathId5)); } -TEST_F(SourcePathCache, source_context_id_is_already_in_cache) +TEST_F(SourcePathCache, directory_path_id_is_already_in_cache) { - auto firstId = cache.sourceContextId(Utils::SmallString("/path/to")); + auto firstId = cache.directoryPathId(Utils::SmallString("/path/to")); - auto secondId = cache.sourceContextId(Utils::SmallString("/path/to")); + auto secondId = cache.directoryPathId(Utils::SmallString("/path/to")); ASSERT_THAT(secondId, firstId); } -TEST_F(SourcePathCache, source_context_id_is_already_in_cache_with_trailing_slash) +TEST_F(SourcePathCache, directory_path_id_is_already_in_cache_with_trailing_slash) { - auto firstId = cache.sourceContextId(Utils::SmallString("/path/to/")); + auto firstId = cache.directoryPathId(Utils::SmallString("/path/to/")); - auto secondId = cache.sourceContextId(Utils::SmallString("/path/to/")); + auto secondId = cache.directoryPathId(Utils::SmallString("/path/to/")); ASSERT_THAT(secondId, firstId); } -TEST_F(SourcePathCache, source_context_id_is_already_in_cache_with_and_without_trailing_slash) +TEST_F(SourcePathCache, directory_path_id_is_already_in_cache_with_and_without_trailing_slash) { - auto firstId = cache.sourceContextId(Utils::SmallString("/path/to/")); + auto firstId = cache.directoryPathId(Utils::SmallString("/path/to/")); - auto secondId = cache.sourceContextId(Utils::SmallString("/path/to")); + auto secondId = cache.directoryPathId(Utils::SmallString("/path/to")); ASSERT_THAT(secondId, firstId); } -TEST_F(SourcePathCache, source_context_id_is_already_in_cache_without_and_with_trailing_slash) +TEST_F(SourcePathCache, directory_path_id_is_already_in_cache_without_and_with_trailing_slash) { - auto firstId = cache.sourceContextId(Utils::SmallString("/path/to")); + auto firstId = cache.directoryPathId(Utils::SmallString("/path/to")); - auto secondId = cache.sourceContextId(Utils::SmallString("/path/to/")); + auto secondId = cache.directoryPathId(Utils::SmallString("/path/to/")); ASSERT_THAT(secondId, firstId); } TEST_F(SourcePathCache, throw_for_getting_a_directory_path_with_an_invalid_id) { - SourceContextId sourceContextId; + DirectoryPathId directoryPathId; - ASSERT_THROW(cache.sourceContextPath(sourceContextId), - QmlDesigner::NoSourceContextPathForInvalidSourceContextId); + ASSERT_THROW(cache.directoryPath(directoryPathId), + QmlDesigner::NoDirectoryPathForInvalidDirectoryPathId); } TEST_F(SourcePathCache, get_a_directory_path) { - SourceContextId sourceContextId{sourceContextId5}; + DirectoryPathId directoryPathId{directoryPathId5}; - auto sourceContextPath = cache.sourceContextPath(sourceContextId); + auto directoryPath = cache.directoryPath(directoryPathId); - ASSERT_THAT(sourceContextPath, Eq(Utils::SmallStringView{"/path/to"})); + ASSERT_THAT(directoryPath, Eq(Utils::SmallStringView{"/path/to"})); } -TEST_F(SourcePathCache, get_a_directory_path_with_cached_source_context_id) +TEST_F(SourcePathCache, get_a_directory_path_with_cached_directory_path_id) { - SourceContextId sourceContextId{sourceContextId5}; - cache.sourceContextPath(sourceContextId); + DirectoryPathId directoryPathId{directoryPathId5}; + cache.directoryPath(directoryPathId); - auto sourceContextPath = cache.sourceContextPath(sourceContextId); + auto directoryPath = cache.directoryPath(directoryPathId); - ASSERT_THAT(sourceContextPath, Eq(Utils::SmallStringView{"/path/to"})); + ASSERT_THAT(directoryPath, Eq(Utils::SmallStringView{"/path/to"})); } TEST_F(SourcePathCache, directory_path_calls_fetch_directory_path) { - EXPECT_CALL(storageMock, fetchSourceContextPath(Eq(sourceContextId5))); + EXPECT_CALL(storageMock, fetchDirectoryPath(Eq(directoryPathId5))); - cache.sourceContextPath(sourceContextId5); + cache.directoryPath(directoryPathId5); } TEST_F(SourcePathCache, second_directory_path_calls_not_fetch_directory_path) { - cache.sourceContextPath(sourceContextId5); + cache.directoryPath(directoryPathId5); - EXPECT_CALL(storageMock, fetchSourceContextPath(_)).Times(0); + EXPECT_CALL(storageMock, fetchDirectoryPath(_)).Times(0); - cache.sourceContextPath(sourceContextId5); + cache.directoryPath(directoryPathId5); } -TEST_F(SourcePathCache, fetch_source_context_from_source_id) +TEST_F(SourcePathCache, fetch_directory_path_from_source_id) { - auto sourceContextId = sourceId542.contextId(); + auto directoryPathId = sourceId542.directoryPathId(); - ASSERT_THAT(sourceContextId, Eq(sourceContextId5)); + ASSERT_THAT(directoryPathId, Eq(directoryPathId5)); } -TEST_F(SourcePathCache, fetch_source_context_id_after_fetching_file_path_by_source_id) +TEST_F(SourcePathCache, fetch_directory_path_id_after_fetching_file_path_by_source_id) { cache.sourcePath(sourceId542); - auto sourceContextId = sourceId542.contextId(); + auto directoryPathId = sourceId542.directoryPathId(); - ASSERT_THAT(sourceContextId, Eq(sourceContextId5)); + ASSERT_THAT(directoryPathId, Eq(directoryPathId5)); } -TEST_F(SourcePathCache, fetch_all_source_contexts_and_sources_at_creation) +TEST_F(SourcePathCache, fetch_all_directory_paths_and_sources_at_creation) { - EXPECT_CALL(storageMock, fetchAllSourceContexts()); - EXPECT_CALL(storageMock, fetchAllSourceNames()); + EXPECT_CALL(storageMock, fetchAllDirectoryPaths()); + EXPECT_CALL(storageMock, fetchAllFileNames()); Cache cache{storageMock}; } @@ -308,20 +309,20 @@ TEST_F(SourcePathCache, get_file_id_in_filled_cache) ASSERT_THAT(id, Eq(sourceId642)); } -TEST_F(SourcePathCache, get_source_context_id_in_filled_cache) +TEST_F(SourcePathCache, get_directory_path_id_in_filled_cache) { Cache cacheFilled{storageMockFilled}; - auto id = sourceId542.contextId(); + auto id = sourceId542.directoryPathId(); - ASSERT_THAT(id, Eq(sourceContextId5)); + ASSERT_THAT(id, Eq(directoryPathId5)); } TEST_F(SourcePathCache, get_directory_path_in_filled_cache) { Cache cacheFilled{storageMockFilled}; - auto path = cacheFilled.sourceContextPath(sourceContextId5); + auto path = cacheFilled.directoryPath(directoryPathId5); ASSERT_THAT(path, Eq("/path/to")); } @@ -348,8 +349,8 @@ TEST_F(SourcePathCache, dont_populate_if_not_empty) { cacheNotFilled.sourceId("/path/to/file.cpp"); - EXPECT_CALL(storageMockFilled, fetchAllSourceContexts()).Times(0); - EXPECT_CALL(storageMockFilled, fetchAllSourceNames()).Times(0); + EXPECT_CALL(storageMockFilled, fetchAllDirectoryPaths()).Times(0); + EXPECT_CALL(storageMockFilled, fetchAllFileNames()).Times(0); cacheNotFilled.populateIfEmpty(); } @@ -358,7 +359,7 @@ TEST_F(SourcePathCache, get_directory_path_after_populate_if_empty) { cacheNotFilled.populateIfEmpty(); - auto path = cacheNotFilled.sourceContextPath(sourceContextId5); + auto path = cacheNotFilled.directoryPath(directoryPathId5); ASSERT_THAT(path, Eq("/path/to")); } @@ -372,78 +373,78 @@ TEST_F(SourcePathCache, get_file_path_after_populate_if_empty) ASSERT_THAT(path, Eq("/path/to/file.cpp")); } -TEST_F(SourcePathCache, source_name_id_calls_fetch_source_name_id) +TEST_F(SourcePathCache, file_name_id_calls_fetch_file_name_id) { - EXPECT_CALL(storageMock, fetchSourceNameId(Eq("file.cpp"))); + EXPECT_CALL(storageMock, fetchFileNameId(Eq("file.cpp"))); - cache.sourceNameId(Utils::SmallString("file.cpp")); + cache.fileNameId(Utils::SmallString("file.cpp")); } -TEST_F(SourcePathCache, second_source_name_id_calls_not_fetch_source_name_id) +TEST_F(SourcePathCache, second_file_name_id_calls_not_fetch_file_name_id) { - cache.sourceNameId(Utils::SmallString("file.cpp")); + cache.fileNameId(Utils::SmallString("file.cpp")); - EXPECT_CALL(storageMock, fetchSourceNameId(Eq("file.cpp"))).Times(0); + EXPECT_CALL(storageMock, fetchFileNameId(Eq("file.cpp"))).Times(0); - cache.sourceNameId(Utils::SmallString("file.cpp")); + cache.fileNameId(Utils::SmallString("file.cpp")); } -TEST_F(SourcePathCache, source_name_id) +TEST_F(SourcePathCache, file_name_id) { - auto id = cache.sourceNameId(Utils::SmallString("file.cpp")); + auto id = cache.fileNameId(Utils::SmallString("file.cpp")); - ASSERT_THAT(id, Eq(sourceNameId42)); + ASSERT_THAT(id, Eq(fileNameId42)); } -TEST_F(SourcePathCache, source_name_id_is_already_in_cache) +TEST_F(SourcePathCache, file_name_id_is_already_in_cache) { - auto firstId = cache.sourceNameId(Utils::SmallString("file.cpp")); + auto firstId = cache.fileNameId(Utils::SmallString("file.cpp")); - auto secondId = cache.sourceNameId(Utils::SmallString("file.cpp")); + auto secondId = cache.fileNameId(Utils::SmallString("file.cpp")); ASSERT_THAT(secondId, firstId); } -TEST_F(SourcePathCache, throw_for_getting_source_name_with_an_invalid_id) +TEST_F(SourcePathCache, throw_for_getting_file_name_with_an_invalid_id) { - SourceNameId sourceNameId; + FileNameId fileNameId; - ASSERT_THROW(cache.sourceName(sourceNameId), QmlDesigner::NoSourceNameForInvalidSourceNameId); + ASSERT_THROW(cache.fileName(fileNameId), QmlDesigner::NoFileNameForInvalidFileNameId); } -TEST_F(SourcePathCache, get_a_source_name) +TEST_F(SourcePathCache, get_a_file_name) { - SourceNameId sourceNameId{sourceNameId42}; + FileNameId fileNameId{fileNameId42}; - auto sourceName = cache.sourceName(sourceNameId); + auto fileName = cache.fileName(fileNameId); - ASSERT_THAT(sourceName, Eq(Utils::SmallStringView{"file.cpp"})); + ASSERT_THAT(fileName, Eq(Utils::SmallStringView{"file.cpp"})); } -TEST_F(SourcePathCache, get_a_source_name_with_cached_source_name_id) +TEST_F(SourcePathCache, get_a_file_name_with_cached_file_name_id) { - SourceNameId sourceNameId{sourceNameId42}; - cache.sourceName(sourceNameId); + FileNameId fileNameId{fileNameId42}; + cache.fileName(fileNameId); - auto sourceName = cache.sourceName(sourceNameId); + auto fileName = cache.fileName(fileNameId); - ASSERT_THAT(sourceName, Eq(Utils::SmallStringView{"file.cpp"})); + ASSERT_THAT(fileName, Eq(Utils::SmallStringView{"file.cpp"})); } -TEST_F(SourcePathCache, source_name_calls_fetch_source_name) +TEST_F(SourcePathCache, file_name_calls_fetch_file_name) { - EXPECT_CALL(storageMock, fetchSourceName(Eq(sourceNameId42))); + EXPECT_CALL(storageMock, fetchFileName(Eq(fileNameId42))); - cache.sourceName(sourceNameId42); + cache.fileName(fileNameId42); } -TEST_F(SourcePathCache, second_source_name_calls_not_fetch_source_name) +TEST_F(SourcePathCache, second_file_name_calls_not_fetch_file_name) { - cache.sourceName(sourceNameId42); + cache.fileName(fileNameId42); - EXPECT_CALL(storageMock, fetchSourceName(_)).Times(0); + EXPECT_CALL(storageMock, fetchFileName(_)).Times(0); - cache.sourceName(sourceNameId42); + cache.fileName(fileNameId42); } } // namespace diff --git a/tests/unit/tests/unittests/sourcepathstorage/sourcepathstorage-test.cpp b/tests/unit/tests/unittests/sourcepathstorage/sourcepathstorage-test.cpp index abc08bf21b1..34a07cc7b42 100644 --- a/tests/unit/tests/unittests/sourcepathstorage/sourcepathstorage-test.cpp +++ b/tests/unit/tests/unittests/sourcepathstorage/sourcepathstorage-test.cpp @@ -7,21 +7,21 @@ namespace { -using QmlDesigner::Cache::SourceContext; -using QmlDesigner::Cache::SourceName; -using QmlDesigner::SourceContextId; +using QmlDesigner::Cache::DirectoryPath; +using QmlDesigner::Cache::FileName; +using QmlDesigner::DirectoryPathId; using QmlDesigner::SourceId; using QmlDesigner::SourceIds; -using QmlDesigner::SourceNameId; +using QmlDesigner::FileNameId; -MATCHER_P2(IsSourceContext, +MATCHER_P2(IsDirectoryPath, id, value, - std::string(negation ? "isn't " : "is ") + PrintToString(SourceContext{value, id})) + std::string(negation ? "isn't " : "is ") + PrintToString(DirectoryPath{value, id})) { - const SourceContext &sourceContext = arg; + const DirectoryPath &directoryPath = arg; - return sourceContext.id == id && sourceContext.value == value; + return directoryPath.id == id && directoryPath.value == value; } class SourcePathStorage : public testing::Test @@ -43,14 +43,14 @@ protected: void addSomeDummyData() { - storage.fetchSourceContextId("/path/dummy"); - storage.fetchSourceContextId("/path/dummy2"); - storage.fetchSourceContextId("/path/"); + storage.fetchDirectoryPathId("/path/dummy"); + storage.fetchDirectoryPathId("/path/dummy2"); + storage.fetchDirectoryPathId("/path/"); - storage.fetchSourceNameId("foo"); - storage.fetchSourceNameId("dummy"); - storage.fetchSourceNameId("bar"); - storage.fetchSourceNameId("bar"); + storage.fetchFileNameId("foo"); + storage.fetchFileNameId("dummy"); + storage.fetchFileNameId("bar"); + storage.fetchFileNameId("bar"); } template @@ -67,112 +67,112 @@ protected: Sqlite::Database &database = staticData->database; }; -TEST_F(SourcePathStorage, fetch_source_context_id_returns_always_the_same_id_for_the_same_path) +TEST_F(SourcePathStorage, fetch_directory_path_id_returns_always_the_same_id_for_the_same_path) { - auto sourceContextId = storage.fetchSourceContextId("/path/to"); + auto directoryPathId = storage.fetchDirectoryPathId("/path/to"); - auto newSourceContextId = storage.fetchSourceContextId("/path/to"); + auto newDirectoryPathId = storage.fetchDirectoryPathId("/path/to"); - ASSERT_THAT(newSourceContextId, Eq(sourceContextId)); + ASSERT_THAT(newDirectoryPathId, Eq(directoryPathId)); } -TEST_F(SourcePathStorage, fetch_source_context_id_returns_not_the_same_id_for_different_path) +TEST_F(SourcePathStorage, fetch_directory_path_id_returns_not_the_same_id_for_different_path) { - auto sourceContextId = storage.fetchSourceContextId("/path/to"); + auto directoryPathId = storage.fetchDirectoryPathId("/path/to"); - auto newSourceContextId = storage.fetchSourceContextId("/path/to2"); + auto newDirectoryPathId = storage.fetchDirectoryPathId("/path/to2"); - ASSERT_THAT(newSourceContextId, Ne(sourceContextId)); + ASSERT_THAT(newDirectoryPathId, Ne(directoryPathId)); } -TEST_F(SourcePathStorage, fetch_source_context_path) +TEST_F(SourcePathStorage, fetch_directory_path_path) { - auto sourceContextId = storage.fetchSourceContextId("/path/to"); + auto directoryPathId = storage.fetchDirectoryPathId("/path/to"); - auto path = storage.fetchSourceContextPath(sourceContextId); + auto path = storage.fetchDirectoryPath(directoryPathId); ASSERT_THAT(path, Eq("/path/to")); } -TEST_F(SourcePathStorage, fetch_unknown_source_context_path_throws) +TEST_F(SourcePathStorage, fetch_unknown_directory_path_path_throws) { - ASSERT_THROW(storage.fetchSourceContextPath(SourceContextId::create(323)), - QmlDesigner::SourceContextIdDoesNotExists); + ASSERT_THROW(storage.fetchDirectoryPath(DirectoryPathId::create(323)), + QmlDesigner::DirectoryPathIdDoesNotExists); } -TEST_F(SourcePathStorage, fetch_all_source_contexts_are_empty_if_no_source_contexts_exists) +TEST_F(SourcePathStorage, fetch_all_directory_paths_are_empty_if_no_directory_paths_exists) { storage.clearSources(); - auto sourceContexts = storage.fetchAllSourceContexts(); + auto directoryPaths = storage.fetchAllDirectoryPaths(); - ASSERT_THAT(toValues(sourceContexts), IsEmpty()); + ASSERT_THAT(toValues(directoryPaths), IsEmpty()); } -TEST_F(SourcePathStorage, fetch_all_source_contexts) +TEST_F(SourcePathStorage, fetch_all_directory_paths) { storage.clearSources(); - auto sourceContextId = storage.fetchSourceContextId("/path/to"); - auto sourceContextId2 = storage.fetchSourceContextId("/path/to2"); + auto directoryPathId = storage.fetchDirectoryPathId("/path/to"); + auto directoryPathId2 = storage.fetchDirectoryPathId("/path/to2"); - auto sourceContexts = storage.fetchAllSourceContexts(); + auto directoryPaths = storage.fetchAllDirectoryPaths(); - ASSERT_THAT(toValues(sourceContexts), - UnorderedElementsAre(IsSourceContext(sourceContextId, "/path/to"), - IsSourceContext(sourceContextId2, "/path/to2"))); + ASSERT_THAT(toValues(directoryPaths), + UnorderedElementsAre(IsDirectoryPath(directoryPathId, "/path/to"), + IsDirectoryPath(directoryPathId2, "/path/to2"))); } TEST_F(SourcePathStorage, fetch_source_id_first_time) { addSomeDummyData(); - auto sourceNameId = storage.fetchSourceNameId("foo"); + auto fileNameId = storage.fetchFileNameId("foo"); - ASSERT_TRUE(sourceNameId.isValid()); + ASSERT_TRUE(fileNameId.isValid()); } TEST_F(SourcePathStorage, fetch_existing_source_id) { addSomeDummyData(); - auto createdSourceNameId = storage.fetchSourceNameId("foo"); + auto createdFileNameId = storage.fetchFileNameId("foo"); - auto sourceNameId = storage.fetchSourceNameId("foo"); + auto fileNameId = storage.fetchFileNameId("foo"); - ASSERT_THAT(sourceNameId, createdSourceNameId); + ASSERT_THAT(fileNameId, createdFileNameId); } TEST_F(SourcePathStorage, fetch_source_id_with_different_name_are_not_equal) { addSomeDummyData(); - auto sourceNameId2 = storage.fetchSourceNameId("foo"); + auto fileNameId2 = storage.fetchFileNameId("foo"); - auto sourceNameId = storage.fetchSourceNameId("foo2"); + auto fileNameId = storage.fetchFileNameId("foo2"); - ASSERT_THAT(sourceNameId, Ne(sourceNameId2)); + ASSERT_THAT(fileNameId, Ne(fileNameId2)); } -TEST_F(SourcePathStorage, fetch_source_name_and_source_context_id_for_non_existing_source_id) +TEST_F(SourcePathStorage, fetch_file_name_and_directory_path_id_for_non_existing_source_id) { - ASSERT_THROW(storage.fetchSourceName(SourceNameId::create(212)), - QmlDesigner::SourceNameIdDoesNotExists); + ASSERT_THROW(storage.fetchFileName(FileNameId::create(212)), + QmlDesigner::FileNameIdDoesNotExists); } -TEST_F(SourcePathStorage, fetch_source_name_for_non_existing_entry) +TEST_F(SourcePathStorage, fetch_file_name_for_non_existing_entry) { addSomeDummyData(); - auto sourceNameId = storage.fetchSourceNameId("foo"); + auto fileNameId = storage.fetchFileNameId("foo"); - auto sourceName = storage.fetchSourceName(sourceNameId); + auto fileName = storage.fetchFileName(fileNameId); - ASSERT_THAT(sourceName, Eq("foo")); + ASSERT_THAT(fileName, Eq("foo")); } TEST_F(SourcePathStorage, fetch_all_sources) { storage.clearSources(); - auto sources = storage.fetchAllSourceNames(); + auto sources = storage.fetchAllFileNames(); ASSERT_THAT(toValues(sources), IsEmpty()); } @@ -182,7 +182,7 @@ TEST_F(SourcePathStorage, fetch_source_id_unguarded_first_time) addSomeDummyData(); std::lock_guard lock{database}; - auto sourceId = storage.fetchSourceNameIdUnguarded("foo"); + auto sourceId = storage.fetchFileNameIdUnguarded("foo"); ASSERT_TRUE(sourceId.isValid()); } @@ -191,9 +191,9 @@ TEST_F(SourcePathStorage, fetch_existing_source_id_unguarded) { addSomeDummyData(); std::lock_guard lock{database}; - auto createdSourceId = storage.fetchSourceNameIdUnguarded("foo"); + auto createdSourceId = storage.fetchFileNameIdUnguarded("foo"); - auto sourceId = storage.fetchSourceNameIdUnguarded("foo"); + auto sourceId = storage.fetchFileNameIdUnguarded("foo"); ASSERT_THAT(sourceId, createdSourceId); } @@ -202,9 +202,9 @@ TEST_F(SourcePathStorage, fetch_source_id_unguarded_with_different_name_are_not_ { addSomeDummyData(); std::lock_guard lock{database}; - auto sourceId2 = storage.fetchSourceNameIdUnguarded("foo"); + auto sourceId2 = storage.fetchFileNameIdUnguarded("foo"); - auto sourceId = storage.fetchSourceNameIdUnguarded("foo2"); + auto sourceId = storage.fetchFileNameIdUnguarded("foo2"); ASSERT_THAT(sourceId, Ne(sourceId2)); } diff --git a/tests/unit/tests/unittests/sourcepathstorage/storagecache-test.cpp b/tests/unit/tests/unittests/sourcepathstorage/storagecache-test.cpp index 4b4850e26ae..feb521ddf52 100644 --- a/tests/unit/tests/unittests/sourcepathstorage/storagecache-test.cpp +++ b/tests/unit/tests/unittests/sourcepathstorage/storagecache-test.cpp @@ -14,42 +14,45 @@ namespace { -using QmlDesigner::SourceContextId; +using QmlDesigner::DirectoryPathId; using QmlDesigner::StorageCacheException; using Utils::compare; class StorageAdapter { public: - auto fetchId(Utils::SmallStringView view) const { return storage.fetchSourceContextId(view); } + auto fetchId(Utils::SmallStringView view) const { return storage.fetchDirectoryPathId(view); } - auto fetchValue(SourceContextId id) const { return storage.fetchSourceContextPath(id); } + auto fetchValue(DirectoryPathId id) const { return storage.fetchDirectoryPath(id); } - auto fetchAll() const { return storage.fetchAllSourceContexts(); } + auto fetchAll() const { return storage.fetchAllDirectoryPaths(); } ProjectStorageMock &storage; }; -auto less(Utils::SmallStringView first, Utils::SmallStringView second) -> bool +struct Less { - return Utils::compare(first, second) < 0; + bool operator()(Utils::SmallStringView first, Utils::SmallStringView second) const + { + return Utils::compare(first, second) < 0; + } }; using CacheWithMockLocking = QmlDesigner::StorageCache, - less, - QmlDesigner::Cache::SourceContext>; + Less, + QmlDesigner::Cache::DirectoryPath>; using CacheWithoutLocking = QmlDesigner::StorageCache, - less, - QmlDesigner::Cache::SourceContext>; + Less, + QmlDesigner::Cache::DirectoryPath>; template class StorageCache : public testing::Test @@ -64,17 +67,17 @@ protected: return std::lexicographical_compare(f.rbegin(), f.rend(), l.rbegin(), l.rend()); }); - ON_CALL(this->mockStorage, fetchSourceContextId(Eq("foo"))).WillByDefault(Return(id42)); - ON_CALL(this->mockStorage, fetchSourceContextId(Eq("bar"))).WillByDefault(Return(id43)); - ON_CALL(this->mockStorage, fetchSourceContextId(Eq("poo"))).WillByDefault(Return(id44)); - ON_CALL(this->mockStorage, fetchSourceContextId(Eq("taa"))).WillByDefault(Return(id45)); - ON_CALL(this->mockStorage, fetchSourceContextPath(this->id41)) + ON_CALL(this->mockStorage, fetchDirectoryPathId(Eq("foo"))).WillByDefault(Return(id42)); + ON_CALL(this->mockStorage, fetchDirectoryPathId(Eq("bar"))).WillByDefault(Return(id43)); + ON_CALL(this->mockStorage, fetchDirectoryPathId(Eq("poo"))).WillByDefault(Return(id44)); + ON_CALL(this->mockStorage, fetchDirectoryPathId(Eq("taa"))).WillByDefault(Return(id45)); + ON_CALL(this->mockStorage, fetchDirectoryPath(this->id41)) .WillByDefault(Return(Utils::PathString("bar"))); - ON_CALL(this->mockStorage, fetchSourceContextId(Eq(filePath1))).WillByDefault(Return(id1)); - ON_CALL(this->mockStorage, fetchSourceContextId(Eq(filePath2))).WillByDefault(Return(id2)); - ON_CALL(this->mockStorage, fetchSourceContextId(Eq(filePath3))).WillByDefault(Return(id3)); - ON_CALL(this->mockStorage, fetchSourceContextId(Eq(filePath4))).WillByDefault(Return(id4)); - ON_CALL(this->mockStorage, fetchSourceContextId(Eq(filePath5))).WillByDefault(Return(id5)); + ON_CALL(this->mockStorage, fetchDirectoryPathId(Eq(filePath1))).WillByDefault(Return(id1)); + ON_CALL(this->mockStorage, fetchDirectoryPathId(Eq(filePath2))).WillByDefault(Return(id2)); + ON_CALL(this->mockStorage, fetchDirectoryPathId(Eq(filePath3))).WillByDefault(Return(id3)); + ON_CALL(this->mockStorage, fetchDirectoryPathId(Eq(filePath4))).WillByDefault(Return(id4)); + ON_CALL(this->mockStorage, fetchDirectoryPathId(Eq(filePath5))).WillByDefault(Return(id5)); } protected: @@ -89,16 +92,16 @@ protected: Utils::PathString filePath5{"/file/pathFife"}; Utils::PathStringVector filePaths{filePath1, filePath2, filePath3, filePath4, filePath5}; Utils::PathStringVector reverseFilePaths{filePath1, filePath2, filePath3, filePath4, filePath5}; - SourceContextId id1{SourceContextId::create(1)}; - SourceContextId id2{SourceContextId::create(2)}; - SourceContextId id3{SourceContextId::create(3)}; - SourceContextId id4{SourceContextId::create(4)}; - SourceContextId id5{SourceContextId::create(5)}; - SourceContextId id41{SourceContextId::create(41)}; - SourceContextId id42{SourceContextId::create(42)}; - SourceContextId id43{SourceContextId::create(43)}; - SourceContextId id44{SourceContextId::create(44)}; - SourceContextId id45{SourceContextId::create(45)}; + DirectoryPathId id1{DirectoryPathId::create(1)}; + DirectoryPathId id2{DirectoryPathId::create(2)}; + DirectoryPathId id3{DirectoryPathId::create(3)}; + DirectoryPathId id4{DirectoryPathId::create(4)}; + DirectoryPathId id5{DirectoryPathId::create(5)}; + DirectoryPathId id41{DirectoryPathId::create(41)}; + DirectoryPathId id42{DirectoryPathId::create(42)}; + DirectoryPathId id43{DirectoryPathId::create(43)}; + DirectoryPathId id44{DirectoryPathId::create(44)}; + DirectoryPathId id45{DirectoryPathId::create(45)}; }; using CacheTypes = ::testing::Types; @@ -217,8 +220,8 @@ TYPED_TEST(StorageCache, is_not_empty_after_populate_with_some_entries) typename TypeParam::CacheEntries entries{{this->filePath1, this->id1}, {this->filePath2, this->id4}, {this->filePath3, this->id3}, - {this->filePath4, SourceContextId::create(5)}}; - ON_CALL(this->mockStorage, fetchAllSourceContexts()).WillByDefault(Return(entries)); + {this->filePath4, DirectoryPathId::create(5)}}; + ON_CALL(this->mockStorage, fetchAllDirectoryPaths()).WillByDefault(Return(entries)); this->cache.uncheckedPopulate(); @@ -229,12 +232,12 @@ TYPED_TEST(StorageCache, get_entry_after_populate_with_some_entries) { typename TypeParam::CacheEntries entries{{this->filePath1, this->id1}, {this->filePath2, this->id2}, - {this->filePath3, SourceContextId::create(7)}, + {this->filePath3, DirectoryPathId::create(7)}, {this->filePath4, this->id4}}; - ON_CALL(this->mockStorage, fetchAllSourceContexts()).WillByDefault(Return(entries)); + ON_CALL(this->mockStorage, fetchAllDirectoryPaths()).WillByDefault(Return(entries)); this->cache.uncheckedPopulate(); - auto value = this->cache.value(SourceContextId::create(7)); + auto value = this->cache.value(DirectoryPathId::create(7)); ASSERT_THAT(value, this->filePath3); } @@ -245,7 +248,7 @@ TYPED_TEST(StorageCache, entries_have_unique_ids) {this->filePath2, this->id2}, {this->filePath3, this->id3}, {this->filePath4, this->id3}}; - ON_CALL(this->mockStorage, fetchAllSourceContexts()).WillByDefault(Return(entries)); + ON_CALL(this->mockStorage, fetchAllDirectoryPaths()).WillByDefault(Return(entries)); ASSERT_THROW(this->cache.populate(), StorageCacheException); } @@ -256,7 +259,7 @@ TYPED_TEST(StorageCache, multiple_entries) {this->filePath1, this->id2}, {this->filePath3, this->id3}, {this->filePath4, this->id4}}; - ON_CALL(this->mockStorage, fetchAllSourceContexts()).WillByDefault(Return(entries)); + ON_CALL(this->mockStorage, fetchAllDirectoryPaths()).WillByDefault(Return(entries)); ASSERT_THROW(this->cache.populate(), StorageCacheException); } @@ -280,7 +283,7 @@ TYPED_TEST(StorageCache, id_with_storage_function_is_read_and_write_locked_for_u EXPECT_CALL(this->mockMutex, lock_shared()); EXPECT_CALL(this->mockMutex, unlock_shared()); EXPECT_CALL(this->mockMutex, lock()); - EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("foo"))); + EXPECT_CALL(this->mockStorage, fetchDirectoryPathId(Eq("foo"))); EXPECT_CALL(this->mockMutex, unlock()); this->cache.id("foo"); @@ -294,7 +297,7 @@ TYPED_TEST(StorageCache, id_with_storage_function_is_read_locked_for_known_entry EXPECT_CALL(this->mockMutex, lock_shared()); EXPECT_CALL(this->mockMutex, unlock_shared()); EXPECT_CALL(this->mockMutex, lock()).Times(0); - EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("foo"))).Times(0); + EXPECT_CALL(this->mockStorage, fetchDirectoryPathId(Eq("foo"))).Times(0); EXPECT_CALL(this->mockMutex, unlock()).Times(0); this->cache.id("foo"); @@ -355,7 +358,7 @@ TYPED_TEST(StorageCache, value_with_storage_function_is_read_and_write_locked_fo EXPECT_CALL(this->mockMutex, lock_shared()); EXPECT_CALL(this->mockMutex, unlock_shared()); EXPECT_CALL(this->mockMutex, lock()); - EXPECT_CALL(this->mockStorage, fetchSourceContextPath(Eq(this->id41))); + EXPECT_CALL(this->mockStorage, fetchDirectoryPath(Eq(this->id41))); EXPECT_CALL(this->mockMutex, unlock()); this->cache.value(this->id41); @@ -369,7 +372,7 @@ TYPED_TEST(StorageCache, value_with_storage_function_is_read_locked_for_known_id EXPECT_CALL(this->mockMutex, lock_shared()); EXPECT_CALL(this->mockMutex, unlock_shared()); EXPECT_CALL(this->mockMutex, lock()).Times(0); - EXPECT_CALL(this->mockStorage, fetchSourceContextPath(Eq(this->id41))).Times(0); + EXPECT_CALL(this->mockStorage, fetchDirectoryPath(Eq(this->id41))).Times(0); EXPECT_CALL(this->mockMutex, unlock()).Times(0); this->cache.value(this->id41); @@ -377,7 +380,7 @@ TYPED_TEST(StorageCache, value_with_storage_function_is_read_locked_for_known_id TYPED_TEST(StorageCache, id_with_storage_function_which_has_no_entry_is_calling_storage_function) { - EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("foo"))); + EXPECT_CALL(this->mockStorage, fetchDirectoryPathId(Eq("foo"))); this->cache.id("foo"); } @@ -386,7 +389,7 @@ TYPED_TEST(StorageCache, id_with_storage_function_which_has_entry_is_not_calling { this->cache.id("foo"); - EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("foo"))).Times(0); + EXPECT_CALL(this->mockStorage, fetchDirectoryPathId(Eq("foo"))).Times(0); this->cache.id("foo"); } @@ -416,24 +419,24 @@ TYPED_TEST(StorageCache, get_entry_by_index_after_inserting_by_custom_index) ASSERT_THAT(value, Eq("foo")); } -TYPED_TEST(StorageCache, call_fetch_source_context_path_for_lower_index) +TYPED_TEST(StorageCache, call_fetch_directory_path_path_for_lower_index) { auto index = this->cache.id("foo"); - SourceContextId lowerIndex{SourceContextId::create(index.internalId() - 1)}; + DirectoryPathId lowerIndex{DirectoryPathId::create(index.internalId() - 1)}; - EXPECT_CALL(this->mockStorage, fetchSourceContextPath(Eq(lowerIndex))); + EXPECT_CALL(this->mockStorage, fetchDirectoryPath(Eq(lowerIndex))); this->cache.value(lowerIndex); } -TYPED_TEST(StorageCache, call_fetch_source_context_path_for_unknown_index) +TYPED_TEST(StorageCache, call_fetch_directory_path_path_for_unknown_index) { - EXPECT_CALL(this->mockStorage, fetchSourceContextPath(Eq(this->id1))); + EXPECT_CALL(this->mockStorage, fetchDirectoryPath(Eq(this->id1))); this->cache.value(this->id1); } -TYPED_TEST(StorageCache, fetch_source_context_path_for_unknown_index) +TYPED_TEST(StorageCache, fetch_directory_path_path_for_unknown_index) { auto value = this->cache.value(this->id41); @@ -442,9 +445,9 @@ TYPED_TEST(StorageCache, fetch_source_context_path_for_unknown_index) TYPED_TEST(StorageCache, add_calls) { - EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("foo"))); - EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("bar"))); - EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("poo"))); + EXPECT_CALL(this->mockStorage, fetchDirectoryPathId(Eq("foo"))); + EXPECT_CALL(this->mockStorage, fetchDirectoryPathId(Eq("bar"))); + EXPECT_CALL(this->mockStorage, fetchDirectoryPathId(Eq("poo"))); this->cache.add({"foo", "bar", "poo"}); } @@ -453,8 +456,8 @@ TYPED_TEST(StorageCache, add_calls_only_for_new_values) { this->cache.add({"foo", "poo"}); - EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("taa"))); - EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("bar"))); + EXPECT_CALL(this->mockStorage, fetchDirectoryPathId(Eq("taa"))); + EXPECT_CALL(this->mockStorage, fetchDirectoryPathId(Eq("bar"))); this->cache.add({"foo", "bar", "poo", "taa"}); } @@ -501,14 +504,51 @@ TYPED_TEST(StorageCache, fetch_ids_from_storage_calls) EXPECT_CALL(this->mockMutex, lock_shared()); EXPECT_CALL(this->mockMutex, unlock_shared()); EXPECT_CALL(this->mockMutex, lock()); - EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("foo"))); + EXPECT_CALL(this->mockStorage, fetchDirectoryPathId(Eq("foo"))); EXPECT_CALL(this->mockMutex, unlock()); EXPECT_CALL(this->mockMutex, lock_shared()); EXPECT_CALL(this->mockMutex, unlock_shared()); EXPECT_CALL(this->mockMutex, lock()); - EXPECT_CALL(this->mockStorage, fetchSourceContextId(Eq("bar"))); + EXPECT_CALL(this->mockStorage, fetchDirectoryPathId(Eq("bar"))); EXPECT_CALL(this->mockMutex, unlock()); this->cache.ids({"foo", "bar"}); } + +TYPED_TEST(StorageCache, getting_ids_that_start_with_po) +{ + ON_CALL(this->mockStorage, fetchDirectoryPathId(Eq("poh"))).WillByDefault(Return(this->id43)); + this->cache.add({"poo", "foo", "poh", "taa"}); + auto projection = [](Utils::SmallStringView text) -> Utils::SmallStringView { + return text.substr(0, 2); + }; + + auto ids = this->cache.template ids<4>("po", projection); + + ASSERT_THAT(ids, UnorderedElementsAre(this->id43, this->id44)); +} + +TYPED_TEST(StorageCache, getting_no_ids_if_there_is_no_entry_starts_with_oh) +{ + this->cache.add({"poo", "taa", "foo", "bar"}); + auto projection = [](Utils::SmallStringView text) -> Utils::SmallStringView { + return text.substr(0, 2); + }; + + auto ids = this->cache.template ids<4>("oh", projection); + + ASSERT_THAT(ids, IsEmpty()); +} + +TYPED_TEST(StorageCache, get_all_ids_if_the_string_is_empty) +{ + this->cache.add({"foo", "bar", "poo", "taa"}); + auto projection = [](Utils::SmallStringView text) -> Utils::SmallStringView { + return text.substr(0, 0); + }; + + auto ids = this->cache.template ids<4>("", projection); + + ASSERT_THAT(ids, UnorderedElementsAre(this->id42, this->id43, this->id44, this->id45)); +} } // namespace diff --git a/tests/unit/tests/utils/google-using-declarations.h b/tests/unit/tests/utils/google-using-declarations.h index 213608916fb..ea781e59dbc 100644 --- a/tests/unit/tests/utils/google-using-declarations.h +++ b/tests/unit/tests/utils/google-using-declarations.h @@ -4,6 +4,7 @@ #pragma once #include +#include using testing::_; using testing::A; @@ -17,6 +18,7 @@ using testing::AtMost; using testing::Between; using testing::ByMove; using testing::ByRef; +using testing::Conditional; using testing::ContainerEq; using testing::Contains; using testing::Each;