diff --git a/cmake/Utils.cmake b/cmake/Utils.cmake index eca19a7dd0b..64473a926c2 100644 --- a/cmake/Utils.cmake +++ b/cmake/Utils.cmake @@ -61,7 +61,7 @@ function(setup_dependencies_component) endfunction() function(configure_qml_designer Qt6_VERSION) - set(QMLDESIGNER_QT6_REQUIRED_VERSION 6.5.4) + set(QMLDESIGNER_QT6_REQUIRED_VERSION 6.7.3) set(QMLDESIGNER_GCC_REQUIRED_VERSION 10.0) set(QMLDESIGNER_CLANG_REQUIRED_VERSION 13.0) set(QMLDESIGNER_APPLECLANG_REQUIRED_VERSION 15.0) diff --git a/dist/branding/qtdesignstudio/QtCreatorIDEBranding.cmake b/dist/branding/qtdesignstudio/QtCreatorIDEBranding.cmake index eb676b209fc..2e889d88be1 100644 --- a/dist/branding/qtdesignstudio/QtCreatorIDEBranding.cmake +++ b/dist/branding/qtdesignstudio/QtCreatorIDEBranding.cmake @@ -32,6 +32,7 @@ set(DESIGNSTUDIO_PLUGINS DiffEditor EffectComposer FakeVim + Git Help Insight LanguageClient diff --git a/doc/qtcreator/src/external-resources/external-resources-qds.qdoc b/doc/qtcreator/src/external-resources/external-resources-qds.qdoc index c46066168e8..1cd90ae903f 100644 --- a/doc/qtcreator/src/external-resources/external-resources-qds.qdoc +++ b/doc/qtcreator/src/external-resources/external-resources-qds.qdoc @@ -105,6 +105,10 @@ \externalpage https://doc.qt.io/qt/linguist-id-based-i18n.html \title Text ID based translations */ +/*! + \externalpage https://www.qt.io/blog/qt-design-studio-4.6-released + \title Qt Design Studio 4.6 released +*/ /*! \externalpage https://www.qt.io/blog/qt-design-studio-4.5.1-released \title Qt Design Studio 4.5.1 released diff --git a/doc/qtdesignstudio/config/style/qt5-sidebar.html b/doc/qtdesignstudio/config/style/qt5-sidebar.html index 7ca7d5b1e65..f1e2fc4af57 100644 --- a/doc/qtdesignstudio/config/style/qt5-sidebar.html +++ b/doc/qtdesignstudio/config/style/qt5-sidebar.html @@ -12,103 +12,444 @@

Getting Started

-
- -
+
-

Wireframing

-
-
- -
-
-
-
-

Prototyping

+

Key Concepts

-
-
-
-

Motion Design

-
- -
-
-
-

Implementing Applications

-
- -
-
-
-

Advanced Designer Topics

-
- -
-
-
-

Developer Topics

-
-
+
-

Help

+

Working with

+ + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+

Best Practices

+
+ + + +
+ +
+
+

Tutorials

+
+ +
+ +
+
+

Examples

+
+ +
+ +
+
+

Reference

+
+ + + + + + +
\ No newline at end of file diff --git a/doc/qtdesignstudio/images/edit-list-model-model-editor.webp b/doc/qtdesignstudio/images/edit-list-model-model-editor.webp deleted file mode 100644 index e7f47c6402c..00000000000 Binary files a/doc/qtdesignstudio/images/edit-list-model-model-editor.webp and /dev/null differ diff --git a/doc/qtdesignstudio/images/model-editor-new-model.webp b/doc/qtdesignstudio/images/model-editor-new-model.webp deleted file mode 100644 index 6ea705a047b..00000000000 Binary files a/doc/qtdesignstudio/images/model-editor-new-model.webp and /dev/null differ diff --git a/doc/qtdesignstudio/images/repeater3d-model-editor.webp b/doc/qtdesignstudio/images/repeater3d-model-editor.webp deleted file mode 100644 index e0e60873668..00000000000 Binary files a/doc/qtdesignstudio/images/repeater3d-model-editor.webp and /dev/null differ diff --git a/doc/qtdesignstudio/images/studio-edit-list-model.webp b/doc/qtdesignstudio/images/studio-edit-list-model.webp new file mode 100644 index 00000000000..ce740ec6d26 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-edit-list-model.webp differ diff --git a/doc/qtdesignstudio/images/studio-feedback-popup-material.png b/doc/qtdesignstudio/images/studio-feedback-popup-material.png new file mode 100644 index 00000000000..2d935349bf1 Binary files /dev/null and b/doc/qtdesignstudio/images/studio-feedback-popup-material.png differ diff --git a/doc/qtdesignstudio/images/studio-feedback-popup.png b/doc/qtdesignstudio/images/studio-feedback-popup.png deleted file mode 100644 index 5a6d38bc050..00000000000 Binary files a/doc/qtdesignstudio/images/studio-feedback-popup.png and /dev/null differ diff --git a/doc/qtdesignstudio/src/components/qtquick-components.qdoc b/doc/qtdesignstudio/src/components/qtquick-components.qdoc index f512b8f67d4..a0ab80b2570 100644 --- a/doc/qtdesignstudio/src/components/qtquick-components.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-components.qdoc @@ -1,9 +1,9 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! \page quick-components.html - \previouspage studio-flow-external-events.html + \previouspage quick-uis.html \nextpage quick-preset-components.html \title Using Components diff --git a/doc/qtdesignstudio/src/components/qtquick-data-models.qdoc b/doc/qtdesignstudio/src/components/qtquick-data-models.qdoc index b93b745bc2c..2aa89a744dd 100644 --- a/doc/qtdesignstudio/src/components/qtquick-data-models.qdoc +++ b/doc/qtdesignstudio/src/components/qtquick-data-models.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! @@ -147,12 +147,12 @@ \uicontrol {Default Components} > \uicontrol Views to the \uicontrol Navigator or \uicontrol {2D} view. \li Right-click the view in \uicontrol Navigator, and select - \uicontrol {Edit Model} in the context-menu to open the - \uicontrol {Model Editor} view. - \image edit-list-model-model-editor.webp "List view in Model Editor" - \li Double-click a cell to edit its value. - \li Use the toolbar buttons to add or remove rows and columns. - In a list, each column represents a property, and each row adds a + \uicontrol {Edit List Model} in the context-menu to open + the list model editor. + \image studio-edit-list-model.webp "List view in the list model editor" + \li Double-click the column headings and cells to change their values. + \li Use the toolbar buttons to add, remove, or move rows and columns. + In a list, each column represents a property and each row adds a list item. \endlist diff --git a/doc/qtdesignstudio/src/developers/studio-designer-developer-workflow.qdoc b/doc/qtdesignstudio/src/developers/studio-designer-developer-workflow.qdoc index 5b59d665971..78e90404542 100644 --- a/doc/qtdesignstudio/src/developers/studio-designer-developer-workflow.qdoc +++ b/doc/qtdesignstudio/src/developers/studio-designer-developer-workflow.qdoc @@ -39,6 +39,9 @@ \list \li Qt Creator 13.0 or above. \li \QDS 4.5 or above. + \li Git. + + \note Learn more about getting Git \l {https://wiki.qt.io/Git_Installation} {here}. \endlist \list 1 diff --git a/doc/qtdesignstudio/src/overviews/qtquick-animation-overview.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-animation-overview.qdoc index 86132b5ce1a..e6ae0295788 100644 --- a/doc/qtdesignstudio/src/overviews/qtquick-animation-overview.qdoc +++ b/doc/qtdesignstudio/src/overviews/qtquick-animation-overview.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! @@ -15,7 +15,7 @@ \list \li Common motion design techniques for 2D and 3D - \li Screen-to-screen or state-to-state animations + \li State-to-state animations \li Data-driven UI logic animations \endlist @@ -70,7 +70,7 @@ \section2 Animation Curves While easing curves work well for most simple UI animations, more complex - 3D animations require several keyframes so it becomes necessary to visualize + 3D animations require several keyframes, so it becomes necessary to visualize the value and the interpolation of a keyframe simultaneously. The \l {Curves} view visualizes the whole animation of a property at once and shows the effective values of a keyframe together with the interpolation @@ -78,36 +78,11 @@ simultaneously so that you can see the animation for the x position and the animation for the y position side-by-side. - \section1 Screen-to-Screen or State-to-State Animations + \section1 State-to-State Animations - The following table summarizes techniques used for navigating between - screens and UI states. - - \table - \header - \li Technique - \li Use Case - \row - \li \l{Designing Application Flows}{Application flows} - \li An interactive prototype that can be clicked through to simulate - the user experience of the application. - \row - \li \l{Transitions}{Transitions between states} - \li Transitions between different states of the UI using a transition - timeline that is based on keyframes. You can apply easing curves - to the keyframes. - \endtable - - \section2 Application Flows - - You can design an application in the form of a \e {schematic diagram} - that shows all the significant components of the application UI and their - interconnections by means of symbols. This results in an interactive - prototype that can be clicked through to simulate the user experience of - the application. Code is created in the background and can be used - as the base of the production version of the application. - - For more information, see \l{Designing Application Flows}. + To navigate between UI states, use transitions between different states of the UI + using a transition timeline that is based on keyframes. You can apply easing + curves to the keyframes. \section2 Transitions Between States diff --git a/doc/qtdesignstudio/src/overviews/qtquick-motion-design.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-motion-design.qdoc index 382c2f5fea8..80e0a844507 100644 --- a/doc/qtdesignstudio/src/overviews/qtquick-motion-design.qdoc +++ b/doc/qtdesignstudio/src/overviews/qtquick-motion-design.qdoc @@ -1,4 +1,4 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! @@ -14,8 +14,8 @@ \li You can use different animation techniques for different purposes. \QDS supports common motion design techniques, such as timeline and keyframe based animation and easing - curves, as well as screen-to-screen or state-to-state - application flows and data-driven UI logic animation. + curves, as well as state-to-state application flows and + data-driven UI logic animation. \endtable \list diff --git a/doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc index 2f0aa723b8f..74063602795 100644 --- a/doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc +++ b/doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc @@ -1,10 +1,10 @@ -// Copyright (C) 2021 The Qt Company Ltd. +// Copyright (C) 2024 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! \page quick-uis.html \previouspage {Examples} - \nextpage studio-app-flows.html + \nextpage quick-components.html \title Wireframing @@ -38,15 +38,6 @@ the developer documentation by pressing \key F1. \list - - \li \l {Designing Application Flows} - - You can design an application in the form of a \e {schematic diagram} - that shows all significant components of an application UI and their - interconnections by means of symbols. This results in an - interactive prototype that can be clicked through to simulate - the user experience of the application. - \li \l {Using Components} \QDS comes with \e {preset components} that you can use in diff --git a/doc/qtdesignstudio/src/overviews/studio-user-feedback.qdoc b/doc/qtdesignstudio/src/overviews/studio-user-feedback.qdoc index db7d24cdba6..5feddcd2c97 100644 --- a/doc/qtdesignstudio/src/overviews/studio-user-feedback.qdoc +++ b/doc/qtdesignstudio/src/overviews/studio-user-feedback.qdoc @@ -16,7 +16,7 @@ \uicontrol Skip or \uicontrol Submit, the pop-up survey will not appear for the same feature again. - \image studio-feedback-popup.png "User feedback pop-up survey for Flow Editor" + \image studio-feedback-popup-material.png "User feedback pop-up survey for Material Browser" For the pop-up survey to appear, you must enable collecting statistics, and also allow collecting \uicontrol {4 - Detailed usage statistics} in diff --git a/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc deleted file mode 100644 index 1be7f143117..00000000000 --- a/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc +++ /dev/null @@ -1,707 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only - -/*! - \page studio-app-flows.html - \previouspage quick-uis.html - \nextpage studio-flow-view.html - - \title Designing Application Flows - - \image studio-flow-view.webp "Application flow in the 2D view" - - In \QDS, a \e {flow view} represents a schematic diagram. It consists of - \e {flow items} that represent the screens in the UI and \e {transition - lines} that connect them, thus illustrating the possible user pathways - through the UI. \e {Action areas} are clickable starting points for transition - lines. Attach effects to transition lines, such as fade or push, - to determine what users see when one flow item changes into another. - - Use \e {flow decisions} to set up alternative pathways between flow items in the UI. For - example, if user input determines which flow item should open next, test the different - scenarios in the prototype with the decision dialog where you can select which flow item to - show next. - - Especially on mobile and embedded platforms, the application might need to - react to external events from the platform, such as notifications or other - applications requiring the users' attention. Use \e {flow wildcards} - to determine the priority of flow items by adding them to allow and - block lists. - - To design application flows: - - \image studio-flow-steps.png "Designing application flows" - - \list 1 - \li Use a project wizard template to add a \uicontrol {Flow View} - component, as described in \l{Adding Flow Views}. - \li Use a project wizard template to add a \uicontrol {Flow Item} - component for each screen in the UI, as described in - \l{Adding Flow Items}. - \li Use context menu commands to add action areas and transitions, - as described in \l{Adding Action Areas and Transitions}. - \endlist - - Additionally, to create a more advanced application flow: - - \list - \li Use context menu commands to apply effects to transitions, - as described in \l{Applying Effects to Transitions}. - \li Use the event list simulator to replace transition lines with connections to real - signals from UI controls, as described in \l{Simulating Events}. - \li Use \uicontrol {Flow Decision} components from \uicontrol Components > \uicontrol {Flow - View} to set up alternative pathways between flow items, as described in - \l{Simulating Conditions}. - \li Use \l{Working with States}{states} in flows to modify the appearance - of components on screens in response to user interaction, as - described in \l{Applying States in Flows}. - \li Use \uicontrol {Flow Wildcard} components from - \uicontrol Components > \uicontrol {Flow View} to prioritize events - from other applications and to stop some screens from appearing on - others, as described in \l{Reacting to External Events}. - \endlist -*/ - -/*! - \page studio-flow-view.html - \previouspage studio-app-flows.html - \nextpage studio-flow-item.html - - \title Adding Flow Views - - A flow view is the base component of the flow diagram that you can use to wireframe - the UI of your application. For more information, see \l{Designing Application Flows}. - - Add a flow view to an existing project or create a new project for it, as described in - \l {Creating Projects}. - - To create the flow view, select \uicontrol File > - \uicontrol {New File} > - \uicontrol {Qt Quick Files} > \uicontrol {Flow View} - and follow the instructions of the wizard. - - \image studio-flow-view-create.png "Create Flow View wizard template" - - If you want to add an event simulator to the flow view, select the - \uicontrol {Use Event Simulator} checkbox. In this case, select also the - \uicontrol {Use Application Import} checkbox to import the project to the flow view - as the event simulator requires it to work correctly. You need the - import also for access to the project \c Constants.qml file that contains - global settings for the project. For more information, see \l {Simulating Events}. - - You can adjust the appearance of all the items in the flow: action areas, - transition lines, decisions, and wildcards. Change the global settings for all items - by editing the flow view properties. To add additional semantics to the flow diagram - design, select an individual action area or transition line and change the appearance - of just that component. - - \section1 Flow View Properties - - You can specify basic properties for a \uicontrol {Flow View} component - in the \l {Type}{Component}, \l {2D Geometry}{Geometry - 2D}, and - \l Visibility sections in the \l Properties view. Specify flow view - properties in the \uicontrol {Flow View} section. - - \image studio-flow-view-properties.webp "Flow View component properties" - - To specify the \uicontrol {Flow Item} that is currently visible in the - flow view, set its index in the \uicontrol {Current index} field. - - Use the \l{Picking Colors}{color picker} to set colors for: - - \list - \li Transition lines - \li Area outlines - \li Area fills - \li Block items - \endlist - - You can set some additional global properties for drawing transition lines: - - \image studio-flow-view-properties-transition.png "Flow View transition properties" - - \list - \li In the \uicontrol {Type} field, select \uicontrol Bezier to draw - transition lines as bezier curves. - \li In the \uicontrol {Radius} field, specify the corner radius for - default curves. - \li In the \uicontrol {Bezier factor} field, specify the factor that - modifies the positions of the control points used for bezier curves. - \endlist - - For more information about changing the appearance of a particular action - area or transition line, see \l{Flow Action Area Properties} and - \l{Flow Transition Properties}. - - In the \uicontrol Advanced section, you can manage the more - \l{Specifying Developer Properties}{advanced properties} - of components. -*/ - -/*! - \page studio-flow-item.html - \previouspage studio-flow-view.html - \nextpage studio-flow-action-area.html - - \title Adding Flow Items - - After you create a \l{Adding Flow Views}{Flow View} component, use a project wizard - template to add a \uicontrol {Flow Item} component for each screen in the UI. - - If you \l{Importing 2D Assets}{imported} your screen designs from a - design tool as individual \l{glossary-component}{components} - (\e {.ui.qml} files), you can use them as content for flow items like any other components. - The imported components are listed in \uicontrol Components - > \uicontrol {My Components}. - - If you are building your UI from scratch in \QDS, add components to the flow items - first to create the screens as you would any components. For more information, see - \l {Using Components}. The flow items that you attach the components to are listed under - \uicontrol {My Components}. - - \image studio-flow-item.webp "Custom Flow Item in Components" - - \note You must use the wizard to create the flow items. After you create - a flow view, the \uicontrol {Flow View} module is added to - \uicontrol Components. It contains the \uicontrol {Flow Item} component for - \l{Applying States in Flows}{applying states to flow items}, and solely for that purpose. - - To add flow items: - - \list 1 - \li Select \uicontrol File > \uicontrol {New File} > - \uicontrol {Qt Quick Files} > - \uicontrol {Flow Item} and follow the instructions of the wizard - to create flow items for each screen in the UI. - \li Add content to the flow item in one of the following ways: - \list - \li Drag components from \uicontrol Components to a - flow item in the \l {2D} view or \l Navigator. - \li Drag a screen from \uicontrol Components - > \uicontrol {My Components} to a flow item in - the \uicontrol {2D} view or \uicontrol Navigator. - \endlist - \li In \l Properties, edit the properties of each flow item. - \endlist - - Now, drag the flow items from \uicontrol Components > \uicontrol {My Components} to the - flow view in the \uicontrol {2D} or \uicontrol Navigator view. When you have all the flow - items in place, \l{Adding Action Areas and Transitions}{add action areas} to them to create - transitions between them. - - \section1 Flow Item Properties - - You can specify basic properties for a \uicontrol {Flow Item} component - in the \l {Type}{Component}, \l {2D Geometry}{Geometry - 2D}, and - \l Visibility sections in the \uicontrol Properties view. Specify flow item - properties in the \uicontrol {Flow Item} section. - - \image studio-flow-item-properties.png "Flow Item properties" - - The \uicontrol {State change target} and \uicontrol {Target state} - properties are used to \l{Applying States in Flows}{apply states} - in flows. - - To include another flow view as a flow item into a flow view, select the UI file (.ui.qml) - that specifies the flow view in the \uicontrol {Loader source} field. - - Usually, a flow item is inactive and invisible when it is not currently - selected in the flow. Especially, all events from the flow item are ignored. - To make a flow item always active, so that another flow item within it - can respond to events and trigger the opening of a dialog, for example, - select the \uicontrol {Force active} checkbox. - - In the flow view, transitions are drawn from action areas to the target flow item by default. - To draw the transitions from the edges of flow items instead, select the - \uicontrol {Join lines} checkbox in the \uicontrol {Transition Lines} - section. - - In the \uicontrol Advanced section, you can manage the more - \l{Specifying Developer Properties}{advanced properties} of components. -*/ - -/*! - \page studio-flow-action-area.html - \previouspage studio-flow-item.html - \nextpage studio-flow-effects.html - - \title Adding Action Areas and Transitions - - \e {Action areas} are clickable areas that initiate transitions between flow items or - \l{Connecting and Releasing Signals}{create connections} to any signal from any component in a - \l{Adding Flow Items}{flow item}. For example, you could connect an - action to the \c onPressed signal of a button in your flow item to - determine what should happen when users press the button. - - \image studio-flow-action-area.webp "Flow Action Area in the 2D view" - - Select the type of the mouse or touch input to use for triggering - events, such as click, double-click, flick, pinch, or long press. - - Typically, a flow item is connected to several other flow items in the - flow with two-way connections. To avoid clutter, set an action area - as \e {go back} instead of adding explicit transition lines to and from - every potentially connected flow item. When the \uicontrol {Go back} option - is enabled, the transition will always take the user back to the previous - flow item. - - You can specify the appearance of each action area or transition line, - including the color, line thickness, dotted or solid lines, and even - the curve of the transition lines. You can change some of these properties - globally, as instructed in \l{Flow View Properties}. - - To create action areas: - - \list 1 - \li Select the flow item in the \l {2D} view, then right-click it, and select - \uicontrol {Flow} > \uicontrol {Create Flow Action} in - the context menu. - \li Drag the action area to the UI control that you want to connect - to the other flow item. For example, to a button that opens another - flow item when clicked. - \li Double-click the action area and drag the transition line to the flow item you want to - connect to. Alternatively, select the action area, right-click it to open the - context-menu, and then select \uicontrol Connect and the flow item from the list. - \li In \l Properties, modify the properties of the action area - and transition line. - \endlist - - To preview the flow, select the - \uicontrol {Live Preview} button on the top toolbar or press \key Alt + - \key P. - - \section1 Common Properties - - Specify basic properties for \uicontrol {Flow Action Area} - and \uicontrol {Flow Transition} components in the \l {Type}{Component}, - \l {2D Geometry}{Geometry - 2D}, and \l Visibility sections in the - \uicontrol Properties view. - - Use \l{Setting Anchors and Margins}{anchors} in the \uicontrol Layout tab to position - the component. - - Manage the more \l{Specifying Developer Properties}{advanced properties} of components - in the \uicontrol Advanced section. - - \section1 Flow Action Area Properties - - Use the \l{Picking Colors}{color picker} in the \uicontrol {Flow Action Area} section - to set line and fill color. - - \image studio-flow-action-area-properties.webp "Flow Action Area properties" - - Specify additional properties for action areas in the \uicontrol {Flow Action} and - \uicontrol {Action Area} sections: - - \list - \li Select the \uicontrol {Go back} checkbox to specify that the - transition will always take the user back to the previous flow item. - \li In the \uicontrol {Event IDs} field, specify the IDs of the - events to connect to, such as mouse, touch or keyboard events. - \li In the \uicontrol {Action type} field, select the type of the - mouse or touch input to use for triggering events. - \li In the \uicontrol {Line width} field, set the width of the - action area outline. - \li Select the \uicontrol {Dashed line} checkbox to draw a dashed - action area outline. - \li Select the \uicontrol Enabled checkbox to enable interaction - with the action area during preview. - \endlist - - \section1 Flow Transition Properties - - Specify additional properties for transitions between \l{Adding Flow Items}{flow items} - in the \uicontrol Transition section: - - \image studio-flow-transition-properties.webp "Flow Transition properties" - - \list - \li Select the \uicontrol Condition checkbox to activate the - transition. Select \inlineimage icons/action-icon.png - to \l{Adding Bindings Between Properties}{bind} a condition - to the transition. - \li In the \uicontrol Question field, enter the text that will appear - next to the transition line. If the transition represents the - connection to a \uicontrol {Flow Decision} component, the - text will also be visible in the selection dialog that opens when - the \l{Simulating Conditions}{condition} is triggered. - \li In the \uicontrol {Event IDs} field, specify the IDs of the - events to connect to, such as mouse, touch or keyboard events. - \li In the \uicontrol From and \uicontrol To fields, select the - flow item where the transition starts and the one where it - ends. - \endlist - - Specify the following properties to change the appearance of transition lines in - the \uicontrol {2D} view: - - \image studio-flow-transition-line-properties.webp "Flow Transition Line properties" - - \list - \li In the \uicontrol {Line width} field, set the width of the - transition line. - \li In the \uicontrol {Offset} and \uicontrol {Break offset} fields, set - the start point (\uicontrol Out) or end point (\uicontrol In) of a - transition line or a break to the specified offset. This enables - you to move them up and down or left and right. - \li Select the \uicontrol {Dashed line} checkbox to draw a dashed line. - \li In the \uicontrol Type field, select \uicontrol Bezier to draw - transition lines as bezier curves. - \li In the \uicontrol Radius field, specify the corner radius for - default curves. - \li In the \uicontrol {Bezier factor} field, specify the factor that - modifies the positions of the control points used for a bezier - curve. - \li In the \uicontrol {Label position} field, set the position of - the value of the \uicontrol Question field in respect to the - transition start point. - \li Select the \uicontrol {Label flip side} checkbox to move the - \uicontrol Question value to the opposite side of the transition - line. - \endlist - - \section1 Connecting and Releasing Signals - - To connect components to \l{Connecting Components to Signals}{signals}, export the - components first as \l{Adding Property Aliases}{aliases} in \l Navigator. To create - and release connections, select \uicontrol {Open Signal Dialog} in the context menu. - The \uicontrol {Signal List} dialog displays the signals for all components. - - \image studio-flow-signal-list.webp "Signal List dialog" - - To connect a component to a signal, select \uicontrol Connect next to one - in the list. To release a connected signal, select \uicontrol Release. -*/ - -/*! - \page studio-flow-effects.html - \previouspage studio-flow-action-area.html - \nextpage studio-flow-events.html - - \title Applying Effects to Transitions - - You can apply effects, such as fade, move, or push, to - \l{Adding Action Areas and Transitions}{transitions} between - \l{Adding Flow Items}{flow items}. A fade effect makes the first - flow item appear to fade out, while the next flow item fades in. - A move effect makes the second flow item appear to move in over the - first flow item. The push effect makes a flow item appear to push out the previous one. - You can also use your own custom effects that you have created with some other tool. - - The transition direction determines the direction the new flow item appears - from: left, right, top, bottom. You can set the duration of the effect and - \l{Editing Easing Curves}{attach an easing curve} to the effect. - - To add effects: - - \list 1 - \li Select a transition line in the \l {2D} view. - \li Right-click the transition line to open the context menu, select \uicontrol {Flow} > - \uicontrol {Flow Effects}, and then select the effect to apply. - \li In \l Properties, modify the properties of the effect. - \endlist - - To edit effect properties later, select a transition, open the context menu, and then select - \uicontrol {Flow} > \uicontrol {Select Effect}. - - To use your own custom effects, select a transition, open the context menu, and then select - \uicontrol {Flow} > \uicontrol {Flow Effects} > \uicontrol {Assign Custom FlowEffect}. - Then specify the path to your custom effect file. - - To remove the current effect from a transition, select a transition, open the context menu, - and then select \uicontrol {Flow} > \uicontrol {Flow Effects} > - \uicontrol {Assign FlowEffect None}. - - \section1 Flow Effect Properties - - Specify basic properties for a \uicontrol {Flow Effect} component in the \l Type and - \l ID fields in the \uicontrol Component section in the \uicontrol Properties view. - - \image studio-flow-effect-properties.png "Flow Effect properties" - - Set the duration and easing curve of flow effects in the \uicontrol {Transition Effect} - section: - - \list - \li In the \uicontrol Duration field, specify the duration of the - effect. - \li Select the \inlineimage icons/curve_editor.png - button to open \uicontrol {Easing Curve Editor} to attach an - \l{Editing Easing Curves}{easing curve} to the effect. - \endlist - - Set some additional properties for a move or push effect in the \uicontrol {Push Effect} - or \uicontrol {Move Effect} section: - - \image studio-flow-effect-push-properties.png "Flow Push Effect properties" - - \list - \li In the \uicontrol Direction field, specify the direction that - the target \uicontrol {Flow Item} appears from: left, right, top, - or bottom. - \li In the \uicontrol Scale field, set scaling for the effect. - \li In the \uicontrol {Incoming opacity} and - \uicontrol {Outgoing opacity} fields, specify the opacity of - the effect as a number between 0 and 1. - \li Select the \uicontrol Reveal checkbox to reveal the - \uicontrol {Flow Item} where the transition starts. - \endlist -*/ - -/*! - \page studio-flow-events.html - \previouspage studio-flow-effects.html - \nextpage studio-flow-conditions.html - - \title Simulating Events - - While \l{Adding Action Areas and Transitions}{transition lines} - are useful for prototyping, in production you need to use the real - \l{Connecting and Releasing Signals}{signals} from UI - \l{glossary-component}{components} to control the flow of the application. - For this purpose, you can use action areas in a more advanced way, by - having them listen to signals from flow items or the controls in them and - by connecting these to the \l{Adding Flow Views}{flow view}. You can use - keyboard shortcuts to simulate these events when you preview the UI. - - When you use the wizard to create a \uicontrol {Flow View} component, select - the \uicontrol {Use event simulator} checkbox to add an event simulator to - the flow view. - - You can create an event list where you assign keyboard shortcuts to events, - and then use context-menu commands to attach the events to action areas or - transition lines. - - \section1 Creating Event Lists - - To create an event list: - - \list 1 - \li Right-click in the \uicontrol 2D or \uicontrol Navigator view and select - \uicontrol {Event List} > \uicontrol {Show Event List}. - \li In the \uicontrol {Event List} dialog, select \inlineimage icons/plus.png - to add a keyboard shortcut for triggering an event to the list. - \image studio-flow-event-list.png "Event List dialog" - \li In the \uicontrol {Event ID} field, enter an identifier for the event. To search - for existing events, enter search criteria in the \uicontrol Filter field. - \li In the \uicontrol Description field, describe the keyboard shortcut. - \li In the \uicontrol Shortcut field, press the keyboard key that will - trigger the event, and then select \uicontrol R to record the - keyboard shortcut. The key identifier appears in the field. - \endlist - - You can now assign the events to action areas and transitions. - - \section1 Assigning Events to Actions - - To assign events to actions: - - \list 1 - \li Select \uicontrol eventListSimulator in \uicontrol Navigator, and in - \uicontrol Properties > \uicontrol {Exposed Custom Properties}, select the - \uicontrol active checkbox. If \uicontrol eventListSimulator is not visible - in the \uicontrol Navigator, select \inlineimage icons/visibilityon.png. - \li In \uicontrol Navigator, select an action area or transition line. - \li In the context menu, select \uicontrol {Event List} > - \uicontrol {Assign Events to Actions}. - \image studio-flow-events-assign.webp "Assign Events to Actions dialog" - \li To connect an event, select \uicontrol Connect next to an event in - the list. To release a connected event, select \uicontrol Release. - \li Press \key {Alt+P} to preview the UI. - \li Select action areas in the preview, double-click events in the - event list, or use the keyboard shortcuts to trigger events. - \image studio-flow-events-event-list.webp "Event list in Live Preview" - \endlist - -*/ - -/*! - \page studio-flow-conditions.html - \previouspage studio-flow-events.html - \nextpage studio-flow-states.html - - \title Simulating Conditions - - Part of any complex UI is the conditional logic it uses to present its - state to users or to collect and process data from various sources. Data - can be produced by user interaction from a variety of inputs, such as - buttons and controls, sensor readings from arrays of equipment, or general - values received from backend or service APIs. - - The \uicontrol {Flow Decision} component simulates conditions by displaying a - list of options you can choose from when you preview the flow. This enables - you to prototype complex interactions before you have access to the physical - controls, backend, or sensor data that will be required for the production - version. - - \image studio-flow-decision.webp "Flow Decision in the 2D view" - - To simulate conditions: - - \list 1 - \li Drag a \uicontrol {Flow Decision} component from - \uicontrol Components > \uicontrol {Flow View} to a - \l{Adding Flow Views}{flow view} in the \l Navigator or \l {2D} view. - \li Select the flow item where you want the application to start in - the \uicontrol Navigator or \uicontrol {2D} view. Then right-click the component - to open the context menu, and select \uicontrol Flow > \uicontrol {Set Flow Start}. - \li Create an \l{Adding Action Areas and Transitions}{action area} for - the component that will trigger the condition and connect it to the - flow decision. - \li Select the flow decision, and then select \uicontrol Connect in the - context menu to create connections to the flow items that will open - depending on whether the condition is met. - \li In the \l Properties view, \uicontrol {Dialog title} field, enter a - title for the selection dialog that opens when the condition is - triggered. - \li Select a transition line in the \uicontrol Navigator or - \uicontrol {2D} view, and add a descriptive text in the - \uicontrol {Question} field in \uicontrol Properties to represent - a choice in the selection dialog. - \image studio-flow-transition-properties-question.webp "Flow Transition properties" - \li Press \key {Alt+P} to preview the UI. - \li Select action areas in the preview, double-click events in the - event list, or use the keyboard shortcuts to trigger events. - \endlist - - Flow decisions are listed in a dialog where you can select which condition - is met to see the results. - - \image studio-flow-decision-preview.webp "Selection dialog for flow decision" - - \section1 Flow Decision Properties - - Specify basic properties for a \uicontrol {Flow Decision} component - in the \l Type and \l ID fields in the \uicontrol Component section in the - \uicontrol Properties view. Specify properties for flow decisions in the - \uicontrol {Flow Decision} section. - - \image studio-flow-decision-properties.webp "Flow Decision properties" - - In the \uicontrol {Dialog title} field, enter a title for the selection - dialog that opens when the condition is triggered. - - Specify the following properties to change the appearance of the - flow decision icon \inlineimage icons/flow-decision-icon.png - : - - \list - \li Select \inlineimage icons/visibility-off.png - to display the ID of the \uicontrol {Flow Decision} - component in the \l {2D} view. - \li In the \uicontrol {Label position} field, select the corner of - the flow decision icon to place the label in. - \li Use the \l{Picking Colors}{color picker} to set \uicontrol {Outline color} and - \uicontrol {Fill color} of the flow decision icon. - \li In the \uicontrol Size field, specify the size of the flow - decision icon. - \li In the \uicontrol Radius field, specify the radius of the flow - decision icon corners. - \endlist - -*/ - -/*! - \page studio-flow-states.html - \previouspage studio-flow-conditions.html - \nextpage studio-flow-external-events.html - - \title Applying States in Flows - - Use \l{Working with States}{states} in flows to modify how the \l{glossary-component} - {component} properties change in flow items. For this purpose, use the \uicontrol {Flow Item} - component available in \uicontrol Components > \uicontrol {Flow View}. - - To apply states in flows: - - \list 1 - \li Select \uicontrol File > \uicontrol {New File} > - \uicontrol {Qt Quick Files} > - \uicontrol {Flow Item} to create a flow item. - \li In the \l States view, add states to the flow item. - \li In the \l Projects view, open the .ui.qml file that contains the \l{Adding Flow Views} - {flow view}, and drag the flow item from \uicontrol Components > - \uicontrol {My Components} to the flow view in the \l Navigator or \l 2D view. - \li From \uicontrol Components > \uicontrol {Flow View}, drag an empty - \uicontrol {Flow Item} component (1) to the flow view for each state that you added. - \image studio-flow-item-component.webp "Flow Item in the Components view." - \li In the \uicontrol Navigator or \uicontrol 2D view, select an empty - \uicontrol {Flow Item} to open the \l Properties view. - \li In the \uicontrol {State change target} field, select the flow item that you created - using the wizard. - \li In the \uicontrol {Target state} field, select the state to apply to the flow item. - \image studio-flow-states-item-properties.webp "Flow Item properties" - \endlist - - To apply the different states to your application flow, add - \l{Adding Action Areas and Transitions}{action areas} and - \l{Simulating Conditions}{flow decisions} to the flow items. -*/ - -/*! - \page studio-flow-external-events.html - \previouspage studio-flow-states.html - \nextpage quick-components.html - - \title Reacting to External Events - - On mobile and embedded platforms, applications are usually integrated into - the platform and therefore screens might pop-up from anywhere or at any - time, based on a conditional event. For example, push notifications - appear on mobile devices and incoming call screens on a car's HMI. - - Use the \uicontrol {Flow Wildcard} component to model this type of - screens in your \l{Adding Flow Views}{flow view} using real or simulated events. - Add \l{Adding Flow Items}{flow items} to an \uicontrol {Allow - list} to prioritize them or to a \uicontrol {Block list} to stop some screens from - appearing on others. For example, you could block the incoming call screen - from appearing on a warning screen for the engine if you consider the - warning more important. - - To use wildcards: - - \list 1 - \li Drag a \uicontrol {Flow Wildcard} component from - \uicontrol Components > \uicontrol {Flow View} to the \l {2D} view. - \li To connect the wildcard to a flow item with a \l{Adding Action Areas and Transitions} - {transition line}, double-click the wildcard and drag the transition line to the flow - item. - \li To add logic to the \uicontrol {Flow Wildcard} component, use - \l{Simulating Events}{events}, \l{Simulating Conditions}{Flow Decision} components, - or \l{Connecting and Releasing Signals}{signals}. - \li To manage the priority of your flow items, add flow items to - \uicontrol {Allow list} or \uicontrol {Block list} in \l Properties. - \image studio-flow-wildcard.webp "The wildcard component in 2D view." - \endlist - - \section1 Flow Wildcard Properties - - Specify basic properties for a \uicontrol {Flow Wildcard} component - in the \l Type and \l ID fields in the \uicontrol Component section in the - \uicontrol Properties view. Specify properties for flow wildcards in the - \uicontrol {Flow Wildcard} section. - - \image studio-flow-wildcard-properties.webp "Flow Wildcard properties" - - In the \uicontrol {Event IDs} field, specify the IDs of the events to - connect to, such as mouse, touch or keyboard events. - - Select the \uicontrol {Global wildcard} checkbox to enable triggering - the wildcard from several flows. - - To give flow items high priority, select them in the - \uicontrol {Allow list} field. To block flow items, - select them in the \uicontrol {Block list} field. - - Specify the following properties to change the appearance of the - wildcard icon \inlineimage icons/flow-wildcard-icon.png: - - \list - \li To set the outline and fill color of the wildcard icon, use the - \l{Picking Colors}{color picker}. - \li In the \uicontrol Size field, specify the size of the wildcard icon. - \li In the \uicontrol Radius field, specify the radius of the wildcard - icon corners. - \endlist - -*/ diff --git a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc index 02a82d02031..c65469d8cd0 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc @@ -247,11 +247,7 @@ \li Wizard Template \li Purpose \row - \li {1,5} Qt Quick Files - \li Flow Item and Flow View - \li Generate components that you can use to design the - \l{Designing Application Flows}{application flow}. - \row + \li {1,4} Qt Quick Files \li Qt Quick File \li Generates a component with one of the following default components or \l{Using Positioners}{positioners} as the root component: diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc index 9000fbb2f5a..8cf7f393684 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc @@ -29,7 +29,6 @@ \li \l{Effect Composer} \li \l{File System} \li \l{Material Editor and Browser} - \li \l{Model Editor} \li \l{Navigator} \li \l{Open Documents} \li \l{Projects} @@ -53,17 +52,6 @@ \endlist \li \l{Wireframing} \list - \li \l{Designing Application Flows} - \list - \li \l{Adding Flow Views} - \li \l{Adding Flow Items} - \li \l{Adding Action Areas and Transitions} - \li \l{Applying Effects to Transitions} - \li \l{Simulating Events} - \li \l{Simulating Conditions} - \li \l{Applying States in Flows} - \li \l{Reacting to External Events} - \endlist \li \l {Using Components} \list \li \l{Preset Components} @@ -134,7 +122,6 @@ \li\l{Connecting Components to Signals} \li\l{Adding Bindings Between Properties} \li\l{Specifying Custom Properties} - \li\l{Connecting Properties to JSON Data Source} \endlist \li \l{Working with States} \endlist diff --git a/doc/qtdesignstudio/src/qtdesignstudio.qdoc b/doc/qtdesignstudio/src/qtdesignstudio.qdoc index e90e733c631..cedc8b80460 100644 --- a/doc/qtdesignstudio/src/qtdesignstudio.qdoc +++ b/doc/qtdesignstudio/src/qtdesignstudio.qdoc @@ -48,8 +48,8 @@ click-through mockup. Test, preview, and fine-tune your designs to pixel-perfection, live on target devices. - A single unified framework, one common language, fewer feedback loops, and faster iterations, - \QDS closes the gap between designers and developers. + With a single unified framework, one common language, fewer feedback loops, and faster + iterations, \QDS closes the gap between designers and developers. \b {LEARN MORE} @@ -87,11 +87,11 @@ \endlist \li Online Courses \list - \li \l{https://qurious.qt.io/enrollments/197683855/details}{Getting Started} - \li \l{https://qurious.qt.io/catalog/courses/3910783}{Creating Your First App} - \li \l{https://qurious.qt.io/enrollments/154647839/details}{Introduction to 2D UI Design} - \li \l{https://qurious.qt.io/enrollments/167005403/details}{Introduction to 3D Design} - \li \l{https://qurious.qt.io/catalog/courses/3910791}{Using Qt Bridge for Figma} + \li \l{https://www.qt.io/academy/course-catalog#getting-started-with-qt-design-studio}{Getting Started} + \li \l{https://www.qt.io/academy/course-catalog#creating-your-first-app-with-qt-design-studio}{Creating Your First App} + \li \l{https://www.qt.io/academy/course-catalog#2d-with-qt-design-studio}{2D with Qt Design Studio} + \li \l{https://www.qt.io/academy/course-catalog#3d-with-qt-design-studio}{3D with Qt Design Studio} + \li \l{https://www.qt.io/academy/course-catalog#qt-design-studio:-blur-effect}{Creating a Blur Effect} \endlist \endtable \enddiv diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-repeater-3d.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-repeater-3d.qdoc index 5cf2370cc98..56a2a803705 100644 --- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-repeater-3d.qdoc +++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-repeater-3d.qdoc @@ -96,44 +96,75 @@ \endlist \image repeater3d-numeric-model.webp - \section1 Adding a Repeater3D Component with a Model + \section1 Adding a Repeater3D Component with a List Model This section explains how to add a \uicontrol Repeater3D component with - a model to your \QDS project: + a list model to your \QDS project: To add a \uicontrol Repeater3D component: \list 1 \li Drag a \uicontrol Repeater3D component from \uicontrol Components to \e scene in \uicontrol Navigator. - \li Go to \uicontrol {Model Editor} and create a new model with the name - \e planetModel. - \li Add the following columns and data to the model. - \raw HTML - - - - - - - - - - - - - - - - - -
name (String)radius (Real)
Mars3.39
Earth6.37
Venus6.05
- \endraw - \note You can also import a model in JSON or CSV format. See \l {Importing a Data Model}. - \image repeater3d-model-editor.webp - \li In \uicontrol Navigator, select \e{_3DRepeater}. - \li In \uicontrol Properties, set \uicontrol Model to \e {DataStore.planetModel}. + \li You need to enter the QML code for the \uicontrol ListModel manually. + Go to the \uicontrol {Code} view and enter the following code somewhere + inside the root object: + \code qml + ListModel { + id: planetModel + ListElement { + name: "Mars" + radius: 3.39 + } + ListElement { + name: "Earth" + radius: 6.37 + } + ListElement { + name: "Venus" + radius: 6.05 + } + } + \endcode + The default root object for a \QDS project is \uicontrol Rectangle, so + you can paste the \uicontrol ListModel code, for example, like this: + \code qml + Rectangle { + width: Constants.width + height: Constants.height + color: Constants.backgroundColor + + ListModel { + id: planetModel + ListElement { + name: "Mars" + radius: 3.39 + } + ListElement { + name: "Earth" + radius: 6.37 + } + ListElement { + name: "Venus" + radius: 6.05 + } + } + View3D { + id: view3D + anchors.fill: parent + ... + \endcode + \li In the \uicontrol {Code} view, add \c {model: planetModel} to the + \uicontrol Repeater3D object to tell that you want to use your + \uicontrol ListModel as the model for the \uicontrol Repeater3D object. \endlist + \code qml + Repeater3D { + id: repeater3D + model: planetModel + } + \endcode + Now, you have set up the \uicontrol Repeater3D component to use a \uicontrol ListModel to draw the items. Next, you need to add the item to draw. In this example, you are using a \uicontrol Sphere. @@ -147,7 +178,7 @@ next to \uicontrol Scale > \uicontrol X. \li Select \uicontrol {Set binding} to open \uicontrol {Binding Editor}. \li In the binding editor, enter \c{radius}. This sets the X - scale to the radius value defined in the model for each of the sphere + scale to the radius value defined in the list model for each of the sphere instances. \image repeater3d-radius-binding.png \li Select \uicontrol OK. @@ -170,6 +201,6 @@ result. You need to zoom out to see all the spheres. \endlist - \image repeater3d-list-model.webp + \image repeater3d-list-model.webp "Spheres in Repeater3D with a ListModel" */ diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor-json.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-json.qdoc deleted file mode 100644 index 8b7451b3aa3..00000000000 --- a/doc/qtdesignstudio/src/views/qtquick-connection-editor-json.qdoc +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only - -/*! - \page quick-json-data-properties.html - \previouspage quick-dynamic-properties.html - \nextpage quick-states.html - - \title Connecting Properties to JSON Data Source - - Connect properties to data from a JSON file. You need two files in your project to do this: - - \table - \row - \li \c {data.json} - \li A data file. - \row - \li \c {JsonData.qml} - \li A singleton that reads data from \c {data.json}. - \endtable - - To create these files, you need to create a new data model: - - \list 1 - \li In \uicontrol {Model Editor}, select \inlineimage {icons/zoomIn.png}. - \li Select \uicontrol{Create}. - \endlist - - The files are created in the \e {/imports//} folder of the project. - - \section1 Connecting a Text Property to a Data Source - - To connect a text property to a corresponding field in a JSON file: - - \list 1 - \li In the \uicontrol Navigator or \uicontrol 2D view, select a component - that has a text property, for example, a text field. - \li In the \uicontrol Connections view, go to the \uicontrol Bindings - tab. - \li Select \inlineimage {icons/plus.png}. - \li In the first \uicontrol From field, select \uicontrol {DataStore}, and in the second field, - select the JSON entry you want to use. In this example, \uicontrol {backend.name} is - selected. This corresponds to the \e name entry in \c {data.json}. - \li In the \uicontrol To field, ensure that \uicontrol text is selected. - \image json-text-binding.webp - \endlist - - Now, the text field is populated with data from the JSON file. - - \section1 Adding Data Fields to the JSON File - - If you add data fields to the JSON file, you need to manually do the same - updates to \c {JsonData.qml}. - - \list 1 - \li Go to the \uicontrol Projects view and open \c {JsonData.qml}. - \image project-jasondata.webp - \li In the \uicontrol Properties view, create a new local custom property. - \image json-new-property.webp - \li Ensure that the name of the property matches the data entry in the JSON file. - \endlist - -*/ diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc index 586098ffca8..bd976fbfd54 100644 --- a/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc +++ b/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc @@ -32,11 +32,6 @@ can specify values for. You can add custom properties that would not otherwise exist for a particular \l{Component Types} {component type} or your custom components. - - \li \l{Connecting Properties to JSON Data Source} - - You can add bindings between properties and data from a JSON file. - \endlist For an example of using properties, bindings, and connections to create a diff --git a/doc/qtdesignstudio/src/views/studio-model-editor.qdoc b/doc/qtdesignstudio/src/views/studio-model-editor.qdoc deleted file mode 100644 index 0caebcfb493..00000000000 --- a/doc/qtdesignstudio/src/views/studio-model-editor.qdoc +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only - -/*! - \page studio-model-editor.html - \previouspage qtquick-effect-composer-view.html - \nextpage creator-project-managing-workspaces.html - - \ingroup studio-views - - \title Model Editor - - \brief Create, manage, import, and export data models. - - In the \uicontrol {Model Editor} view, you can create, manage, import, and export - data models. With data models, you can, for example, populate views with data. - - \image edit-list-model-model-editor.webp - - For examples of how to use data models, see - \l {Adding a Repeater3D Component with a Model}. - - \section1 Creating a Data Model - - To create a data model: - \list 1 - \li In \uicontrol {Model Editor}, select \inlineimage {icons/zoomIn.png}. - \li Enter a name and select \uicontrol {Create}. - \endlist - - This creates a single-cell table. - - \image model-editor-new-model.webp - - Next, add columns, rows, and data to the model. - - \note You must manually save the table after you have made changes. To do this, - select \inlineimage {icons/save-effect-composer.png}. - - \section1 Editing a Data Model - - Edit a data model in one of the following ways: - \list - \li Right-click a column name to edit its name and type, delete, or sort it. - \li Double-click a cell to edit its content. - \li Use the toolbar to add and remove columns and rows. - \endlist - - \note You must manually save the table after you have made changes. To do this, - select \inlineimage {icons/save-effect-composer.png}. - - \section1 Importing a Data Model - - Import data models from JSON or CSV files. To do this, select \inlineimage {icons/import.png} - in \uicontrol {Model Editor}. - - \section1 Exporting a Data Model - - Export data models to JSON or CSV files. To do this, select \inlineimage {icons/export.png} - in \uicontrol {Model Editor}. - -*/ diff --git a/doc/qtdesignstudio/src/whats new/qds-releases.qdoc b/doc/qtdesignstudio/src/whats new/qds-releases.qdoc index ee792775f82..c21baef03ba 100644 --- a/doc/qtdesignstudio/src/whats new/qds-releases.qdoc +++ b/doc/qtdesignstudio/src/whats new/qds-releases.qdoc @@ -14,6 +14,7 @@ \section2 \QDS 4 \list + \li \l{Qt Design Studio 4.6 released} \li \l{Qt Design Studio 4.5.1 released} \li \l{Qt Design Studio 4.5 released} \li \l{Qt Design Studio 4.4 released} diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/Assets.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/Assets.qml index 0514f3dfaef..60beacfe6e2 100644 --- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/Assets.qml +++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/Assets.qml @@ -101,7 +101,7 @@ Item { anchors.fill: parent acceptedButtons: Qt.RightButton onClicked: { - if (assetsModel.hasFiles) { + if (!assetsModel.isEmpty) { function onFolderCreated(path) { assetsView.addCreatedFolder(path) } @@ -189,13 +189,13 @@ Item { leftPadding: 10 color: StudioTheme.Values.themeTextColor font.pixelSize: StudioTheme.Values.baseFont - visible: !assetsModel.hasFiles && !root.__searchBoxEmpty + visible: assetsModel.isEmpty && !root.__searchBoxEmpty } Item { // placeholder when the assets library is empty width: parent.width height: parent.height - toolbar.height - column.spacing - visible: !assetsModel.hasFiles && root.__searchBoxEmpty + visible: assetsModel.isEmpty && root.__searchBoxEmpty clip: true MouseArea { // right clicking the empty area of the view diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsContextMenu.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsContextMenu.qml index 40cdac85bbb..08f6c0a990f 100644 --- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsContextMenu.qml +++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsContextMenu.qml @@ -192,7 +192,7 @@ StudioControls.Menu { StudioControls.MenuItem { text: qsTr("New Folder") - visible: root.assetsModel.hasFiles + visible: !root.assetsModel.isEmpty height: visible ? implicitHeight : 0 NewFolderDialog { diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml index 307d3637521..df45bc32487 100644 --- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml +++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/AssetsView.qml @@ -70,9 +70,9 @@ TreeView { model: assetsModel onRowsChanged: { - if (root.rows > root.rootPathRow + 1 && !assetsModel.hasFiles || - root.rows <= root.rootPathRow + 1 && assetsModel.hasFiles) { - assetsModel.syncHasFiles() + if (root.rows > root.rootPathRow + 1 && assetsModel.isEmpty || + root.rows <= root.rootPathRow + 1 && !assetsModel.isEmpty) { + assetsModel.syncIsEmpty() } root.updateRows() @@ -328,7 +328,7 @@ TreeView { function moveSelection(amount) { - if (!assetsModel.hasFiles || !amount) + if (assetsModel.isEmpty || !amount) return let index = root.currentFilePath ? assetsModel.indexForPath(root.currentFilePath) diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml index c7b2f5a0822..8cfabf06d22 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml @@ -133,6 +133,8 @@ HelperWidgets.ScrollView { topPadding: 10 leftPadding: 10 visible: root.materialsModel.isEmpty + wrapMode: Text.WordWrap + width: root.width - x } } } diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml index ca8fb64eccf..a0942bc64a6 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabBar.qml @@ -2,11 +2,12 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick +import QtQuick.Layouts import HelperWidgets 2.0 as HelperWidgets import StudioControls 1.0 as StudioControls import StudioTheme 1.0 as StudioTheme -Row { +RowLayout { id: root property int currIndex: 0 @@ -24,6 +25,7 @@ Row { icon: modelData.icon selected: root.currIndex === index onClicked: root.currIndex = index + Layout.fillWidth: true } } } diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml index 587f846a10b..cc8efbf7168 100644 --- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml +++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTabButton.qml @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 import QtQuick +import QtQuick.Controls import HelperWidgets 2.0 as HelperWidgets import StudioControls 1.0 as StudioControls import StudioTheme 1.0 as StudioTheme @@ -16,7 +17,6 @@ Rectangle { property bool selected: false height: button.height - width: button.width + label.width + contentRow.spacing + 6 color: StudioTheme.Values.themeToolbarBackground radius: StudioTheme.Values.smallRadius @@ -43,9 +43,9 @@ Rectangle { color: StudioTheme.Values.themeTextColor text: qsTr("Materials") font.pixelSize: StudioTheme.Values.baseFontSize - horizontalAlignment: Text.AlignLeft verticalAlignment: Text.AlignVCenter elide: Text.ElideRight + width: root.width - x } } @@ -56,6 +56,12 @@ Rectangle { onClicked: root.clicked() } + StudioControls.ToolTip { + visible: mouseArea.containsMouse + text: label.text + delay: 1000 + } + states: [ State { name: "default" diff --git a/share/qtcreator/qmldesigner/designericons.json b/share/qtcreator/qmldesigner/designericons.json index 005494b4715..f4f60b7412c 100644 --- a/share/qtcreator/qmldesigner/designericons.json +++ b/share/qtcreator/qmldesigner/designericons.json @@ -241,6 +241,9 @@ "LocalOrientIcon": { "iconName": "localOrient_medium" }, + "LiveUpdateIcon": { + "iconName": "restartParticles_medium" + }, "MoveToolIcon": { "iconName": "move_medium" }, @@ -276,6 +279,9 @@ "SplitViewIcon": { "iconName": "splitScreen_medium" }, + "SyncIcon": { + "iconName": "updateContent_medium" + }, "ToggleGroupIcon": { "Off": { "iconName": "selectOutline_medium" diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposer.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposer.qml index 16525678be8..81c01d5f54e 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposer.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposer.qml @@ -195,6 +195,10 @@ Item { onAssignToSelectedClicked: { root.backendModel.assignToSelected() } + + onOpenShadersCodeEditor: { + root.backendModel.openMainShadersCodeEditor() + } } SplitView { @@ -366,6 +370,8 @@ Item { expanded = wasExpanded dragAnimation.enabled = true } + + onOpenShadersCodeEditor: (idx) => root.backendModel.openShadersCodeEditor(idx) } } // Repeater } // Column diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerTopBar.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerTopBar.qml index 799dbeeddc3..c6e8abe11a3 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerTopBar.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectComposerTopBar.qml @@ -19,6 +19,7 @@ Rectangle { signal saveClicked signal saveAsClicked signal assignToSelectedClicked + signal openShadersCodeEditor Row { spacing: 5 @@ -48,12 +49,24 @@ Rectangle { style: StudioTheme.Values.viewBarButtonStyle buttonIcon: StudioTheme.Constants.saveAs_medium tooltip: qsTr("Save current composition with a new name") - enabled: root.backendModel ? root.backendModel.isEnabled && root.backendModel.currentComposition !== "" + enabled: root.backendModel ? root.backendModel.isEnabled + && root.backendModel.currentComposition !== "" : false onClicked: root.saveAsClicked() } + HelperWidgets.AbstractButton { + style: StudioTheme.Values.viewBarButtonStyle + buttonIcon: StudioTheme.Constants.codeEditor_medium + tooltip: qsTr("Open Code") + enabled: root.backendModel ? root.backendModel.isEnabled + && root.backendModel.currentComposition !== "" + : false + + onClicked: root.openShadersCodeEditor() + } + HelperWidgets.AbstractButton { style: StudioTheme.Values.viewBarButtonStyle buttonIcon: StudioTheme.Constants.assignTo_medium diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNode.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNode.qml index a606461b5c5..ef59468ed60 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNode.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectCompositionNode.qml @@ -30,10 +30,34 @@ HelperWidgets.Section { eyeEnabled: nodeEnabled eyeButtonToolTip: qsTr("Enable/Disable Node") + signal openShadersCodeEditor(index: int) + onEyeButtonClicked: { nodeEnabled = root.eyeEnabled } + icons: HelperWidgets.IconButton { + icon: StudioTheme.Constants.codeEditor_medium + transparentBg: true + buttonSize: 21 + iconSize: StudioTheme.Values.smallIconFontSize + iconColor: StudioTheme.Values.themeTextColor + iconScale: containsMouse ? 1.2 : 1 + implicitWidth: width + onClicked: root.openShadersCodeEditor(index) + } + + content: Label { + text: root.caption + color: root.labelColor + elide: Text.ElideRight + font.pixelSize: root.sectionFontSize + font.capitalization: root.labelCapitalization + anchors.verticalCenter: parent?.verticalCenter + textFormat: Text.RichText + leftPadding: StudioTheme.Values.toolbarSpacing + } + Column { spacing: 10 diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectNode.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectNode.qml index dd361b08d73..130208253c6 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectNode.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/EffectNode.qml @@ -3,6 +3,7 @@ import QtQuick import QtQuick.Controls +import QtQuick.Controls.impl import HelperWidgets import StudioControls as StudioControls import StudioTheme as StudioTheme diff --git a/share/qtcreator/qmldesigner/effectComposerQmlSources/PreviewImagesComboBox.qml b/share/qtcreator/qmldesigner/effectComposerQmlSources/PreviewImagesComboBox.qml index 201fab9699d..b75a04001e8 100644 --- a/share/qtcreator/qmldesigner/effectComposerQmlSources/PreviewImagesComboBox.qml +++ b/share/qtcreator/qmldesigner/effectComposerQmlSources/PreviewImagesComboBox.qml @@ -22,12 +22,17 @@ StudioControls.ComboBox { required property Item mainRoot - property var images: ["images/preview0.png", - "images/preview1.png", - "images/preview2.png", - "images/preview3.png", - "images/preview4.png"] - property string selectedImage: images[0] + property var images: [Qt.url(""), + Qt.url("images/preview0.png"), + Qt.url("images/preview1.png"), + Qt.url("images/preview2.png"), + Qt.url("images/preview3.png"), + Qt.url("images/preview4.png")] + property url selectedImage: EffectComposerBackend.effectComposerModel.currentPreviewImage != Qt.url("") + ? EffectComposerBackend.effectComposerModel.currentPreviewImage + : images[1] + + Component.onCompleted: EffectComposerBackend.effectComposerModel.currentPreviewImage = images[1] readonly property int popupHeight: Math.min(800, col.height + 2) @@ -122,45 +127,80 @@ StudioControls.ComboBox { border.width: 1 focus: true - HelperWidgets.ScrollView { + Column { anchors.fill: parent - anchors.margins: 1 - clip: true - Column { - id: col + Item { + id: setCustomItem + width: parent.width + height: 50 - padding: 10 - spacing: 10 + HelperWidgets.Button { + anchors.fill: parent + anchors.bottomMargin: 2 + anchors.topMargin: col.padding + anchors.leftMargin: col.padding + anchors.rightMargin: col.padding + text: qsTr("Set Custom Image") + onClicked: { + EffectComposerBackend.effectComposerModel.chooseCustomPreviewImage() + root.popup.close() + } + } + } - Repeater { - model: root.images - Rectangle { - required property int index - required property var modelData + HelperWidgets.ScrollView { + width: parent.width - 2 + height: parent.height - setCustomItem.height - color: "transparent" - border.color: root.selectedImage === modelData ? StudioTheme.Values.themeInteraction - : "transparent" + clip: true - width: 200 - height: 200 + Column { + id: col - Image { - source: modelData - anchors.fill: parent - fillMode: Image.PreserveAspectFit - smooth: true - anchors.margins: 1 - } + padding: 10 + spacing: 10 - MouseArea { - anchors.fill: parent + Repeater { + model: root.images - onClicked: { - root.selectedImage = root.images[index] - root.popup.close() + Rectangle { + required property int index + required property var modelData + + color: "transparent" + border.color: root.selectedImage === modelData ? StudioTheme.Values.themeInteraction + : "transparent" + + width: 200 + height: 200 + visible: index > 0 + || EffectComposerBackend.effectComposerModel.customPreviewImage !== Qt.url("") + + Image { + source: index > 0 + ? parent.modelData + : EffectComposerBackend.effectComposerModel.customPreviewImage + anchors.fill: parent + fillMode: Image.PreserveAspectFit + smooth: true + anchors.margins: 1 + } + + MouseArea { + anchors.fill: parent + + onClicked: { + if (parent.index > 0) { + EffectComposerBackend.effectComposerModel.currentPreviewImage + = root.images[index] + } else { + EffectComposerBackend.effectComposerModel.currentPreviewImage + = EffectComposerBackend.effectComposerModel.customPreviewImage + } + root.popup.close() + } } } } diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml index f905191eff9..ccad08f738a 100644 --- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml +++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml @@ -391,6 +391,21 @@ Item { visible: BackendApi.haveVirtualKeyboard } + StudioControls.CheckBox { + id: enableCMakeGeneration + actionIndicatorVisible: false + text: qsTr("Enable Cmake Generation") + font.pixelSize: DialogValues.defaultPixelSize + checked: BackendApi.enableCMakeGeneration + visible: BackendApi.hasCMakeGeneration + } + + Binding { + target: BackendApi + property: "enableCMakeGeneration" + value: enableCMakeGeneration.checked + } + RowLayout { // Target Qt Version width: parent.width visible: BackendApi.haveTargetQtVersion diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml index 245b8506a28..232574a2207 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml @@ -39,6 +39,8 @@ Item { textFormat: Text.RichText } + property Item icons + property int leftPadding: StudioTheme.Values.sectionLeftPadding property int rightPadding: 0 property int topPadding: StudioTheme.Values.sectionHeadSpacerHeight @@ -214,6 +216,13 @@ Item { } } + Item { + id: iconsContent + height: header.height + children: [ section.icons ] + Layout.preferredWidth: childrenRect.width + } + IconButton { id: arrow icon: StudioTheme.Constants.sectionToggle diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json index afb00fa253c..ae3dfe5a4ab 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json @@ -32,6 +32,7 @@ { "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" }, { "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" }, { "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" }, + { "key": "EnableCMakeGenerationDefault", "value": "%{JS: true}" }, { "key": "QtQuick3DVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuick3DVersion}" } ], @@ -208,6 +209,15 @@ "checked": "%{UseVirtualKeyboardDefault}" } }, + { + "name": "EnableCMakeGeneration", + "trDisplayName": "Enable CMake Genertion", + "type": "CheckBox", + "data": + { + "checked": "%{EnableCMakeGenerationDefault}" + } + }, { "name": "CustomScreenWidth", "trDisplayName": "Custom screen width:", diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-extended-3d/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application-extended-3d/wizard.json index ccfcd01a983..a0cccc15915 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application-extended-3d/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-extended-3d/wizard.json @@ -32,6 +32,7 @@ { "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" }, { "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" }, { "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" }, + { "key": "EnableCMakeGenerationDefault", "value": "%{JS: true}" }, { "key": "QtQuick3DVersion", "value": "%{JS: %{TargetQtVersion}.TargetQuick3DVersion}" } ], @@ -208,6 +209,15 @@ "checked": "%{UseVirtualKeyboardDefault}" } }, + { + "name": "EnableCMakeGeneration", + "trDisplayName": "Enable CMake Genertion", + "type": "CheckBox", + "data": + { + "checked": "%{EnableCMakeGenerationDefault}" + } + }, { "name": "CustomScreenWidth", "trDisplayName": "Custom screen width:", diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json index 0aab9b601f3..a7eb00ae0f5 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json +++ b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json @@ -31,6 +31,7 @@ { "key": "ScreenWidth", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenWidth : value('CustomScreenWidth')}" }, { "key": "ScreenHeight", "value": "%{JS: value('UseStandardResolution') === 'true' ? %{ScreenFactor}.ScreenHeight : value('CustomScreenHeight')}" }, { "key": "UseVirtualKeyboardDefault", "value": "%{JS: false}" }, + { "key": "EnableCMakeGenerationDefault", "value": "%{JS: true}" }, { "key": "DefaultStyle", "value": "Basic" } ], @@ -207,6 +208,15 @@ "checked": "%{UseVirtualKeyboardDefault}" } }, + { + "name": "EnableCMakeGeneration", + "trDisplayName": "Enable CMake Genertion", + "type": "CheckBox", + "data": + { + "checked": "%{EnableCMakeGenerationDefault}" + } + }, { "name": "CustomScreenWidth", "trDisplayName": "Custom screen width:", diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl index 58afba69c34..615cc8d2348 100644 --- a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl +++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl @@ -22,7 +22,7 @@ Project { } JavaScriptFiles { - directory: "%{ProjectName}" + directory: "%{ContentDir}" } ImageFiles { @@ -103,6 +103,10 @@ Project { /* Required for deployment */ targetDirectory: "/opt/%{ProjectName}" +@if %{EnableCMakeGeneration} + enableCMakeGeneration: true +@endif + qdsVersion: "4.6" quickVersion: "%{QtQuickVersion}" diff --git a/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml b/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml index 721e2b06dd9..d57d35ecb20 100644 --- a/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml +++ b/share/qtcreator/qmldesigner/welcomepage/BrandBar.qml @@ -32,6 +32,7 @@ Item { } Text { + visible: !Constants.projectModel.liteDesignerEnabled id: brandLabel color: Constants.currentBrand text: qsTr("Qt Design Studio") @@ -44,6 +45,20 @@ Item { } Text { + visible: Constants.projectModel.liteDesignerEnabled + id: brandLabelLite + color: Constants.currentBrand + text: qsTr("Lite QML Designer") + anchors.verticalCenter: parent.verticalCenter + anchors.left: welcomeTo.right + anchors.leftMargin: 8 + verticalAlignment: Text.AlignVCenter + font.pixelSize: 36 + font.family: "titillium web" + } + + Text { + visible: !Constants.projectModel.liteDesignerEnabled width: 291 height: 55 color: Constants.currentGlobalText diff --git a/src/plugins/coreplugin/dialogs/settingsdialog.cpp b/src/plugins/coreplugin/dialogs/settingsdialog.cpp index 828f396433e..6ca8b7d8f06 100644 --- a/src/plugins/coreplugin/dialogs/settingsdialog.cpp +++ b/src/plugins/coreplugin/dialogs/settingsdialog.cpp @@ -56,6 +56,8 @@ using namespace Utils; namespace Core { namespace Internal { +namespace { + bool optionsPageLessThan(const IOptionsPage *p1, const IOptionsPage *p2) { if (p1->category() != p2->category()) @@ -127,7 +129,7 @@ CategoryModel::~CategoryModel() int CategoryModel::rowCount(const QModelIndex &parent) const { - return parent.isValid() ? 0 : m_categories.size(); + return parent.isValid() ? 0 : static_cast(m_categories.size()); } QVariant CategoryModel::data(const QModelIndex &index, int role) const @@ -249,7 +251,7 @@ protected: bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; }; -static bool categoryVisible(const Id &id) +static bool categoryVisible([[maybe_unused]] const Id &id) { #ifdef QT_NO_DEBUG @@ -806,6 +808,8 @@ bool SettingsDialog::execDialog() return m_applied; } +} // namespace + bool executeSettingsDialog(QWidget *parent, Id initialPage) { if (!ExtensionSystem::PluginManager::isInitializationDone()) { diff --git a/src/plugins/effectcomposer/CMakeLists.txt b/src/plugins/effectcomposer/CMakeLists.txt index 71805ea1be2..4e3e7283b3b 100644 --- a/src/plugins/effectcomposer/CMakeLists.txt +++ b/src/plugins/effectcomposer/CMakeLists.txt @@ -6,12 +6,14 @@ add_qtc_plugin(EffectComposer Qt::Core Qt::CorePrivate Qt::Widgets Qt::Qml Qt::QmlPrivate Qt::Quick QtCreator::Utils SOURCES + effectcodeeditorwidget.cpp effectcodeeditorwidget.h effectcomposerplugin.cpp effectcomposerwidget.cpp effectcomposerwidget.h effectcomposerview.cpp effectcomposerview.h effectcomposermodel.cpp effectcomposermodel.h effectcomposernodesmodel.cpp effectcomposernodesmodel.h effectcomposeruniformsmodel.cpp effectcomposeruniformsmodel.h + effectshaderscodeeditor.cpp effectshaderscodeeditor.h effectnode.cpp effectnode.h effectnodescategory.cpp effectnodescategory.h compositionnode.cpp compositionnode.h diff --git a/src/plugins/effectcomposer/compositionnode.cpp b/src/plugins/effectcomposer/compositionnode.cpp index a69cd00e075..5426d55f2cb 100644 --- a/src/plugins/effectcomposer/compositionnode.cpp +++ b/src/plugins/effectcomposer/compositionnode.cpp @@ -3,8 +3,9 @@ #include "compositionnode.h" -#include "effectutils.h" #include "effectcomposeruniformsmodel.h" +#include "effectshaderscodeeditor.h" +#include "effectutils.h" #include "propertyhandler.h" #include "uniform.h" @@ -44,6 +45,8 @@ CompositionNode::CompositionNode(const QString &effectName, const QString &qenPa } } +CompositionNode::~CompositionNode() = default; + QString CompositionNode::fragmentCode() const { return m_fragmentCode; @@ -110,8 +113,8 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c m_name = json.value("name").toString(); m_description = json.value("description").toString(); - m_fragmentCode = EffectUtils::codeFromJsonArray(json.value("fragmentCode").toArray()); - m_vertexCode = EffectUtils::codeFromJsonArray(json.value("vertexCode").toArray()); + setFragmentCode(EffectUtils::codeFromJsonArray(json.value("fragmentCode").toArray())); + setVertexCode(EffectUtils::codeFromJsonArray(json.value("vertexCode").toArray())); if (json.contains("extraMargin")) m_extraMargin = json.value("extraMargin").toInt(); @@ -154,6 +157,36 @@ void CompositionNode::parse(const QString &effectName, const QString &qenPath, c } } +void CompositionNode::ensureShadersCodeEditor() +{ + if (m_shadersCodeEditor) + return; + + m_shadersCodeEditor = Utils::makeUniqueObjectLatePtr(name()); + m_shadersCodeEditor->setFragmentValue(fragmentCode()); + m_shadersCodeEditor->setVertexValue(vertexCode()); + + connect(m_shadersCodeEditor.get(), &EffectShadersCodeEditor::vertexValueChanged, this, [this] { + setVertexCode(m_shadersCodeEditor->vertexValue()); + }); + + connect(m_shadersCodeEditor.get(), &EffectShadersCodeEditor::fragmentValueChanged, this, [this] { + setFragmentCode(m_shadersCodeEditor->fragmentValue()); + }); + + connect( + m_shadersCodeEditor.get(), + &EffectShadersCodeEditor::rebakeRequested, + this, + &CompositionNode::rebakeRequested); +} + +void CompositionNode::requestRebakeIfLiveUpdateMode() +{ + if (m_shadersCodeEditor && m_shadersCodeEditor->liveUpdate()) + emit rebakeRequested(); +} + QList CompositionNode::uniforms() const { return m_uniforms; @@ -189,6 +222,34 @@ void CompositionNode::setRefCount(int count) emit isDepencyChanged(); } +void CompositionNode::setFragmentCode(const QString &fragmentCode) +{ + if (m_fragmentCode == fragmentCode) + return; + + m_fragmentCode = fragmentCode; + emit fragmentCodeChanged(); + + requestRebakeIfLiveUpdateMode(); +} + +void CompositionNode::setVertexCode(const QString &vertexCode) +{ + if (m_vertexCode == vertexCode) + return; + + m_vertexCode = vertexCode; + emit vertexCodeChanged(); + + requestRebakeIfLiveUpdateMode(); +} + +void CompositionNode::openShadersCodeEditor() +{ + ensureShadersCodeEditor(); + m_shadersCodeEditor->showWidget(); +} + QString CompositionNode::name() const { return m_name; diff --git a/src/plugins/effectcomposer/compositionnode.h b/src/plugins/effectcomposer/compositionnode.h index 433468688a2..dcd66072afa 100644 --- a/src/plugins/effectcomposer/compositionnode.h +++ b/src/plugins/effectcomposer/compositionnode.h @@ -5,11 +5,15 @@ #include "effectcomposeruniformsmodel.h" +#include + #include #include namespace EffectComposer { +class EffectShadersCodeEditor; + class CompositionNode : public QObject { Q_OBJECT @@ -18,6 +22,12 @@ class CompositionNode : public QObject Q_PROPERTY(bool nodeEnabled READ isEnabled WRITE setIsEnabled NOTIFY isEnabledChanged) Q_PROPERTY(bool isDependency READ isDependency NOTIFY isDepencyChanged) Q_PROPERTY(QObject *nodeUniformsModel READ uniformsModel NOTIFY uniformsModelChanged) + Q_PROPERTY( + QString fragmentCode + READ fragmentCode + WRITE setFragmentCode + NOTIFY fragmentCodeChanged) + Q_PROPERTY(QString vertexCode READ vertexCode WRITE setVertexCode NOTIFY vertexCodeChanged) public: enum NodeType { @@ -27,6 +37,7 @@ public: }; CompositionNode(const QString &effectName, const QString &qenPath, const QJsonObject &json = {}); + virtual ~CompositionNode(); QString fragmentCode() const; QString vertexCode() const; @@ -54,14 +65,23 @@ public: int extraMargin() const { return m_extraMargin; } + void setFragmentCode(const QString &fragmentCode); + void setVertexCode(const QString &vertexCode); + + void openShadersCodeEditor(); + signals: void uniformsModelChanged(); void isEnabledChanged(); void isDepencyChanged(); void rebakeRequested(); + void fragmentCodeChanged(); + void vertexCodeChanged(); private: void parse(const QString &effectName, const QString &qenPath, const QJsonObject &json); + void ensureShadersCodeEditor(); + void requestRebakeIfLiveUpdateMode(); QString m_name; NodeType m_type = CustomNode; @@ -77,6 +97,7 @@ private: QList m_uniforms; EffectComposerUniformsModel m_unifomrsModel; + Utils::UniqueObjectLatePtr m_shadersCodeEditor; }; } // namespace EffectComposer diff --git a/src/plugins/effectcomposer/effectcodeeditorwidget.cpp b/src/plugins/effectcomposer/effectcodeeditorwidget.cpp new file mode 100644 index 00000000000..c6fcf7c952e --- /dev/null +++ b/src/plugins/effectcomposer/effectcodeeditorwidget.cpp @@ -0,0 +1,142 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "effectcodeeditorwidget.h" + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +namespace EffectComposer { + +constexpr char EFFECTEDITOR_CONTEXT_ID[] = "EffectEditor.EffectEditorContext"; + +EffectCodeEditorWidget::EffectCodeEditorWidget() + : m_context(new Core::IContext(this)) +{ + Core::Context context(EFFECTEDITOR_CONTEXT_ID, ProjectExplorer::Constants::QMLJS_LANGUAGE_ID); + + m_context->setWidget(this); + m_context->setContext(context); + Core::ICore::addContextObject(m_context); + + Utils::TransientScrollAreaSupport::support(this); + + /* + * We have to register our own active auto completion shortcut, because the original shortcut will + * use the cursor position of the original editor in the editor manager. + */ + m_completionAction = new QAction(tr("Trigger Completion"), this); + + Core::Command *command = Core::ActionManager::registerAction( + m_completionAction, TextEditor::Constants::COMPLETE_THIS, context); + command->setDefaultKeySequence(QKeySequence( + Core::useMacShortcuts + ? tr("Meta+Space") + : tr("Ctrl+Space"))); + + connect(m_completionAction, &QAction::triggered, this, [this] { + invokeAssist(TextEditor::Completion); + }); +} + +EffectCodeEditorWidget::~EffectCodeEditorWidget() +{ + unregisterAutoCompletion(); +} + +void EffectCodeEditorWidget::unregisterAutoCompletion() +{ + if (m_completionAction) { + Core::ActionManager::unregisterAction(m_completionAction, TextEditor::Constants::COMPLETE_THIS); + delete m_completionAction; + m_completionAction = nullptr; + } +} + +void EffectCodeEditorWidget::setEditorTextWithIndentation(const QString &text) +{ + auto *doc = document(); + doc->setPlainText(text); + + // We don't need to indent an empty text but is also needed for safer text.length()-1 below + if (text.isEmpty()) + return; + + auto modifier = std::make_unique(doc, QTextCursor{doc}); + modifier->indent(0, text.length()-1); +} + +EffectDocument::EffectDocument() + : QmlJSEditor::QmlJSEditorDocument(EFFECTEDITOR_CONTEXT_ID) + , m_semanticHighlighter(new QmlJSEditor::SemanticHighlighter(this)) +{} + +EffectDocument::~EffectDocument() +{ + delete m_semanticHighlighter; +} + +void EffectDocument::applyFontSettings() +{ + TextDocument::applyFontSettings(); + m_semanticHighlighter->updateFontSettings(fontSettings()); + if (!isSemanticInfoOutdated() && semanticInfo().isValid()) + m_semanticHighlighter->rerun(semanticInfo()); +} + +void EffectDocument::triggerPendingUpdates() +{ + TextDocument::triggerPendingUpdates(); // Calls applyFontSettings if necessary + if (!isSemanticInfoOutdated() && semanticInfo().isValid()) + m_semanticHighlighter->rerun(semanticInfo()); +} + +EffectCodeEditorFactory::EffectCodeEditorFactory() +{ + setId(EFFECTEDITOR_CONTEXT_ID); + setDisplayName(::Core::Tr::tr("Effect Code Editor")); + addMimeType(EFFECTEDITOR_CONTEXT_ID); + addMimeType(Utils::Constants::QML_MIMETYPE); + addMimeType(Utils::Constants::QMLTYPES_MIMETYPE); + addMimeType(Utils::Constants::JS_MIMETYPE); + + setDocumentCreator([]() { return new EffectDocument; }); + setEditorWidgetCreator([]() { return new EffectCodeEditorWidget; }); + setEditorCreator([]() { return new QmlJSEditor::QmlJSEditor; }); + setAutoCompleterCreator([]() { return new QmlJSEditor::AutoCompleter; }); + setCommentDefinition(Utils::CommentDefinition::CppStyle); + setParenthesesMatchingEnabled(true); + setCodeFoldingSupported(true); + + addHoverHandler(new QmlJSEditor::QmlJSHoverHandler); + setCompletionAssistProvider(new QmlJSEditor::QmlJSCompletionAssistProvider); +} + +void EffectCodeEditorFactory::decorateEditor(TextEditor::TextEditorWidget *editor) +{ + editor->textDocument()->resetSyntaxHighlighter( + [] { return new QmlJSEditor::QmlJSHighlighter(); }); + editor->textDocument()->setIndenter(QmlJSEditor::createQmlJsIndenter( + editor->textDocument()->document())); + editor->setAutoCompleter(new QmlJSEditor::AutoCompleter); +} + +} // namespace EffectComposer diff --git a/src/plugins/effectcomposer/effectcodeeditorwidget.h b/src/plugins/effectcomposer/effectcodeeditorwidget.h new file mode 100644 index 00000000000..1ea043dc68e --- /dev/null +++ b/src/plugins/effectcomposer/effectcodeeditorwidget.h @@ -0,0 +1,63 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include +#include + +QT_FORWARD_DECLARE_CLASS(QAction) + +namespace QmlJSEditor { +class SemanticHighlighter; +} + +namespace Core { +class IContext; +} + +namespace EffectComposer { + +class EffectCodeEditorWidget : public QmlJSEditor::QmlJSEditorWidget +{ + Q_OBJECT + +public: + EffectCodeEditorWidget(); + ~EffectCodeEditorWidget() override; + + void unregisterAutoCompletion(); + void setEditorTextWithIndentation(const QString &text); + +signals: + void returnKeyClicked(); + +public: + Core::IContext *m_context = nullptr; + QAction *m_completionAction = nullptr; + bool m_isMultiline = true; +}; + +class EffectDocument : public QmlJSEditor::QmlJSEditorDocument +{ +public: + EffectDocument(); + ~EffectDocument(); + +protected: + void applyFontSettings() final; + void triggerPendingUpdates() final; + +private: + QmlJSEditor::SemanticHighlighter *m_semanticHighlighter = nullptr; +}; + +class EffectCodeEditorFactory : public TextEditor::TextEditorFactory +{ +public: + EffectCodeEditorFactory(); + + static void decorateEditor(TextEditor::TextEditorWidget *editor); +}; + +} // namespace EffectComposer diff --git a/src/plugins/effectcomposer/effectcomposercontextobject.cpp b/src/plugins/effectcomposer/effectcomposercontextobject.cpp index 95ebe7a3670..68053055b30 100644 --- a/src/plugins/effectcomposer/effectcomposercontextobject.cpp +++ b/src/plugins/effectcomposer/effectcomposercontextobject.cpp @@ -168,11 +168,11 @@ int EffectComposerContextObject::devicePixelRatio() QStringList EffectComposerContextObject::allStatesForId(const QString &id) { - if (m_model && m_model->rewriterView()) { - const QmlDesigner::QmlObjectNode node = m_model->rewriterView()->modelNodeForId(id); - if (node.isValid()) - return node.allStateNames(); - } + if (m_model) { + const QmlDesigner::QmlObjectNode node = m_model->modelNodeForId(id); + if (node.isValid()) + return node.allStateNames(); + } return {}; } diff --git a/src/plugins/effectcomposer/effectcomposermodel.cpp b/src/plugins/effectcomposer/effectcomposermodel.cpp index 3561f46a3f0..6f7a2612c98 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.cpp +++ b/src/plugins/effectcomposer/effectcomposermodel.cpp @@ -4,27 +4,36 @@ #include "effectcomposermodel.h" #include "compositionnode.h" +#include "effectshaderscodeeditor.h" #include "effectutils.h" #include "propertyhandler.h" #include "syntaxhighlighterdata.h" #include "uniform.h" +#include +#include +#include +#include +#include + +#include + #include #include #include -#include #include #include -#include - #include +#include #include #include #include +using namespace Qt::StringLiterals; + namespace EffectComposer { enum class FileType @@ -58,11 +67,12 @@ EffectComposerModel::EffectComposerModel(QObject *parent) QHash EffectComposerModel::roleNames() const { - QHash roles; - roles[NameRole] = "nodeName"; - roles[EnabledRole] = "nodeEnabled"; - roles[UniformsRole] = "nodeUniformsModel"; - roles[Dependency] = "isDependency"; + static const QHash roles = { + {NameRole, "nodeName"}, + {EnabledRole, "nodeEnabled"}, + {UniformsRole, "nodeUniformsModel"}, + {Dependency, "isDependency"}, + }; return roles; } @@ -206,6 +216,8 @@ void EffectComposerModel::clear(bool clearName) if (clearName) { setCurrentComposition(""); setCompositionPath(""); + resetRootFragmentShader(); + resetRootVertexShader(); } setHasUnsavedChanges(!m_currentComposition.isEmpty()); @@ -241,6 +253,47 @@ bool EffectComposerModel::nameExists(const QString &name) const return QFile::exists(path.arg(name)); } +void EffectComposerModel::chooseCustomPreviewImage() +{ + QTimer::singleShot(0, this, [&]() { + using Utils::FilePath; + static FilePath lastDir; + const QStringList &suffixes = QmlDesigner::Asset::supportedImageSuffixes(); + QmlDesigner::DesignDocument *document = QmlDesigner::QmlDesignerPlugin::instance()->currentDesignDocument(); + const FilePath currentDir = lastDir.isEmpty() ? document->fileName().parentDir() + : lastDir; + const QStringList fileNames = QFileDialog::getOpenFileNames(Core::ICore::dialogParent(), + tr("Select custom effect background image"), + currentDir.toFSPathString(), + tr("Image Files (%1)").arg(suffixes.join(" "))); + + if (!fileNames.isEmpty()) { + FilePath imageFile = FilePath::fromString(fileNames.first()); + lastDir = imageFile.absolutePath(); + if (imageFile.exists()) { + FilePath projDir = QmlDesigner::QmlDesignerPlugin::instance()->documentManager() + .currentProjectDirPath(); + if (!imageFile.isChildOf(projDir)) { + FilePath imagesDir = QmlDesigner::ModelNodeOperations::getImagesDefaultDirectory(); + FilePath targetFile = imagesDir.pathAppended(imageFile.fileName()); + if (!targetFile.exists()) + imageFile.copyFile(targetFile); + if (targetFile.exists()) + imageFile = targetFile; + } + + m_customPreviewImage = QUrl::fromLocalFile(imageFile.toFSPathString()); + m_currentPreviewImage = m_customPreviewImage; + + setHasUnsavedChanges(true); + + emit currentPreviewImageChanged(); + emit customPreviewImageChanged(); + } + } + }); +} + QString EffectComposerModel::fragmentShader() const { return m_fragmentShader; @@ -267,6 +320,40 @@ void EffectComposerModel::setVertexShader(const QString &newVertexShader) m_vertexShader = newVertexShader; } +void EffectComposerModel::setRootFragmentShader(const QString &shader) +{ + m_rootFragmentShader = shader; +} + +void EffectComposerModel::resetRootFragmentShader() +{ + static const QString defaultRootFragmentShader = { + "void main() {\n" + " fragColor = texture(iSource, texCoord);\n" + " @nodes\n" + " fragColor = fragColor * qt_Opacity;\n" + "}\n"}; + setRootFragmentShader(defaultRootFragmentShader); +} + +void EffectComposerModel::setRootVertexShader(const QString &shader) +{ + m_rootVertexShader = shader; +} + +void EffectComposerModel::resetRootVertexShader() +{ + static const QString defaultRootVertexShader = { + "void main() {\n" + " texCoord = qt_MultiTexCoord0;\n" + " fragCoord = qt_Vertex.xy;\n" + " vec2 vertCoord = qt_Vertex.xy;\n" + " @nodes\n" + " gl_Position = qt_Matrix * vec4(vertCoord, 0.0, 1.0);\n" + "}\n"}; + setRootVertexShader(defaultRootVertexShader); +} + QString EffectComposerModel::qmlComponentString() const { return m_qmlComponentString; @@ -960,11 +1047,26 @@ void EffectComposerModel::saveComposition(const QString &name) return; } + const Utils::FilePath compositionPath = Utils::FilePath::fromString(path); + const Utils::FilePath compositionDir = compositionPath.absolutePath(); + updateExtraMargin(); QJsonObject json; // File format version json.insert("version", 1); + json.insert("tool", "EffectComposer"); + + Utils::FilePath customPreviewPath = Utils::FilePath::fromUrl(m_customPreviewImage); + if (m_customPreviewImage.isLocalFile()) + customPreviewPath = customPreviewPath.relativePathFrom(compositionDir); + json.insert("customPreviewImage", customPreviewPath.toUrl().toString()); + + QUrl previewUrl = m_currentPreviewImage; + if (m_currentPreviewImage == m_customPreviewImage) + previewUrl = customPreviewPath.toUrl(); + + json.insert("previewImage", previewUrl.toString()); // Add nodes QJsonArray nodesArray; @@ -973,9 +1075,18 @@ void EffectComposerModel::saveComposition(const QString &name) nodesArray.append(nodeObject); } + auto toJsonArray = [](const QString &code) -> QJsonArray { + if (code.isEmpty()) + return {}; + return QJsonArray::fromStringList(code.split('\n')); + }; + if (!nodesArray.isEmpty()) json.insert("nodes", nodesArray); + json.insert("vertexCode", toJsonArray(m_rootVertexShader)); + json.insert("fragmentCode", toJsonArray(m_rootFragmentShader)); + QJsonObject rootJson; rootJson.insert("QEP", json); QJsonDocument jsonDoc(rootJson); @@ -984,20 +1095,60 @@ void EffectComposerModel::saveComposition(const QString &name) saveFile.close(); setCurrentComposition(name); - setCompositionPath(Utils::FilePath::fromString(path)); + setCompositionPath(compositionPath); saveResources(name); setHasUnsavedChanges(false); } +void EffectComposerModel::openShadersCodeEditor(int idx) +{ + if (m_nodes.size() < idx || idx < 0) + return; + + CompositionNode *node = m_nodes.at(idx); + node->openShadersCodeEditor(); +} + +void EffectComposerModel::openMainShadersCodeEditor() +{ + if (!m_shadersCodeEditor) { + m_shadersCodeEditor = Utils::makeUniqueObjectLatePtr( + currentComposition()); + m_shadersCodeEditor->setFragmentValue(m_rootFragmentShader); + m_shadersCodeEditor->setVertexValue(m_rootVertexShader); + + connect(m_shadersCodeEditor.get(), &EffectShadersCodeEditor::vertexValueChanged, this, [this] { + setRootVertexShader(m_shadersCodeEditor->vertexValue()); + setHasUnsavedChanges(true); + rebakeIfLiveUpdateMode(); + }); + + connect( + m_shadersCodeEditor.get(), &EffectShadersCodeEditor::fragmentValueChanged, this, [this] { + setRootFragmentShader(m_shadersCodeEditor->fragmentValue()); + setHasUnsavedChanges(true); + rebakeIfLiveUpdateMode(); + }); + + connect( + m_shadersCodeEditor.get(), + &EffectShadersCodeEditor::rebakeRequested, + this, + &EffectComposerModel::startRebakeTimer); + } + m_shadersCodeEditor->showWidget(); +} + void EffectComposerModel::openComposition(const QString &path) { clear(true); - const QString effectName = QFileInfo(path).baseName(); + Utils::FilePath effectPath = Utils::FilePath::fromString(path); + const QString effectName = effectPath.baseName(); setCurrentComposition(effectName); - setCompositionPath(Utils::FilePath::fromString(path)); + setCompositionPath(effectPath); QFile compFile(path); if (!compFile.open(QIODevice::ReadOnly)) { @@ -1030,6 +1181,18 @@ void EffectComposerModel::openComposition(const QString &path) QJsonObject json = rootJson["QEP"].toObject(); + const QString toolName = json.contains("tool") ? json["tool"].toString() + : json.contains("QQEM") ? "QQEM"_L1 + : ""_L1; + + if (!toolName.isEmpty() && toolName != "EffectComposer") { + const QString error + = tr("Error: '%1' effects are not compatible with 'Effect Composer'").arg(toolName); + qWarning() << error; + setEffectError(error); + return; + } + int version = -1; if (json.contains("version")) version = json["version"].toInt(-1); @@ -1041,6 +1204,63 @@ void EffectComposerModel::openComposition(const QString &path) return; } + auto toCodeBlock = [](const QJsonValue &jsonValue) -> QString { + if (!jsonValue.isArray()) + return {}; + + QString code; + const QJsonArray array = jsonValue.toArray(); + for (const QJsonValue &lineValue : array) { + if (lineValue.isString()) + code += lineValue.toString() + '\n'; + } + + return code; + }; + + if (json.contains("vertexCode")) + setRootVertexShader(toCodeBlock(json["vertexCode"])); + else + resetRootVertexShader(); + + if (json.contains("fragmentCode")) + setRootFragmentShader(toCodeBlock(json["fragmentCode"])); + else + resetRootFragmentShader(); + + m_currentPreviewImage.clear(); + if (json.contains("previewImage")) { + const QString imageStr = json["previewImage"].toString(); + if (!imageStr.isEmpty()) { + const QUrl imageUrl{imageStr}; + Utils::FilePath imagePath = Utils::FilePath::fromUrl(imageUrl); + if (imageStr.startsWith("images/preview")) { // built-in preview image + m_currentPreviewImage = imageUrl; + } else if (imagePath.isAbsolutePath()) { + if (imagePath.exists()) + m_currentPreviewImage = imageUrl; + } else { + imagePath = effectPath.absolutePath().resolvePath(imagePath); + if (imagePath.exists()) + m_currentPreviewImage = imagePath.toUrl(); + } + } + } + + m_customPreviewImage.clear(); + if (json.contains("customPreviewImage")) { + QUrl imageUrl{json["customPreviewImage"].toString()}; + Utils::FilePath imagePath = Utils::FilePath::fromUrl(imageUrl); + if (imagePath.isAbsolutePath()) { + if (imagePath.exists()) + m_customPreviewImage = imageUrl; + } else { + imagePath = effectPath.absolutePath().resolvePath(imagePath); + if (imagePath.exists()) + m_customPreviewImage = imagePath.toUrl(); + } + } + if (json.contains("nodes") && json["nodes"].isArray()) { beginResetModel(); QHash refCounts; @@ -1069,6 +1289,8 @@ void EffectComposerModel::openComposition(const QString &path) setHasUnsavedChanges(false); emit nodesChanged(); + emit currentPreviewImageChanged(); + emit customPreviewImageChanged(); } void EffectComposerModel::saveResources(const QString &name) @@ -1354,8 +1576,6 @@ QString EffectComposerModel::valueAsVariable(const Uniform &uniform) // Return name for the image property Image element QString EffectComposerModel::getImageElementName(const Uniform &uniform, bool localFiles) { - if (localFiles && uniform.value().toString().isEmpty()) - return QStringLiteral("null"); QString simplifiedName = uniform.name().simplified(); simplifiedName = simplifiedName.remove(' '); return QStringLiteral("imageItem") + simplifiedName; @@ -1439,32 +1659,6 @@ QString EffectComposerModel::processFragmentRootLine(const QString &line) return output; } -QStringList EffectComposerModel::getDefaultRootVertexShader() -{ - if (m_defaultRootVertexShader.isEmpty()) { - m_defaultRootVertexShader << "void main() {"; - m_defaultRootVertexShader << " texCoord = qt_MultiTexCoord0;"; - m_defaultRootVertexShader << " fragCoord = qt_Vertex.xy;"; - m_defaultRootVertexShader << " vec2 vertCoord = qt_Vertex.xy;"; - m_defaultRootVertexShader << " @nodes"; - m_defaultRootVertexShader << " gl_Position = qt_Matrix * vec4(vertCoord, 0.0, 1.0);"; - m_defaultRootVertexShader << "}"; - } - return m_defaultRootVertexShader; -} - -QStringList EffectComposerModel::getDefaultRootFragmentShader() -{ - if (m_defaultRootFragmentShader.isEmpty()) { - m_defaultRootFragmentShader << "void main() {"; - m_defaultRootFragmentShader << " fragColor = texture(iSource, texCoord);"; - m_defaultRootFragmentShader << " @nodes"; - m_defaultRootFragmentShader << " fragColor = fragColor * qt_Opacity;"; - m_defaultRootFragmentShader << "}"; - } - return m_defaultRootFragmentShader; -} - // Remove all post-processing tags ("@tag") from the code. // Except "@nodes" tag as that is handled later. QStringList EffectComposerModel::removeTagsFromCode(const QStringList &codeLines) @@ -1527,7 +1721,7 @@ QString EffectComposerModel::generateVertexShader(bool includeUniforms) // split to root and main parts QString s_root; QString s_main; - QStringList s_sourceCode; + QStringList s_sourceCode = m_rootVertexShader.split('\n'); m_shaderVaryingVariables.clear(); for (const CompositionNode *n : std::as_const(m_nodes)) { if (!n->vertexCode().isEmpty() && n->isEnabled()) { @@ -1544,11 +1738,6 @@ QString EffectComposerModel::generateVertexShader(bool includeUniforms) } } - if (s_sourceCode.isEmpty()) { - // If source nodes doesn't contain any code, use default one - s_sourceCode << getDefaultRootVertexShader(); - } - if (removeTags) { s_sourceCode = removeTagsFromCode(s_sourceCode); s_root = removeTagsFromCode(s_root); @@ -1583,7 +1772,7 @@ QString EffectComposerModel::generateFragmentShader(bool includeUniforms) // split to root and main parts QString s_root; QString s_main; - QStringList s_sourceCode; + QStringList s_sourceCode = m_rootFragmentShader.split('\n'); for (const CompositionNode *n : std::as_const(m_nodes)) { if (!n->fragmentCode().isEmpty() && n->isEnabled()) { const QStringList fragmentCode = n->fragmentCode().split('\n'); @@ -1599,11 +1788,6 @@ QString EffectComposerModel::generateFragmentShader(bool includeUniforms) } } - if (s_sourceCode.isEmpty()) { - // If source nodes doesn't contain any code, use default one - s_sourceCode << getDefaultRootFragmentShader(); - } - if (removeTags) { s_sourceCode = removeTagsFromCode(s_sourceCode); s_root = removeTagsFromCode(s_root); @@ -1828,7 +2012,6 @@ void EffectComposerModel::bakeShaders() runQsb(qsbPath, outPaths, false); runQsb(qsbPrevPath, outPrevPaths, true); - } bool EffectComposerModel::shadersUpToDate() const @@ -1877,11 +2060,7 @@ QString EffectComposerModel::getQmlImagesString(bool localFiles) for (Uniform *uniform : uniforms) { if (uniform->type() == Uniform::Type::Sampler) { QString imagePath = uniform->value().toString(); - // For preview, generate image element even if path is empty, as changing uniform values - // will not trigger qml code regeneration if (localFiles) { - if (imagePath.isEmpty()) - continue; QFileInfo fi(imagePath); imagePath = fi.fileName(); imagesString += QString(" property url %1Url: \"%2\"\n") @@ -2003,14 +2182,16 @@ QString EffectComposerModel::getQmlComponentString(bool localFiles) void EffectComposerModel::connectCompositionNode(CompositionNode *node) { - connect(qobject_cast(node->uniformsModel()), - &EffectComposerUniformsModel::dataChanged, this, [this] { - setHasUnsavedChanges(true); - }); - connect(node, &CompositionNode::rebakeRequested, this, [this] { - // This can come multiple times in a row in response to property changes, so let's buffer it - m_rebakeTimer.start(200); - }); + auto setUnsaved = std::bind(&EffectComposerModel::setHasUnsavedChanges, this, true); + connect( + qobject_cast(node->uniformsModel()), + &EffectComposerUniformsModel::dataChanged, + this, + setUnsaved); + + connect(node, &CompositionNode::rebakeRequested, this, &EffectComposerModel::startRebakeTimer); + connect(node, &CompositionNode::fragmentCodeChanged, this, setUnsaved); + connect(node, &CompositionNode::vertexCodeChanged, this, setUnsaved); } void EffectComposerModel::updateExtraMargin() @@ -2020,6 +2201,18 @@ void EffectComposerModel::updateExtraMargin() m_extraMargin = qMax(node->extraMargin(), m_extraMargin); } +void EffectComposerModel::startRebakeTimer() +{ + // This can come multiple times in a row in response to property changes, so let's buffer it + m_rebakeTimer.start(200); +} + +void EffectComposerModel::rebakeIfLiveUpdateMode() +{ + if (m_shadersCodeEditor && m_shadersCodeEditor->liveUpdate()) + startRebakeTimer(); +} + QSet EffectComposerModel::getExposedProperties(const QByteArray &qmlContent) { QSet returnSet; @@ -2051,6 +2244,30 @@ void EffectComposerModel::setCurrentComposition(const QString &newCurrentComposi m_currentComposition = newCurrentComposition; emit currentCompositionChanged(); + + m_shadersCodeEditor.reset(); +} + +QUrl EffectComposerModel::customPreviewImage() const +{ + return m_customPreviewImage; +} + +QUrl EffectComposerModel::currentPreviewImage() const +{ + return m_currentPreviewImage; +} + +void EffectComposerModel::setCurrentPreviewImage(const QUrl &path) +{ + if (m_currentPreviewImage == path) + return; + + if (!m_nodes.isEmpty()) + setHasUnsavedChanges(true); + + m_currentPreviewImage = path; + emit currentPreviewImageChanged(); } Utils::FilePath EffectComposerModel::compositionPath() const diff --git a/src/plugins/effectcomposer/effectcomposermodel.h b/src/plugins/effectcomposer/effectcomposermodel.h index 098cc730069..09aeb724532 100644 --- a/src/plugins/effectcomposer/effectcomposermodel.h +++ b/src/plugins/effectcomposer/effectcomposermodel.h @@ -6,6 +6,7 @@ #include "shaderfeatures.h" #include +#include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include namespace ProjectExplorer { class Target; @@ -26,6 +28,7 @@ class Process; namespace EffectComposer { class CompositionNode; +class EffectShadersCodeEditor; class Uniform; struct EffectError { @@ -51,6 +54,8 @@ class EffectComposerModel : public QAbstractListModel Q_PROPERTY(bool isEnabled READ isEnabled WRITE setIsEnabled NOTIFY isEnabledChanged) Q_PROPERTY(bool hasValidTarget READ hasValidTarget WRITE setHasValidTarget NOTIFY hasValidTargetChanged) Q_PROPERTY(QString currentComposition READ currentComposition WRITE setCurrentComposition NOTIFY currentCompositionChanged) + Q_PROPERTY(QUrl currentPreviewImage READ currentPreviewImage WRITE setCurrentPreviewImage NOTIFY currentPreviewImageChanged) + Q_PROPERTY(QUrl customPreviewImage READ customPreviewImage NOTIFY customPreviewImageChanged) public: EffectComposerModel(QObject *parent = nullptr); @@ -75,6 +80,7 @@ public: Q_INVOKABLE void assignToSelected(); Q_INVOKABLE QString getUniqueEffectName() const; Q_INVOKABLE bool nameExists(const QString &name) const; + Q_INVOKABLE void chooseCustomPreviewImage(); bool shadersUpToDate() const; void setShadersUpToDate(bool newShadersUpToDate); @@ -91,6 +97,12 @@ public: QString vertexShader() const; void setVertexShader(const QString &newVertexShader); + void setRootFragmentShader(const QString &shader); + void resetRootFragmentShader(); + + void setRootVertexShader(const QString &shader); + void resetRootVertexShader(); + Q_INVOKABLE QString qmlComponentString() const; Q_INVOKABLE void updateQmlComponent(); @@ -100,11 +112,18 @@ public: Q_INVOKABLE void saveComposition(const QString &name); + Q_INVOKABLE void openShadersCodeEditor(int idx); + Q_INVOKABLE void openMainShadersCodeEditor(); + void openComposition(const QString &path); QString currentComposition() const; void setCurrentComposition(const QString &newCurrentComposition); + QUrl customPreviewImage() const; + QUrl currentPreviewImage() const; + void setCurrentPreviewImage(const QUrl &path); + Utils::FilePath compositionPath() const; void setCompositionPath(const Utils::FilePath &newCompositionPath); @@ -129,6 +148,8 @@ signals: void hasUnsavedChangesChanged(); void assignToSelectedTriggered(const QString &effectPath); void removePropertiesFromScene(QSet props, const QString &typeName); + void currentPreviewImageChanged(); + void customPreviewImageChanged(); private: enum Roles { @@ -167,8 +188,6 @@ private: int getTagIndex(const QStringList &code, const QString &tag); QString processVertexRootLine(const QString &line); QString processFragmentRootLine(const QString &line); - QStringList getDefaultRootVertexShader(); - QStringList getDefaultRootFragmentShader(); QStringList removeTagsFromCode(const QStringList &codeLines); QString removeTagsFromCode(const QString &code); QString getCustomShaderVaryings(bool outState); @@ -190,6 +209,8 @@ private: void connectCompositionNode(CompositionNode *node); void updateExtraMargin(); + void startRebakeTimer(); + void rebakeIfLiveUpdateMode(); QSet getExposedProperties(const QByteArray &qmlContent); QList m_nodes; @@ -205,8 +226,8 @@ private: QStringList m_shaderVaryingVariables; QString m_fragmentShader; QString m_vertexShader; - QStringList m_defaultRootVertexShader; - QStringList m_defaultRootFragmentShader; + QString m_rootVertexShader; + QString m_rootFragmentShader; // Temp files to store shaders sources and binary data QTemporaryDir m_shaderDir; QString m_fragmentSourceFilename; @@ -230,6 +251,9 @@ private: int m_extraMargin = 0; QString m_effectTypePrefix; Utils::FilePath m_compositionPath; + Utils::UniqueObjectLatePtr m_shadersCodeEditor; + QUrl m_currentPreviewImage; + QUrl m_customPreviewImage; const QRegularExpression m_spaceReg = QRegularExpression("\\s+"); }; diff --git a/src/plugins/effectcomposer/effectcomposerview.cpp b/src/plugins/effectcomposer/effectcomposerview.cpp index d8077502bcb..08fad0150d9 100644 --- a/src/plugins/effectcomposer/effectcomposerview.cpp +++ b/src/plugins/effectcomposer/effectcomposerview.cpp @@ -6,6 +6,7 @@ #include "effectcomposermodel.h" #include "effectcomposernodesmodel.h" #include "effectcomposerwidget.h" +#include "studioquickwidget.h" #include #include @@ -218,4 +219,27 @@ void EffectComposerView::removeUnusedEffectImports() } } +void EffectComposerView::highlightSupportedProperties(bool highlight, const QString &suffix) +{ + QQmlContext *ctxObj = m_widget->quickWidget()->rootContext(); + ctxObj->setContextProperty("activeDragSuffix", suffix); + ctxObj->setContextProperty("hasActiveDrag", highlight); +} + +void EffectComposerView::dragStarted(QMimeData *mimeData) +{ + if (mimeData->hasFormat(QmlDesigner::Constants::MIME_TYPE_ASSETS)) { + QString format = mimeData->formats()[0]; + const QString assetPath = QString::fromUtf8(mimeData->data(format)).split(',')[0]; + const QString suffix = "*." + assetPath.split('.').last().toLower(); + + highlightSupportedProperties(true, suffix); + } +} + +void EffectComposerView::dragEnded() +{ + highlightSupportedProperties(false); +} + } // namespace EffectComposer diff --git a/src/plugins/effectcomposer/effectcomposerview.h b/src/plugins/effectcomposer/effectcomposerview.h index aed51146805..347409172ea 100644 --- a/src/plugins/effectcomposer/effectcomposerview.h +++ b/src/plugins/effectcomposer/effectcomposerview.h @@ -31,6 +31,11 @@ public: const QList &lastSelectedNodeList) override; void nodeAboutToBeRemoved(const QmlDesigner::ModelNode &removedNode) override; + void dragStarted(QMimeData *mimeData) override; + void dragEnded() override; + + void highlightSupportedProperties(bool highlight, const QString &suffix = {}); + private: void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; diff --git a/src/plugins/effectcomposer/effectshaderscodeeditor.cpp b/src/plugins/effectcomposer/effectshaderscodeeditor.cpp new file mode 100644 index 00000000000..95fe30a54e6 --- /dev/null +++ b/src/plugins/effectcomposer/effectshaderscodeeditor.cpp @@ -0,0 +1,226 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "effectshaderscodeeditor.h" +#include "effectcodeeditorwidget.h" + +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace { + +using IconId = QmlDesigner::DesignerIcons::IconId; + +inline constexpr char EFFECTCOMPOSER_LIVE_UPDATE_KEY[] = "EffectComposer/CodeEditor/LiveUpdate"; + +QIcon toolbarIcon(IconId iconId) +{ + return QmlDesigner::DesignerActionManager::instance().toolbarIcon(iconId); +}; + +} // namespace + +namespace EffectComposer { + +EffectShadersCodeEditor::EffectShadersCodeEditor(const QString &title, QWidget *parent) + : QWidget(parent) + , m_settings(new QSettings(qApp->organizationName(), qApp->applicationName(), this)) +{ + setWindowFlag(Qt::Tool, true); + setWindowTitle(title); + + m_fragmentEditor = createJSEditor(); + m_vertexEditor = createJSEditor(); + + connect( + m_fragmentEditor, + &QPlainTextEdit::textChanged, + this, + &EffectShadersCodeEditor::fragmentValueChanged); + connect( + m_vertexEditor, + &QPlainTextEdit::textChanged, + this, + &EffectShadersCodeEditor::vertexValueChanged); + + setupUIComponents(); +} + +EffectShadersCodeEditor::~EffectShadersCodeEditor() +{ + m_fragmentEditor->deleteLater(); + m_vertexEditor->deleteLater(); +} + +void EffectShadersCodeEditor::showWidget() +{ + readAndApplyLiveUpdateSettings(); + show(); + raise(); + m_vertexEditor->setFocus(); +} + +void EffectShadersCodeEditor::showWidget(int x, int y) +{ + showWidget(); + move(QPoint(x, y)); +} + +QString EffectShadersCodeEditor::fragmentValue() const +{ + if (!m_fragmentEditor) + return {}; + + return m_fragmentEditor->document()->toPlainText(); +} + +void EffectShadersCodeEditor::setFragmentValue(const QString &text) +{ + if (m_fragmentEditor) + m_fragmentEditor->setEditorTextWithIndentation(text); +} + +QString EffectShadersCodeEditor::vertexValue() const +{ + if (!m_vertexEditor) + return {}; + + return m_vertexEditor->document()->toPlainText(); +} + +void EffectShadersCodeEditor::setVertexValue(const QString &text) +{ + if (m_vertexEditor) + m_vertexEditor->setEditorTextWithIndentation(text); +} + +bool EffectShadersCodeEditor::liveUpdate() const +{ + return m_liveUpdate; +} + +void EffectShadersCodeEditor::setLiveUpdate(bool liveUpdate) +{ + if (m_liveUpdate == liveUpdate) + return; + + m_liveUpdate = liveUpdate; + writeLiveUpdateSettings(); + + emit liveUpdateChanged(m_liveUpdate); + + if (m_liveUpdate) + emit rebakeRequested(); +} + +EffectCodeEditorWidget *EffectShadersCodeEditor::createJSEditor() +{ + static EffectCodeEditorFactory f; + TextEditor::BaseTextEditor *editor = qobject_cast( + f.createEditor()); + Q_ASSERT(editor); + + editor->setParent(this); + + EffectCodeEditorWidget *editorWidget = qobject_cast( + editor->editorWidget()); + Q_ASSERT(editorWidget); + + editorWidget->setLineNumbersVisible(false); + editorWidget->setMarksVisible(false); + editorWidget->setCodeFoldingSupported(false); + editorWidget->setTabChangesFocus(true); + editorWidget->unregisterAutoCompletion(); + editorWidget->setParent(this); + editorWidget->setFrameStyle(QFrame::StyledPanel | QFrame::Raised); + + return editorWidget; +} + +void EffectShadersCodeEditor::setupUIComponents() +{ + QVBoxLayout *verticalLayout = new QVBoxLayout(this); + QTabWidget *tabWidget = new QTabWidget(this); + + tabWidget->addTab(m_fragmentEditor, tr("Fragment Shader")); + tabWidget->addTab(m_vertexEditor, tr("Vertex Shader")); + + verticalLayout->setContentsMargins(0, 0, 0, 0); + verticalLayout->addWidget(createToolbar()); + verticalLayout->addWidget(tabWidget); + + this->resize(660, 240); +} + +void EffectShadersCodeEditor::closeEvent(QCloseEvent *event) +{ + QWidget::closeEvent(event); + + if (!liveUpdate()) + emit rebakeRequested(); +} + +void EffectShadersCodeEditor::writeLiveUpdateSettings() +{ + m_settings->setValue(EFFECTCOMPOSER_LIVE_UPDATE_KEY, m_liveUpdate); +} + +void EffectShadersCodeEditor::readAndApplyLiveUpdateSettings() +{ + bool liveUpdateStatus = m_settings->value(EFFECTCOMPOSER_LIVE_UPDATE_KEY, false).toBool(); + + setLiveUpdate(liveUpdateStatus); +} + +QToolBar *EffectShadersCodeEditor::createToolbar() +{ + using QmlDesigner::Theme; + + QToolBar *toolbar = new QToolBar(this); + + toolbar->setFixedHeight(Theme::toolbarSize()); + toolbar->setFloatable(false); + toolbar->setContentsMargins(0, 0, 0, 0); + + toolbar->setStyleSheet(Theme::replaceCssColors( + QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css")))); + + QAction *liveUpdateButton + = toolbar->addAction(toolbarIcon(IconId::LiveUpdateIcon), tr("Live Update")); + liveUpdateButton->setCheckable(true); + connect(liveUpdateButton, &QAction::toggled, this, &EffectShadersCodeEditor::setLiveUpdate); + + QAction *applyAction = toolbar->addAction(toolbarIcon(IconId::SyncIcon), tr("Apply")); + connect(applyAction, &QAction::triggered, this, &EffectShadersCodeEditor::rebakeRequested); + + auto syncLive = [liveUpdateButton, applyAction](bool liveState) { + liveUpdateButton->setChecked(liveState); + applyAction->setDisabled(liveState); + }; + + connect(this, &EffectShadersCodeEditor::liveUpdateChanged, this, syncLive); + syncLive(liveUpdate()); + + toolbar->addAction(liveUpdateButton); + toolbar->addAction(applyAction); + + return toolbar; +} + +} // namespace EffectComposer diff --git a/src/plugins/effectcomposer/effectshaderscodeeditor.h b/src/plugins/effectcomposer/effectshaderscodeeditor.h new file mode 100644 index 00000000000..f797315f4a6 --- /dev/null +++ b/src/plugins/effectcomposer/effectshaderscodeeditor.h @@ -0,0 +1,61 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +QT_FORWARD_DECLARE_CLASS(QSettings) +QT_FORWARD_DECLARE_CLASS(QToolBar) + +namespace EffectComposer { + +class EffectCodeEditorWidget; + +class EffectShadersCodeEditor : public QWidget +{ + Q_OBJECT + Q_PROPERTY(bool liveUpdate READ liveUpdate WRITE setLiveUpdate NOTIFY liveUpdateChanged) + +public: + EffectShadersCodeEditor(const QString &title = tr("Untitled Editor"), QWidget *parent = nullptr); + ~EffectShadersCodeEditor() override; + + void showWidget(); + void showWidget(int x, int y); + + QString fragmentValue() const; + void setFragmentValue(const QString &text); + + QString vertexValue() const; + void setVertexValue(const QString &text); + + bool liveUpdate() const; + void setLiveUpdate(bool liveUpdate); + +signals: + void liveUpdateChanged(bool); + void fragmentValueChanged(); + void vertexValueChanged(); + void rebakeRequested(); + +protected: + using QWidget::show; + EffectCodeEditorWidget *createJSEditor(); + void setupUIComponents(); + + void closeEvent(QCloseEvent *event) override; + +private: + void writeLiveUpdateSettings(); + void readAndApplyLiveUpdateSettings(); + QToolBar *createToolbar(); + + QSettings *m_settings = nullptr; + QPointer m_fragmentEditor; + QPointer m_vertexEditor; + + bool m_liveUpdate = false; +}; + +} // namespace EffectComposer diff --git a/src/plugins/effectcomposer/uniform.cpp b/src/plugins/effectcomposer/uniform.cpp index 590b38b423b..c42f11063d6 100644 --- a/src/plugins/effectcomposer/uniform.cpp +++ b/src/plugins/effectcomposer/uniform.cpp @@ -57,6 +57,14 @@ Uniform::Uniform(const QString &effectName, const QJsonObject &propObj, const QS m_backendValue = new QmlDesigner::PropertyEditorValue(this); m_backendValue->setValue(value); + + connect(m_backendValue, &QmlDesigner::PropertyEditorValue::dropCommitted, + this, [this](const QString &dropData) { + m_backendValue->setValue(dropData); + auto *model = QmlDesigner::QmlDesignerPlugin::instance() + ->currentDesignDocument()->currentModel(); + model->endDrag(); + }); } Uniform::Type Uniform::type() const diff --git a/src/plugins/insight/insightmodel.cpp b/src/plugins/insight/insightmodel.cpp index 50474ffecff..3a4d03124ce 100644 --- a/src/plugins/insight/insightmodel.cpp +++ b/src/plugins/insight/insightmodel.cpp @@ -7,9 +7,10 @@ #include #include #include +#include +#include #include #include -#include #include #include @@ -192,7 +193,9 @@ Qt::CheckState checkState(const std::vector &a, const std::vectorsetCheckLinkErrors(false); rewriter->setTextModifier(modifier.get()); +#ifdef QDS_USE_PROJECTSTORAGE + model = QmlDesigner::Model::create(projectStorageDependencies, + "Item", + {Import::createLibraryImport("QtQuick")}, + filePath); +#else model = QmlDesigner::Model::create("QtQuick.Item", 2, 1); +#endif model->setRewriterView(rewriter.get()); } @@ -221,9 +231,12 @@ struct ModelBuilder } // namespace -InsightModel::InsightModel(InsightView *view, ExternalDependenciesInterface &externalDependencies) +InsightModel::InsightModel(InsightView *view, + ExternalDependenciesInterface &externalDependencies, + QmlDesignerProjectManager &projectManager) : m_insightView(view) , m_externalDependencies(externalDependencies) + , m_projectManager(projectManager) , m_fileSystemWatcher(new Utils::FileSystemWatcher(this)) { QObject::connect(ProjectExplorer::ProjectManager::instance(), @@ -446,7 +459,9 @@ void InsightModel::setEnabled(bool value) return; } - ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(), m_externalDependencies); + ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(), + m_externalDependencies, + m_projectManager.projectStorageDependencies()); if (!builder.model) { qWarning() << "Could not create model" << m_mainQmlInfo.absoluteFilePath(); @@ -613,7 +628,9 @@ int InsightModel::devicePixelRatio() void InsightModel::parseMainQml() { - ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(), m_externalDependencies); + ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(), + m_externalDependencies, + m_projectManager.projectStorageDependencies()); if (!builder.model) return; diff --git a/src/plugins/insight/insightmodel.h b/src/plugins/insight/insightmodel.h index b21d7e36205..302d79e25b4 100644 --- a/src/plugins/insight/insightmodel.h +++ b/src/plugins/insight/insightmodel.h @@ -39,7 +39,9 @@ class InsightModel : public QAbstractListModel }; public: - InsightModel(InsightView *view, class ExternalDependenciesInterface &externalDependencies); + InsightModel(InsightView *view, + class ExternalDependenciesInterface &externalDependencies, + class QmlDesignerProjectManager &projectManager); int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; @@ -109,6 +111,7 @@ private: private: QPointer m_insightView; ExternalDependenciesInterface &m_externalDependencies; + QmlDesignerProjectManager &m_projectManager; Utils::FileSystemWatcher *m_fileSystemWatcher; diff --git a/src/plugins/insight/insightplugin.cpp b/src/plugins/insight/insightplugin.cpp index f3bbcf5fa5c..a7172d807cf 100644 --- a/src/plugins/insight/insightplugin.cpp +++ b/src/plugins/insight/insightplugin.cpp @@ -20,7 +20,8 @@ class InsightPlugin final : public ExtensionSystem::IPlugin auto *designerPlugin = QmlDesignerPlugin::instance(); auto &viewManager = designerPlugin->viewManager(); viewManager.registerView(std::make_unique( - QmlDesignerPlugin::externalDependenciesForPluginInitializationOnly())); + QmlDesignerPlugin::externalDependenciesForPluginInitializationOnly(), + QmlDesignerPlugin::projectManagerForPluginInitializationOnly())); return true; } diff --git a/src/plugins/insight/insightview.cpp b/src/plugins/insight/insightview.cpp index 28101dc94e3..8a4dd5d19ec 100644 --- a/src/plugins/insight/insightview.cpp +++ b/src/plugins/insight/insightview.cpp @@ -14,9 +14,10 @@ namespace QmlDesigner { -InsightView::InsightView(ExternalDependenciesInterface &externalDependencies) +InsightView::InsightView(ExternalDependenciesInterface &externalDependencies, + QmlDesignerProjectManager &projectManager) : AbstractView(externalDependencies) - , m_insightModel(std::make_unique(this, externalDependencies)) + , m_insightModel(std::make_unique(this, externalDependencies, projectManager)) { Q_ASSERT(m_insightModel); } diff --git a/src/plugins/insight/insightview.h b/src/plugins/insight/insightview.h index e39f34239c2..00f2877d234 100644 --- a/src/plugins/insight/insightview.h +++ b/src/plugins/insight/insightview.h @@ -15,13 +15,15 @@ namespace QmlDesigner { class InsightModel; class InsightWidget; +class QmlDesignerProjectManager; class InsightView : public AbstractView { Q_OBJECT public: - explicit InsightView(ExternalDependenciesInterface &externalDependencies); + explicit InsightView(ExternalDependenciesInterface &externalDependencies, + QmlDesignerProjectManager &projectManager); ~InsightView() override; // AbstractView diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index eb498302fbd..f97e3b4a169 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -52,13 +52,14 @@ add_qtc_plugin(QmlDesigner QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem Qt::QuickWidgets Qt::CorePrivate Qt::Xml Qt::Svg Sqlite Zip Qt::GuiPrivate PUBLIC_DEPENDS - QmlDesignerUtils QmlPuppetCommunication QmlDesignerCore + QmlDesignerUtils QmlPuppetCommunication QmlDesignerCore DesignSystem DEFINES IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\" SHARE_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/../../../share/qtcreator/qmldesigner" - $<$:QDS_USE_PROJECTSTORAGE> $<$:QTC_USE_QML_DESIGNER_LITE> $<$:DETACH_DISABLED_VIEWS> + PUBLIC_DEFINES + $<$:QDS_USE_PROJECTSTORAGE> INCLUDES ${CMAKE_CURRENT_LIST_DIR}/libs ${CMAKE_CURRENT_LIST_DIR}/components @@ -725,14 +726,6 @@ extend_qtc_plugin(QmlDesigner messagemodel.h ) -extend_qtc_plugin(QmlDesigner - SOURCES_PREFIX components/designsystem - SOURCES - dsconstants.h - dsthememanager.h dsthememanager.cpp - dsthemegroup.cpp dsthemegroup.h -) - add_qtc_plugin(assetexporterplugin PLUGIN_CLASS AssetExporterPlugin CONDITION TARGET QmlDesigner diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp index 5fd0c5e0fa7..62f0522fafc 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.cpp @@ -85,13 +85,13 @@ private: std::atomic m_quitDumper; }; - - -AssetExporter::AssetExporter(AssetExporterView *view, ProjectExplorer::Project *project, QObject *parent) : - QObject(parent), - m_currentState(*this), - m_project(project), - m_view(view) +AssetExporter::AssetExporter(AssetExporterView *view, + ProjectExplorer::Project *project, + ProjectStorageDependencies projectStorageDependencies) + : m_currentState(*this) + , m_project(project) + , m_view(view) + , m_projectStorageDependencies{projectStorageDependencies} { connect(m_view, &AssetExporterView::loadingFinished, this, &AssetExporter::onQmlFileLoaded); connect(m_view, &AssetExporterView::loadingError, this, &AssetExporter::notifyLoadError); @@ -260,7 +260,14 @@ void AssetExporter::preprocessQmlFile(const Utils::FilePath &path) { // Load the QML file and assign UUIDs to items having none. // Meanwhile cache the Component UUIDs as well - ModelPointer model(Model::create("Item", 2, 7)); +#ifdef QDS_USE_PROJECTSTORAGE + ModelPointer model = Model::create(m_projectStorageDependencies, + "Item", + {Import::createLibraryImport("QtQuick")}, + path.path()); +#else + ModelPointer model = Model::create("Item", 2, 7); +#endif Utils::FileReader reader; if (!reader.fetch(path)) { ExportNotification::addError(tr("Cannot preprocess file: %1. Error %2") diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h index f356d56a0d0..36e7d29136b 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporter.h @@ -32,8 +32,9 @@ public: ExportingDone }; - AssetExporter(AssetExporterView *view, ProjectExplorer::Project *project, - QObject *parent = nullptr); + AssetExporter(AssetExporterView *view, + ProjectExplorer::Project *project, + ProjectStorageDependencies projectStorageDependencies); ~AssetExporter(); void exportQml(const Utils::FilePaths &qmlFiles, const Utils::FilePath &exportPath, @@ -89,6 +90,7 @@ private: QHash m_componentUuidCache; QSet m_usedHashes; QHash m_assets; + ProjectStorageDependencies m_projectStorageDependencies; std::unique_ptr m_assetDumper; bool m_cancelled = false; }; diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.cpp b/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.cpp index ea0899d07c6..6246e0ed36f 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.cpp @@ -3,12 +3,13 @@ #include "assetexporterplugin.h" -#include "assetexportpluginconstants.h" #include "assetexportdialog.h" #include "assetexporter.h" #include "assetexporterview.h" -#include "filepathmodel.h" +#include "assetexportpluginconstants.h" #include "componentexporter.h" +#include "filepathmodel.h" +#include #include "dumpers/itemnodedumper.h" #include "dumpers/textnodedumper.h" @@ -37,6 +38,7 @@ namespace QmlDesigner { AssetExporterPlugin::AssetExporterPlugin() + : m_projectManager{QmlDesigner::QmlDesignerPlugin::projectManagerForPluginInitializationOnly()} { ProjectExplorer::TaskHub::addCategory({Constants::TASK_CATEGORY_ASSET_EXPORT, tr("Asset Export"), @@ -44,6 +46,7 @@ AssetExporterPlugin::AssetExporterPlugin() false}); auto *designerPlugin = QmlDesigner::QmlDesignerPlugin::instance(); + auto &viewManager = designerPlugin->viewManager(); m_view = viewManager.registerView(std::make_unique( designerPlugin->externalDependenciesForPluginInitializationOnly())); @@ -79,7 +82,7 @@ void AssetExporterPlugin::onExport() if (!exportDir.parentDir().isEmpty()) exportDir = exportDir.parentDir(); exportDir = exportDir.pathAppended(startupProject->displayName() + "_export"); - AssetExporter assetExporter(m_view, startupProject); + AssetExporter assetExporter(m_view, startupProject, m_projectManager.projectStorageDependencies()); AssetExportDialog assetExporterDialog(exportDir, assetExporter, model); assetExporterDialog.exec(); } diff --git a/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.h b/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.h index 9261b4601f8..1c2b779138e 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.h +++ b/src/plugins/qmldesigner/assetexporterplugin/assetexporterplugin.h @@ -29,6 +29,7 @@ private: void updateActions(); AssetExporterView *m_view = nullptr; + class QmlDesignerProjectManager &m_projectManager; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp index 701e9fdd244..5979ea2f657 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.cpp @@ -21,19 +21,6 @@ namespace { Q_LOGGING_CATEGORY(loggerInfo, "qtc.designer.assetExportPlugin.modelExporter", QtInfoMsg) - -static QByteArrayList populateLineage(const QmlDesigner::ModelNode &node) -{ - QByteArrayList lineage; - if (!node.isValid() || node.type().isEmpty()) - return {}; - - for (auto &info : node.metaInfo().prototypes()) - lineage.append(info.typeName()); - - return lineage; -} - } namespace QmlDesigner { @@ -78,10 +65,9 @@ const QString &Component::name() const NodeDumper *Component::createNodeDumper(const ModelNode &node) const { - QByteArrayList lineage = populateLineage(node); std::unique_ptr reader; for (auto &dumperCreator: m_readers) { - std::unique_ptr r(dumperCreator->instance(lineage, node)); + std::unique_ptr r(dumperCreator->instance(node)); if (r->isExportable()) { if (reader) { if (reader->priority() < r->priority()) diff --git a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h index cf816c748c9..59ee8a2e677 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h +++ b/src/plugins/qmldesigner/assetexporterplugin/componentexporter.h @@ -27,7 +27,7 @@ class NodeDumperCreatorBase public: virtual ~NodeDumperCreatorBase() {} protected: - virtual NodeDumper *instance(const QByteArrayList &, const ModelNode &) const = 0; + virtual NodeDumper *instance(const ModelNode &) const = 0; friend Component; }; @@ -39,9 +39,7 @@ public: ~NodeDumperCreator() = default; protected: - NodeDumper *instance(const QByteArrayList &lineage, const ModelNode &node) const { - return new T(lineage, node); - } + NodeDumper *instance(const ModelNode &node) const { return new T(node); } }; } //Internal diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.cpp b/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.cpp index fea0f19c801..3fd6cbb333f 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.cpp @@ -14,18 +14,18 @@ namespace QmlDesigner { using namespace Constants; -AssetNodeDumper::AssetNodeDumper(const QByteArrayList &lineage, const ModelNode &node) : - ItemNodeDumper(lineage, node) + +AssetNodeDumper::AssetNodeDumper(const ModelNode &node) + : ItemNodeDumper(node) { } bool AssetNodeDumper::isExportable() const { - auto hasType = [this](const QByteArray &type) { - return lineage().contains(type); - }; - return hasType("QtQuick.Image") || hasType("QtQuick.Rectangle"); + auto qtQuickImageMetaInfo = model()->qtQuickImageMetaInfo(); + auto qtQuickRectangleMetaInfo = model()->qtQuickRectangleMetaInfo(); + return metaInfo().isBasedOn(qtQuickImageMetaInfo, qtQuickRectangleMetaInfo); } QJsonObject AssetNodeDumper::json(Component &component) const diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.h b/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.h index c7bba0b3720..1a5449efafc 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.h +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/assetnodedumper.h @@ -10,7 +10,7 @@ class Component; class AssetNodeDumper : public ItemNodeDumper { public: - AssetNodeDumper(const QByteArrayList &lineage, const ModelNode &node); + AssetNodeDumper(const ModelNode &node); ~AssetNodeDumper() override = default; bool isExportable() const override; diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.cpp b/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.cpp index 3f5fc4a50c8..e7159d76626 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.cpp @@ -22,16 +22,16 @@ static QString capitalize(const QString &str) namespace QmlDesigner { using namespace Constants; -ItemNodeDumper::ItemNodeDumper(const QByteArrayList &lineage, - const ModelNode &node) : - NodeDumper(lineage, node) + +ItemNodeDumper::ItemNodeDumper(const ModelNode &node) + : NodeDumper(node) { } bool QmlDesigner::ItemNodeDumper::isExportable() const { - return lineage().contains("QtQuick.Item"); + return metaInfo().isQtQuickItem(); } QJsonObject QmlDesigner::ItemNodeDumper::json([[maybe_unused]] QmlDesigner::Component &component) const diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.h b/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.h index 25576bb4067..9752d37caef 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.h +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/itemnodedumper.h @@ -11,7 +11,7 @@ class Component; class ItemNodeDumper : public NodeDumper { public: - ItemNodeDumper(const QByteArrayList &lineage, const ModelNode &node); + ItemNodeDumper(const ModelNode &node); ~ItemNodeDumper() override = default; diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.cpp b/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.cpp index 390b0684c8c..521180f2f28 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.cpp @@ -6,10 +6,11 @@ #include namespace QmlDesigner { -NodeDumper::NodeDumper(const QByteArrayList &lineage, const ModelNode &node) : - m_node(node), - m_objectNode(node), - m_lineage(lineage) +NodeDumper::NodeDumper(const ModelNode &node) + : m_node(node) + , m_objectNode(node) + , m_metaInfo(node.metaInfo()) + , m_model{node.model()} { } diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.h b/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.h index f735884e5d0..17bace9ad61 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.h +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/nodedumper.h @@ -14,7 +14,7 @@ class ModelNode; class NodeDumper { public: - NodeDumper(const QByteArrayList &lineage, const ModelNode &node); + NodeDumper(const ModelNode &node); virtual ~NodeDumper() = default; @@ -22,16 +22,19 @@ public: virtual bool isExportable() const = 0; virtual QJsonObject json(Component& component) const = 0; - const QByteArrayList& lineage() const { return m_lineage; } + const NodeMetaInfo &metaInfo() const { return m_metaInfo; } const QmlObjectNode& objectNode() const { return m_objectNode; } QVariant propertyValue(const PropertyName &name) const; QString uuid() const; + Model *model() const { return m_model; } + protected: const ModelNode &m_node; private: QmlObjectNode m_objectNode; - QByteArrayList m_lineage; + NodeMetaInfo m_metaInfo; + Model *m_model = nullptr; }; } diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.cpp b/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.cpp index aaf87af73ba..5f96d3e2175 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.cpp +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.cpp @@ -4,6 +4,8 @@ #include "textnodedumper.h" #include "assetexportpluginconstants.h" +#include + #include #include #include @@ -35,18 +37,18 @@ QString toJsonAlignEnum(QString value) { namespace QmlDesigner { using namespace Constants; -TextNodeDumper::TextNodeDumper(const QByteArrayList &lineage, const ModelNode &node) : - ItemNodeDumper(lineage, node) + +TextNodeDumper::TextNodeDumper(const ModelNode &node) + : ItemNodeDumper(node) { } bool TextNodeDumper::isExportable() const { - const QByteArrayList &baseClasses = lineage(); - return std::any_of(baseClasses.cbegin(), baseClasses.cend(), [](const QByteArray &type) { - return type == "QtQuick.Text" || type == "QtQuick.Controls.Label"; - }); + auto qtQuickTextMetaInfo = model()->qtQuickTextMetaInfo(); + auto qtQuickControlsLabelMetaInfo = model()->qtQuickControlsLabelMetaInfo(); + return metaInfo().isBasedOn(qtQuickTextMetaInfo, qtQuickControlsLabelMetaInfo); } QJsonObject TextNodeDumper::json([[maybe_unused]] Component &component) const diff --git a/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.h b/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.h index efd2ea5ca47..b084bdae48c 100644 --- a/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.h +++ b/src/plugins/qmldesigner/assetexporterplugin/dumpers/textnodedumper.h @@ -10,7 +10,7 @@ class Component; class TextNodeDumper : public ItemNodeDumper { public: - TextNodeDumper(const QByteArrayList &lineage, const ModelNode &node); + TextNodeDumper(const ModelNode &node); ~TextNodeDumper() override = default; bool isExportable() const override; diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp index 3b7524faa00..19c7319d2c0 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp @@ -41,7 +41,7 @@ void AssetsLibraryModel::createBackendModel() QObject::connect(m_sourceFsModel, &QFileSystemModel::directoryLoaded, this, [this]([[maybe_unused]] const QString &dir) { - syncHasFiles(); + syncIsEmpty(); }); m_fileWatcher = new Utils::FileSystemWatcher(parent()); @@ -202,7 +202,7 @@ bool AssetsLibraryModel::isSameOrDescendantPath(const QUrl &source, const QStrin Utils::FilePath srcPath = Utils::FilePath::fromUrl(source); Utils::FilePath targetPath = Utils::FilePath::fromString(target); - return targetPath.isChildOf(srcPath); + return srcPath == targetPath || targetPath.isChildOf(srcPath); } bool AssetsLibraryModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const @@ -224,41 +224,20 @@ bool AssetsLibraryModel::filterAcceptsRow(int sourceRow, const QModelIndex &sour } } -bool AssetsLibraryModel::checkHasFiles(const QModelIndex &parentIdx) const +void AssetsLibraryModel::setIsEmpty(bool value) { - if (!parentIdx.isValid()) - return false; - - const int rowCount = this->rowCount(parentIdx); - for (int i = 0; i < rowCount; ++i) { - auto newIdx = this->index(i, 0, parentIdx); - if (!isDirectory(newIdx)) - return true; - - if (checkHasFiles(newIdx)) - return true; - } - - return false; -} - -void AssetsLibraryModel::setHasFiles(bool value) -{ - if (m_hasFiles != value) { - m_hasFiles = value; - emit hasFilesChanged(); + if (m_isEmpty != value) { + m_isEmpty = value; + emit isEmptyChanged(); } } -bool AssetsLibraryModel::checkHasFiles() const +void AssetsLibraryModel::syncIsEmpty() { - auto rootIdx = indexForPath(m_rootPath); - return checkHasFiles(rootIdx); -} + QModelIndex rootIdx = indexForPath(m_rootPath); -void AssetsLibraryModel::syncHasFiles() -{ - setHasFiles(checkHasFiles()); + bool hasContent = rowCount(rootIdx); + setIsEmpty(!hasContent); } void AssetsLibraryModel::setRootPath(const QString &newPath) diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h index 27b5eb77f27..5b5525a01bf 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h @@ -23,7 +23,7 @@ public: void setRootPath(const QString &newPath); void setSearchText(const QString &searchText); - Q_PROPERTY(bool hasFiles READ hasFiles NOTIFY hasFilesChanged) + Q_PROPERTY(bool isEmpty READ isEmpty NOTIFY isEmptyChanged) Q_INVOKABLE QString rootPath() const; Q_INVOKABLE QString filePath(const QModelIndex &index) const; @@ -36,7 +36,7 @@ public: Q_INVOKABLE QModelIndex parentDirIndex(const QString &path) const; Q_INVOKABLE QModelIndex parentDirIndex(const QModelIndex &index) const; Q_INVOKABLE QString parentDirPath(const QString &path) const; - Q_INVOKABLE void syncHasFiles(); + Q_INVOKABLE void syncIsEmpty(); Q_INVOKABLE QList parentIndices(const QModelIndex &index) const; Q_INVOKABLE bool indexIsValid(const QModelIndex &index) const; @@ -58,29 +58,27 @@ public: return std::min(result, 1); } - bool hasFiles() const { return m_hasFiles; } + bool isEmpty() const { return m_isEmpty; } signals: void directoryLoaded(const QString &path); void rootPathChanged(); - void hasFilesChanged(); + void isEmptyChanged(); void fileChanged(const QString &path); void effectsDeleted(const QStringList &effectNames); private: - void setHasFiles(bool value); + void setIsEmpty(bool value); bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; void resetModel(); void createBackendModel(); void destroyBackendModel(); - bool checkHasFiles(const QModelIndex &parentIdx) const; - bool checkHasFiles() const; QString m_searchText; QString m_rootPath; QFileSystemModel *m_sourceFsModel = nullptr; - bool m_hasFiles = false; + bool m_isEmpty = true; Utils::FileSystemWatcher *m_fileWatcher = nullptr; }; diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp index 1d5f68970d3..7d182b99c42 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp @@ -7,6 +7,7 @@ #include "assetslibrarymodel.h" #include "assetslibraryview.h" +#include #include #include #include @@ -102,7 +103,6 @@ AssetsLibraryWidget::AssetsLibraryWidget(AsynchronousImageCache &asynchronousFon , m_assetsIconProvider{new AssetsLibraryIconProvider(synchronousFontImageCache)} , m_assetsModel{new AssetsLibraryModel(this)} , m_assetsView{view} - , m_createTextures{view} , m_assetsWidget{Utils::makeUniqueObjectPtr(this)} { setWindowTitle(tr("Assets Library", "Title of assets library widget")); @@ -237,18 +237,20 @@ int AssetsLibraryWidget::qtVersion() const void AssetsLibraryWidget::addTextures(const QStringList &filePaths) { m_assetsView->executeInTransaction(__FUNCTION__, [&] { - m_createTextures.execute(filePaths, - AddTextureMode::Texture, - Utils3D::active3DSceneId(m_assetsView->model())); + CreateTexture(m_assetsView) + .execute(filePaths, + AddTextureMode::Texture, + Utils3D::active3DSceneId(m_assetsView->model())); }); } void AssetsLibraryWidget::addLightProbe(const QString &filePath) { m_assetsView->executeInTransaction(__FUNCTION__, [&] { - m_createTextures.execute({filePath}, - AddTextureMode::LightProbe, - Utils3D::active3DSceneId(m_assetsView->model())); + CreateTexture(m_assetsView) + .execute(filePath, + AddTextureMode::LightProbe, + Utils3D::active3DSceneId(m_assetsView->model())); }); } @@ -257,8 +259,9 @@ void AssetsLibraryWidget::updateContextMenuActionsEnableState() setHasMaterialLibrary(Utils3D::materialLibraryNode(m_assetsView).isValid() && m_assetsView->model()->hasImport("QtQuick3D")); - ModelNode activeSceneEnv = m_createTextures.resolveSceneEnv( - Utils3D::active3DSceneId(m_assetsView->model())); + ModelNode activeSceneEnv = Utils3D::resolveSceneEnv(m_assetsView, + Utils3D::active3DSceneId( + m_assetsView->model())); setHasSceneEnv(activeSceneEnv.isValid()); } @@ -394,11 +397,11 @@ void AssetsLibraryWidget::handleAssetsDrop(const QList &urls, const QStrin if (destDir.isFile()) destDir = destDir.parentDir(); - QMessageBox mb; - mb.setInformativeText("What would you like to do with the existing asset?"); - mb.addButton("Keep Both", QMessageBox::AcceptRole); - mb.addButton("Replace", QMessageBox::ResetRole); - mb.addButton("Cancel", QMessageBox::RejectRole); + QMessageBox msgBox; + msgBox.setInformativeText("What would you like to do with the existing asset?"); + msgBox.addButton("Keep Both", QMessageBox::AcceptRole); + msgBox.addButton("Replace", QMessageBox::ResetRole); + msgBox.addButton("Cancel", QMessageBox::RejectRole); for (const QUrl &url : urls) { Utils::FilePath src = Utils::FilePath::fromUrl(url); @@ -408,9 +411,9 @@ void AssetsLibraryWidget::handleAssetsDrop(const QList &urls, const QStrin continue; if (dest.exists()) { - mb.setText("An asset named " + dest.fileName() + " already exists."); - mb.exec(); - int userAction = mb.buttonRole(mb.clickedButton()); + msgBox.setText("An asset named " + dest.fileName() + " already exists."); + msgBox.exec(); + int userAction = msgBox.buttonRole(msgBox.clickedButton()); if (userAction == QMessageBox::AcceptRole) { // "Keep Both" dest = Utils::FilePath::fromString(UniqueName::generatePath(dest.toString())); @@ -424,8 +427,13 @@ void AssetsLibraryWidget::handleAssetsDrop(const QList &urls, const QStrin } } - if (!src.renameFile(dest)) - qWarning() << __FUNCTION__ << "Failed to move asset from" << src << "to" << dest; + if (!src.renameFile(dest) && src.isDir()) { + QMessageBox errBox; + QString message = QString("Failed to move folder \"%1\".\nThe folder might contain subfolders or one of its files is in use.") + .arg(src.fileName()); + errBox.setInformativeText(message); + errBox.exec(); + } } if (m_assetsView->model()) @@ -439,7 +447,7 @@ QList AssetsLibraryWidget::createToolBarWidgets() void AssetsLibraryWidget::handleSearchFilterChanged(const QString &filterText) { - if (filterText == m_filterText || (!m_assetsModel->hasFiles() + if (filterText == m_filterText || (m_assetsModel->isEmpty() && filterText.contains(m_filterText, Qt::CaseInsensitive))) return; diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h index 79deeb9efd3..5456fb139b4 100644 --- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h +++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h @@ -3,7 +3,6 @@ #pragma once -#include "createtexture.h" #include "previewtooltipbackend.h" #include @@ -135,7 +134,6 @@ private: AssetsLibraryIconProvider *m_assetsIconProvider = nullptr; AssetsLibraryModel *m_assetsModel = nullptr; AssetsLibraryView *m_assetsView = nullptr; - CreateTextures m_createTextures = nullptr; Utils::UniqueObjectPtr m_assetsWidget; std::unique_ptr m_fontPreviewTooltipBackend; diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp index 91660e90908..b7b454ffc55 100644 --- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditorwidget.cpp @@ -20,7 +20,6 @@ #include -#include #include #include diff --git a/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp b/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp index 5d097aaef3b..3d803111516 100644 --- a/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp +++ b/src/plugins/qmldesigner/components/componentcore/bundlehelper.cpp @@ -77,6 +77,7 @@ void BundleHelper::createImporter() newNode.simplifiedTypeName(), "node")); m_view->clearSelectedModelNodes(); m_view->selectModelNode(newNode); + m_view->resetPuppet(); }); } }); @@ -104,6 +105,7 @@ void BundleHelper::createImporter() newNode.simplifiedTypeName(), "node")); m_view->clearSelectedModelNodes(); m_view->selectModelNode(newNode); + m_view->resetPuppet(); }); } }); @@ -135,8 +137,16 @@ void BundleHelper::importBundleToProject() " of Qt Design Studio")); return; } + QString bundleId = importedJsonObj.value("id").toString(); + bool hasQuick3DImport = m_view->model()->hasImport("QtQuick3D"); + + if (!hasQuick3DImport) { + Import import = Import::createLibraryImport("QtQuick3D"); + m_view->model()->changeImports({import}, {}); + } + QTemporaryDir tempDir; QTC_ASSERT(tempDir.isValid(), return); auto bundlePath = Utils::FilePath::fromString(tempDir.path()); diff --git a/src/plugins/qmldesigner/components/componentcore/createtexture.cpp b/src/plugins/qmldesigner/components/componentcore/createtexture.cpp index f595e0e47e7..cd8ea6cfd78 100644 --- a/src/plugins/qmldesigner/components/componentcore/createtexture.cpp +++ b/src/plugins/qmldesigner/components/componentcore/createtexture.cpp @@ -114,10 +114,10 @@ ModelNode CreateTexture::execute(const QString &filePath, AddTextureMode mode, i return {}; if (mode == AddTextureMode::LightProbe && sceneId != -1) - assignTextureAsLightProbe(texture, sceneId); + Utils3D::assignTextureAsLightProbe(m_view, texture, sceneId); - QTimer::singleShot(0, m_view, [this, texture]() { - if (m_view->model() && texture.isValid()) { + QTimer::singleShot(0, m_view, [view = m_view, texture]() { + if (view && view->model() && texture.isValid()) { QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialBrowser"); Utils3D::selectTexture(texture); } @@ -210,6 +210,12 @@ ModelNode CreateTexture::execute(const ModelNode &texture) return duplicateTextureNode; } +void CreateTexture::execute(const QStringList &filePaths, AddTextureMode mode, int sceneId) +{ + for (const QString &path : filePaths) + execute(path, mode, sceneId); +} + bool CreateTexture::addFileToProject(const QString &filePath) { AddFilesResult result = ModelNodeOperations::addImageToProject( @@ -260,48 +266,4 @@ ModelNode CreateTexture::createTextureFromImage(const Utils::FilePath &assetPat return newTexNode; } -void CreateTexture::assignTextureAsLightProbe(const ModelNode &texture, int sceneId) -{ - ModelNode sceneEnvNode = resolveSceneEnv(sceneId); - QmlObjectNode sceneEnv = sceneEnvNode; - if (sceneEnv.isValid()) { - sceneEnv.setBindingProperty("lightProbe", texture.id()); - sceneEnv.setVariantProperty("backgroundMode", - QVariant::fromValue(Enumeration("SceneEnvironment", - "SkyBox"))); - } -} - -ModelNode CreateTexture::resolveSceneEnv(int sceneId) -{ - ModelNode activeSceneEnv; - ModelNode selectedNode = m_view->firstSelectedModelNode(); - - if (selectedNode.metaInfo().isQtQuick3DSceneEnvironment()) { - activeSceneEnv = selectedNode; - } else if (sceneId != -1) { - ModelNode activeScene = Utils3D::active3DSceneNode(m_view); - if (activeScene.isValid()) { - QmlObjectNode view3D; - if (activeScene.metaInfo().isQtQuick3DView3D()) { - view3D = activeScene; - } else { - ModelNode sceneParent = activeScene.parentProperty().parentModelNode(); - if (sceneParent.metaInfo().isQtQuick3DView3D()) - view3D = sceneParent; - } - if (view3D.isValid()) - activeSceneEnv = m_view->modelNodeForId(view3D.expression("environment")); - } - } - - return activeSceneEnv; -} - -void CreateTextures::execute(const QStringList &filePaths, AddTextureMode mode, int sceneId) -{ - for (const QString &path : filePaths) - CreateTexture::execute(path, mode, sceneId); -} - } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/createtexture.h b/src/plugins/qmldesigner/components/componentcore/createtexture.h index 450a7f7a0db..57ef9893cc0 100644 --- a/src/plugins/qmldesigner/components/componentcore/createtexture.h +++ b/src/plugins/qmldesigner/components/componentcore/createtexture.h @@ -3,7 +3,7 @@ #pragma once -#include +#include namespace Utils { class FilePath; @@ -16,10 +16,8 @@ class ModelNode; enum class AddTextureMode { Image, Texture, LightProbe }; -class CreateTexture : public QObject +class CreateTexture { - Q_OBJECT - public: CreateTexture(AbstractView *view); @@ -28,8 +26,7 @@ public: AddTextureMode mode = AddTextureMode::Texture, int sceneId = -1); ModelNode execute(const ModelNode &texture); - ModelNode resolveSceneEnv(int sceneId); - void assignTextureAsLightProbe(const ModelNode &texture, int sceneId); + void execute(const QStringList &filePaths, AddTextureMode mode, int sceneId = -1); private: bool addFileToProject(const QString &filePath); @@ -38,11 +35,4 @@ private: AbstractView *m_view = nullptr; }; -class CreateTextures : public CreateTexture -{ -public: - using CreateTexture::CreateTexture; - void execute(const QStringList &filePaths, AddTextureMode mode, int sceneId = -1); -}; - } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/componentcore/designericons.h b/src/plugins/qmldesigner/components/componentcore/designericons.h index 1bce6581bdb..98edfac0b59 100644 --- a/src/plugins/qmldesigner/components/componentcore/designericons.h +++ b/src/plugins/qmldesigner/components/componentcore/designericons.h @@ -80,6 +80,7 @@ public: LightDirectionalIcon, LightPointIcon, LightSpotIcon, + LiveUpdateIcon, LocalOrientIcon, MakeComponentIcon, MaterialIcon, @@ -107,6 +108,7 @@ public: SnappingIcon, SnappingConfIcon, SplitViewIcon, + SyncIcon, TimelineIcon, ToggleGroupIcon, VisibilityIcon diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp index db23abc4697..950575888e6 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp @@ -6,6 +6,7 @@ #include "addimagesdialog.h" #include "addsignalhandlerdialog.h" #include "componentcore_constants.h" +#include "createtexture.h" #include "findimplementation.h" #include "layoutingridlayout.h" #include "modelnodecontextmenu_helper.h" @@ -87,11 +88,14 @@ Utils::SmallString auxPropertyString(Utils::SmallStringView name) { return auxDataString + name; } -} // namespace -inline static void reparentTo(const ModelNode &node, const QmlItemNode &parent) +QString relativePathToQmlFile(const QString &absolutePath) { + return DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath(absolutePath); +} +inline void reparentTo(const ModelNode &node, const QmlItemNode &parent) +{ if (parent.isValid() && node.isValid()) { NodeAbstractProperty parentProperty; @@ -104,7 +108,7 @@ inline static void reparentTo(const ModelNode &node, const QmlItemNode &parent) } } -inline static QPointF getUpperLeftPosition(const QList &modelNodeList) +inline QPointF getUpperLeftPosition(const QList &modelNodeList) { QPointF postion(std::numeric_limits::max(), std::numeric_limits::max()); for (const ModelNode &modelNode : modelNodeList) { @@ -120,13 +124,15 @@ inline static QPointF getUpperLeftPosition(const QList &modelNodeList return postion; } -static void setUpperLeftPostionToNode(const ModelNode &layoutNode, const QList &modelNodeList) +void setUpperLeftPostionToNode(const ModelNode &layoutNode, const QList &modelNodeList) { QPointF upperLeftPosition = getUpperLeftPosition(modelNodeList); layoutNode.variantProperty("x").setValue(qRound(upperLeftPosition.x())); layoutNode.variantProperty("y") .setValue(qRound(upperLeftPosition.y())); } +} // namespace + namespace ModelNodeOperations { bool goIntoComponent(const ModelNode &modelNode) @@ -1753,13 +1759,10 @@ void editInEffectComposer(const SelectionContext &selectionContext) bool isEffectComposerActivated() { - const ExtensionSystem::PluginSpecs specs = ExtensionSystem::PluginManager::plugins(); - return std::ranges::find_if(specs, - [](ExtensionSystem::PluginSpec *spec) { - return spec->name() == "EffectComposer" - && spec->isEffectivelyEnabled(); - }) - != specs.end(); + using namespace ExtensionSystem; + return Utils::anyOf(PluginManager::plugins(), [](PluginSpec *spec) { + return spec->name() == "EffectComposer" && spec->isEffectivelyEnabled(); + }); } void openEffectComposer(const QString &filePath) @@ -1905,41 +1908,15 @@ static bool moveNodeToParent(const NodeAbstractProperty &targetProperty, const M return false; } -ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath) +ModelNode createTextureNode(AbstractView *view, const QString &imagePath) { - AbstractView *view = targetProp.view(); QTC_ASSERT(view, return {}); - if (targetProp.isValid()) { - // create a texture item lib - ItemLibraryEntry itemLibraryEntry; - itemLibraryEntry.setName("Texture"); - itemLibraryEntry.setType("QtQuick3D.Texture", 1, 0); - - // set texture source - PropertyName prop = "source"; - QString type = "QUrl"; - QVariant val = imagePath; - itemLibraryEntry.addProperty(prop, type, val); - - // create a texture - ModelNode newModelNode = QmlItemNode::createQmlObjectNode(view, - itemLibraryEntry, - {}, - targetProp, - false); - - // Rename the node based on source image - QFileInfo fi(imagePath); - newModelNode.setIdWithoutRefactoring( - view->model()->generateNewId(fi.baseName(), "textureImage")); - return newModelNode; - } - return {}; + CreateTexture textureCreator(view); + return textureCreator.execute(imagePath, AddTextureMode::Texture); } bool dropAsImage3dTexture(const ModelNode &targetNode, - const NodeAbstractProperty &targetProp, const QString &imagePath, ModelNode &newNode, bool &outMoveNodesAfter) @@ -1949,16 +1926,11 @@ bool dropAsImage3dTexture(const ModelNode &targetNode, auto bindToProperty = [&](const PropertyName &propName) { view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] { - newNode = createTextureNode(targetProp, imagePath); + newNode = createTextureNode(view, imagePath); if (newNode.isValid()) { BindingProperty bindProp = targetNode.bindingProperty(propName); bindProp.setExpression(newNode.validId()); - ModelNode matLib = Utils3D::materialLibraryNode(view); - if (matLib.isValid()) { - NodeAbstractProperty matLibProp = matLib.defaultNodeAbstractProperty(); - matLibProp.reparentHere(newNode); - outMoveNodesAfter = false; - } + outMoveNodesAfter = false; } }); }; @@ -1979,7 +1951,7 @@ bool dropAsImage3dTexture(const ModelNode &targetNode, if (dialog->result() == QDialog::Accepted) { view->executeInTransaction("NavigatorTreeModel::dropAsImage3dTexture", [&] { - newNode = createTextureNode(targetProp, imagePath); + newNode = createTextureNode(view, imagePath); if (newNode.isValid()) // Automatically set the texture to selected property targetNode.bindingProperty(dialog->selectedProperty()) .setExpression(newNode.validId()); @@ -1999,10 +1971,11 @@ bool dropAsImage3dTexture(const ModelNode &targetNode, return newNode.isValid(); } else if (targetNode.metaInfo().isQtQuick3DTexture()) { // if dropping an image on an existing texture, set the source - targetNode.variantProperty("source").setValue(imagePath); + targetNode.variantProperty("source").setValue(relativePathToQmlFile(imagePath)); return true; } else if (targetNode.metaInfo().isQtQuick3DModel()) { - QTimer::singleShot(0, view, [targetNode, imagePath, view]() { + const QString relImagePath = relativePathToQmlFile(imagePath); + QTimer::singleShot(0, view, [targetNode, relImagePath, view]() { if (view && targetNode.isValid()) { // To MaterialBrowserView. Done async to avoid custom notification in transaction QmlDesignerPlugin::instance()->mainWidget()->showDockWidget("MaterialBrowser"); @@ -2010,7 +1983,7 @@ bool dropAsImage3dTexture(const ModelNode &targetNode, {targetNode}, {DocumentManager::currentFilePath() .absolutePath() - .pathAppended(imagePath) + .pathAppended(relImagePath) .cleanPath() .toString()}); } @@ -2102,20 +2075,12 @@ ModelNode handleItemLibraryImageDrop(const QString &imagePath, AbstractView *view = targetNode.view(); QTC_ASSERT(view, return {}); - const QString imagePathRelative - = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath( - imagePath); // relative to .ui.qml file - ModelNode newModelNode; - if (!dropAsImage3dTexture(targetNode, - targetProperty, - imagePathRelative, - newModelNode, - outMoveNodesAfter)) { + if (!dropAsImage3dTexture(targetNode, imagePath, newModelNode, outMoveNodesAfter)) { if (targetNode.metaInfo().isQtQuickImage() || targetNode.metaInfo().isQtQuickBorderImage()) { // if dropping an image on an existing image, set the source - targetNode.variantProperty("source").setValue(imagePathRelative); + targetNode.variantProperty("source").setValue(relativePathToQmlFile(imagePath)); } else { // create an image QmlItemNode newItemNode = QmlItemNode::createQmlItemNodeFromImage(view, @@ -2176,8 +2141,7 @@ ModelNode handleItemLibraryShaderDrop(const QString &shaderPath, ModelNode newModelNode; - const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath( - shaderPath); + const QString relPath = relativePathToQmlFile(shaderPath); if (targetNode.metaInfo().isQtQuick3DShader()) { // if dropping into an existing Shader, update @@ -2233,8 +2197,7 @@ ModelNode handleItemLibrarySoundDrop(const QString &soundPath, ModelNode newModelNode; - const QString relPath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath( - soundPath); + const QString relPath = relativePathToQmlFile(soundPath); if (targetNode.metaInfo().isQtMultimediaSoundEffect()) { // if dropping into on an existing SoundEffect, update @@ -2268,7 +2231,6 @@ ModelNode handleItemLibrarySoundDrop(const QString &soundPath, } ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath, - NodeAbstractProperty targetProperty, const ModelNode &targetNode, bool &outMoveNodesAfter) { @@ -2279,24 +2241,9 @@ ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath, if (!view->model()->hasImport(import, true, true)) return {}; - const QString imagePath = DocumentManager::currentFilePath().toFileInfo().dir().relativeFilePath( - tex3DPath); // relative to qml file - ModelNode newModelNode; - if (!dropAsImage3dTexture(targetNode, - targetProperty, - imagePath, - newModelNode, - outMoveNodesAfter)) { - view->executeInTransaction("NavigatorTreeModel::handleItemLibraryTexture3dDrop", [&] { - // create a standalone Texture3D at drop location - newModelNode = createTextureNode(targetProperty, imagePath); - if (!NodeHints::fromModelNode(targetProperty.parentModelNode()) - .canBeContainerFor(newModelNode)) - newModelNode.destroy(); - }); - } + dropAsImage3dTexture(targetNode, tex3DPath, newModelNode, outMoveNodesAfter); return newModelNode; } diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h index 7538452848f..116ea90d1c7 100644 --- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h +++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h @@ -137,7 +137,7 @@ bool useLayerEffect(); bool validateEffect(const QString &effectPath); bool isEffectComposerActivated(); -Utils::FilePath getImagesDefaultDirectory(); +QMLDESIGNERCOMPONENTS_EXPORT Utils::FilePath getImagesDefaultDirectory(); //Item Library and Assets related drop operations QMLDESIGNERCOMPONENTS_EXPORT ModelNode handleItemLibraryEffectDrop(const QString &effectPath, @@ -160,7 +160,6 @@ ModelNode handleItemLibrarySoundDrop(const QString &soundPath, NodeAbstractProperty targetProperty, const ModelNode &targetNode); ModelNode handleItemLibraryTexture3dDrop(const QString &tex3DPath, - NodeAbstractProperty targetProperty, const ModelNode &targetNode, bool &outMoveNodesAfter); diff --git a/src/plugins/qmldesigner/components/componentcore/utils3d.cpp b/src/plugins/qmldesigner/components/componentcore/utils3d.cpp index 7ddd0997cdf..e38fd544084 100644 --- a/src/plugins/qmldesigner/components/componentcore/utils3d.cpp +++ b/src/plugins/qmldesigner/components/componentcore/utils3d.cpp @@ -252,6 +252,43 @@ void applyMaterialToModels(AbstractView *view, const ModelNode &material, }); } +ModelNode resolveSceneEnv(AbstractView *view, int sceneId) +{ + ModelNode activeSceneEnv; + ModelNode selectedNode = view->firstSelectedModelNode(); + + if (selectedNode.metaInfo().isQtQuick3DSceneEnvironment()) { + activeSceneEnv = selectedNode; + } else if (sceneId != -1) { + ModelNode activeScene = Utils3D::active3DSceneNode(view); + if (activeScene.isValid()) { + QmlObjectNode view3D; + if (activeScene.metaInfo().isQtQuick3DView3D()) { + view3D = activeScene; + } else { + ModelNode sceneParent = activeScene.parentProperty().parentModelNode(); + if (sceneParent.metaInfo().isQtQuick3DView3D()) + view3D = sceneParent; + } + if (view3D.isValid()) + activeSceneEnv = view->modelNodeForId(view3D.expression("environment")); + } + } + + return activeSceneEnv; +} + +void assignTextureAsLightProbe(AbstractView *view, const ModelNode &texture, int sceneId) +{ + ModelNode sceneEnvNode = resolveSceneEnv(view, sceneId); + QmlObjectNode sceneEnv = sceneEnvNode; + if (sceneEnv.isValid()) { + sceneEnv.setBindingProperty("lightProbe", texture.id()); + sceneEnv.setVariantProperty("backgroundMode", + QVariant::fromValue(Enumeration("SceneEnvironment", "SkyBox"))); + } +} + // This method should be executed within a transaction as it performs multiple modifications to the model #ifdef QDS_USE_PROJECTSTORAGE ModelNode createMaterial(AbstractView *view, const TypeName &typeName) diff --git a/src/plugins/qmldesigner/components/componentcore/utils3d.h b/src/plugins/qmldesigner/components/componentcore/utils3d.h index 546c90f8e70..6a7899589c3 100644 --- a/src/plugins/qmldesigner/components/componentcore/utils3d.h +++ b/src/plugins/qmldesigner/components/componentcore/utils3d.h @@ -40,10 +40,14 @@ void selectTexture(const ModelNode &texture); ModelNode selectedMaterial(AbstractView *view); ModelNode selectedTexture(AbstractView *view); +ModelNode resolveSceneEnv(AbstractView *view, int sceneId); + QList getSelectedModels(AbstractView *view); void applyMaterialToModels(AbstractView *view, const ModelNode &material, const QList &models, bool add = false); +void assignTextureAsLightProbe(AbstractView *view, const ModelNode &texture, int sceneId); + #ifdef QDS_USE_PROJECTSTORAGE ModelNode createMaterial(AbstractView *view, const TypeName &typeName); #else diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp index 5151d89534e..e1f74075c2c 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp @@ -57,7 +57,6 @@ ContentLibraryView::ContentLibraryView(AsynchronousImageCache &imageCache, ExternalDependenciesInterface &externalDependencies) : AbstractView(externalDependencies) , m_imageCache(imageCache) - , m_createTexture(this) {} ContentLibraryView::~ContentLibraryView() @@ -88,15 +87,17 @@ WidgetInfo ContentLibraryView::widgetInfo() m_draggedBundleItem = item; }); - connect(m_widget, &ContentLibraryWidget::addTextureRequested, this, - [&] (const QString &texPath, AddTextureMode mode) { - executeInTransaction("ContentLibraryView::widgetInfo", [&]() { - m_createTexture.execute(texPath, mode, m_sceneId); - }); - }); + connect(m_widget, + &ContentLibraryWidget::addTextureRequested, + this, + [&](const QString &texPath, AddTextureMode mode) { + executeInTransaction("ContentLibraryView::widgetInfo", [&]() { + CreateTexture(this).execute(texPath, mode, m_sceneId); + }); + }); connect(m_widget, &ContentLibraryWidget::updateSceneEnvStateRequested, this, [this] { - ModelNode activeSceneEnv = m_createTexture.resolveSceneEnv(m_sceneId); + ModelNode activeSceneEnv = Utils3D::resolveSceneEnv(this, m_sceneId); const bool sceneEnvExists = activeSceneEnv.isValid(); m_widget->texturesModel()->setHasSceneEnv(sceneEnvExists); m_widget->environmentsModel()->setHasSceneEnv(sceneEnvExists); diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h index deba7b93a61..f42423fd7d2 100644 --- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h +++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h @@ -90,7 +90,6 @@ private: bool m_bundleMaterialAddToSelected = false; bool m_hasQuick3DImport = false; qint32 m_sceneId = -1; - CreateTexture m_createTexture; Utils::FilePath m_iconSavePath; QString m_generatedFolderName; QString m_bundleId; diff --git a/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp b/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp index 167282ea90f..516e7a3c609 100644 --- a/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp +++ b/src/plugins/qmldesigner/components/formeditor/movemanipulator.cpp @@ -101,8 +101,9 @@ bool MoveManipulator::itemsCanReparented() const void MoveManipulator::setDirectUpdateInNodeInstances(bool directUpdate) { - for (FormEditorItem* item : std::as_const(m_itemList)) { - if (item && item->qmlItemNode().isValid()) + const auto allFormEditorItems = m_view->scene()->allFormEditorItems(); + for (FormEditorItem *item : std::as_const(m_itemList)) { + if (item && allFormEditorItems.contains(item) && item->qmlItemNode().isValid()) item->qmlItemNode().nodeInstance().setDirectUpdate(directUpdate); } } diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp index 1d9bbf5cd34..0997d06853e 100644 --- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp +++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp @@ -376,10 +376,11 @@ void ItemLibraryModel::update(Model *model) for (const ItemLibraryEntry &entry : itemLibEntries) { NodeMetaInfo metaInfo; - if constexpr (useProjectStorage()) - metaInfo = NodeMetaInfo{entry.typeId(), model->projectStorage()}; - else - metaInfo = model->metaInfo(entry.typeName()); +#ifdef QDS_USE_PROJECTSTORAGE + metaInfo = NodeMetaInfo{entry.typeId(), model->projectStorage()}; +#else + metaInfo = model->metaInfo(entry.typeName()); +#endif #ifdef QDS_USE_PROJECTSTORAGE bool valid = metaInfo.isValid(); diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp index 1d689e88a64..a6344fbb552 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp @@ -209,7 +209,7 @@ WidgetInfo MaterialBrowserView::widgetInfo() }); connect(texturesModel, &MaterialBrowserTexturesModel::updateSceneEnvStateRequested, this, [this] { - ModelNode activeSceneEnv = CreateTexture(this).resolveSceneEnv(m_sceneId); + ModelNode activeSceneEnv = Utils3D::resolveSceneEnv(this, m_sceneId); const bool sceneEnvExists = activeSceneEnv.isValid(); m_widget->materialBrowserTexturesModel()->setHasSceneEnv(sceneEnvExists); }); @@ -222,12 +222,14 @@ WidgetInfo MaterialBrowserView::widgetInfo() m_widget->materialBrowserTexturesModel()->setHasSingleModelSelection(hasModel); }); - connect(texturesModel, &MaterialBrowserTexturesModel::applyAsLightProbeRequested, this, - [&] (const ModelNode &texture) { - executeInTransaction(__FUNCTION__, [&] { - CreateTexture(this).assignTextureAsLightProbe(texture, m_sceneId); - }); - }); + connect(texturesModel, + &MaterialBrowserTexturesModel::applyAsLightProbeRequested, + this, + [&](const ModelNode &texture) { + executeInTransaction(__FUNCTION__, [&] { + Utils3D::assignTextureAsLightProbe(this, texture, m_sceneId); + }); + }); } return createWidgetInfo(m_widget.data(), @@ -239,13 +241,9 @@ WidgetInfo MaterialBrowserView::widgetInfo() void MaterialBrowserView::createTextures(const QStringList &assetPaths) { - auto *create = new CreateTextures(this); - executeInTransaction("MaterialBrowserView::createTextures", [&]() { - create->execute(assetPaths, AddTextureMode::Texture, m_sceneId); + CreateTexture(this).execute(assetPaths, AddTextureMode::Texture, m_sceneId); }); - - create->deleteLater(); } void MaterialBrowserView::modelAttached(Model *model) @@ -740,11 +738,10 @@ void MaterialBrowserView::applyTextureToProperty(const QString &matId, const QSt { executeInTransaction(__FUNCTION__, [&] { if (m_appliedTextureId.isEmpty() && !m_appliedTexturePath.isEmpty()) { - auto texCreator = new CreateTexture(this); - ModelNode tex = texCreator->execute(m_appliedTexturePath, AddTextureMode::Texture); + CreateTexture texCreator(this); + ModelNode tex = texCreator.execute(m_appliedTexturePath, AddTextureMode::Texture); m_appliedTextureId = tex.id(); m_appliedTexturePath.clear(); - texCreator->deleteLater(); } QTC_ASSERT(!m_appliedTextureId.isEmpty(), return); diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp index 7573c7c4288..40e7652e66a 100644 --- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp +++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserwidget.cpp @@ -307,10 +307,8 @@ void MaterialBrowserWidget::acceptBundleTextureDropOnMaterial(int matIndex, cons ModelNode mat = m_materialBrowserModel->materialAt(matIndex); QTC_ASSERT(mat.isValid(), return); - auto *creator = new CreateTexture(m_materialBrowserView); - m_materialBrowserView->executeInTransaction(__FUNCTION__, [&] { - ModelNode tex = creator->execute(bundleTexPath.toLocalFile()); + ModelNode tex = CreateTexture(m_materialBrowserView).execute(bundleTexPath.toLocalFile()); QTC_ASSERT(tex.isValid(), return); m_materialBrowserModel->selectMaterial(matIndex); @@ -319,8 +317,6 @@ void MaterialBrowserWidget::acceptBundleTextureDropOnMaterial(int matIndex, cons if (m_materialBrowserView->model()) m_materialBrowserView->model()->endDrag(); - - creator->deleteLater(); } void MaterialBrowserWidget::acceptAssetsDrop(const QList &urls) @@ -336,14 +332,12 @@ void MaterialBrowserWidget::acceptAssetsDropOnMaterial(int matIndex, const QList ModelNode mat = m_materialBrowserModel->materialAt(matIndex); QTC_ASSERT(mat.isValid(), return); - auto *creator = new CreateTexture(m_materialBrowserView); - - QString imageSrc = Utils::findOrDefault(urls, [] (const QUrl &url) { - return Asset(url.toLocalFile()).isValidTextureSource(); - }).toLocalFile(); + QString imageSrc = Utils::findOrDefault(urls, [](const QUrl &url) { + return Asset(url.toLocalFile()).isValidTextureSource(); + }).toLocalFile(); m_materialBrowserView->executeInTransaction(__FUNCTION__, [&] { - ModelNode tex = creator->execute(imageSrc); + ModelNode tex = CreateTexture(m_materialBrowserView).execute(imageSrc); QTC_ASSERT(tex.isValid(), return); m_materialBrowserModel->selectMaterial(matIndex); @@ -352,8 +346,6 @@ void MaterialBrowserWidget::acceptAssetsDropOnMaterial(int matIndex, const QList if (m_materialBrowserView->model()) m_materialBrowserView->model()->endDrag(); - - creator->deleteLater(); } void MaterialBrowserWidget::acceptTextureDropOnMaterial(int matIndex, const QString &texId) diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp index 341f3694857..2c6a02002d4 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp @@ -177,8 +177,8 @@ static void reparentModelNodeToNodeProperty(NodeAbstractProperty &parentProperty } } -NavigatorTreeModel::NavigatorTreeModel(QObject *parent) : QAbstractItemModel(parent) - , m_createTextures(Utils::makeUniqueObjectPtr(m_view)) +NavigatorTreeModel::NavigatorTreeModel(QObject *parent) + : QAbstractItemModel(parent) { m_actionManager = &QmlDesignerPlugin::instance()->viewManager().designerActionManager(); } @@ -324,7 +324,10 @@ QList NavigatorTreeModel::filteredList(const NodeListProperty &proper if (filter) { list.append(::Utils::filtered(nameFilteredList, [](const ModelNode &arg) { - const bool value = (QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator()) + const bool visibleInNavigator = NodeHints::fromModelNode(arg).visibleInNavigator(); + const bool hideInNavigator = NodeHints::fromModelNode(arg).hideInNavigator(); + const bool value = ((QmlItemNode::isValidQmlItemNode(arg) && !hideInNavigator) + || visibleInNavigator) && arg.id() != Constants::MATERIAL_LIB_ID; return value; })); @@ -583,17 +586,10 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, bool moveNodesAfter = false; m_view->executeInTransaction(__FUNCTION__, [&] { - m_createTextures->execute(QStringList{texturePath}, - AddTextureMode::Image, - Utils3D::active3DSceneId(m_view->model())); - QString textureName = Utils::FilePath::fromString(texturePath).fileName(); - QString textureAbsolutePath = DocumentManager::currentResourcePath() - .pathAppended("images/" + textureName).toString(); - ModelNodeOperations::handleItemLibraryImageDrop(textureAbsolutePath, - targetProperty, - modelNodeForIndex( - rowModelIndex), - moveNodesAfter); + ModelNodeOperations::handleItemLibraryTexture3dDrop(texturePath, + modelNodeForIndex( + rowModelIndex), + moveNodesAfter); }); } } @@ -664,7 +660,6 @@ bool NavigatorTreeModel::dropMimeData(const QMimeData *mimeData, } else if (assetType == Constants::MIME_TYPE_ASSET_TEXTURE3D) { currNode = ModelNodeOperations::handleItemLibraryTexture3dDrop( assetPath, - targetProperty, modelNodeForIndex(rowModelIndex), moveNodesAfter); } else if (assetType == Constants::MIME_TYPE_ASSET_EFFECT) { @@ -853,34 +848,6 @@ bool QmlDesigner::NavigatorTreeModel::moveNodeToParent(const NodeAbstractPropert return false; } -ModelNode NavigatorTreeModel::createTextureNode(const NodeAbstractProperty &targetProp, - const QString &imagePath) -{ - if (targetProp.isValid()) { - // create a texture item lib - ItemLibraryEntry itemLibraryEntry; - itemLibraryEntry.setName("Texture"); - itemLibraryEntry.setType("QtQuick3D.Texture", 1, 0); - - // set texture source - PropertyName prop = "source"; - QString type = "QUrl"; - QVariant val = imagePath; - itemLibraryEntry.addProperty(prop, type, val); - - // create a texture - ModelNode newModelNode = QmlItemNode::createQmlObjectNode(m_view, itemLibraryEntry, {}, - targetProp, false); - - // Rename the node based on source image - QFileInfo fi(imagePath); - newModelNode.setIdWithoutRefactoring( - m_view->model()->generateNewId(fi.baseName(), "textureImage")); - return newModelNode; - } - return {}; -} - namespace { NodeMetaInfo propertyType(const NodeAbstractProperty &property) { diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h index 7e6df8b2ec1..350b72dd608 100644 --- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h +++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.h @@ -17,7 +17,6 @@ QT_FORWARD_DECLARE_CLASS(QPixmap) namespace QmlDesigner { -class CreateTextures; class DesignerActionManager; class Model; class ModelNode; @@ -88,7 +87,7 @@ public: void updateToolTipPixmap(const ModelNode &node, const QPixmap &pixmap); signals: - void toolTipPixmapUpdated(const QString &id, const QPixmap &pixmap) const; + void toolTipPixmapUpdated(const QString &id, const QPixmap &pixmap); private: void moveNodesInteractive(NodeAbstractProperty &parentProperty, const QList &modelNodes, @@ -96,16 +95,17 @@ private: void handleInternalDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); void handleItemLibraryItemDrop(const QMimeData *mimeData, int rowNumber, const QModelIndex &dropModelIndex); - bool dropAsImage3dTexture(const ModelNode &targetNode, const NodeAbstractProperty &targetProp, - const QString &imagePath, ModelNode &newNode, bool &outMoveNodesAfter); - ModelNode createTextureNode(const NodeAbstractProperty &targetProp, const QString &imagePath); + bool dropAsImage3dTexture(const ModelNode &targetNode, + const NodeAbstractProperty &targetProp, + const QString &imagePath, + ModelNode &newNode, + bool &outMoveNodesAfter); QList nodesToPersistentIndex(const QList &modelNodes); void addImport(const QString &importName); QList filteredList(const NodeListProperty &property, bool filter, bool reverseOrder) const; bool moveNodeToParent(const NodeAbstractProperty &targetProperty, const ModelNode &newModelNode); QPointer m_view; - Utils::UniqueObjectPtr m_createTextures; mutable QHash m_nodeIndexHash; mutable QHash > m_rowCache; bool m_showOnlyVisibleItems = true; diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp index 77b98786e01..b4e7f9a6eac 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp @@ -521,9 +521,8 @@ void PropertyEditorValue::commitDrop(const QString &dropData) m_modelNode.view()->executeInTransaction(__FUNCTION__, [&] { ModelNode texture = m_modelNode.view()->modelNodeForInternalId(dropData.toInt()); if (!texture || !texture.metaInfo().isQtQuick3DTexture()) { - auto texCreator = new CreateTexture(m_modelNode.view()); - texture = texCreator->execute(dropData, AddTextureMode::Texture); - texCreator->deleteLater(); + CreateTexture texCreator(m_modelNode.view()); + texture = texCreator.execute(dropData, AddTextureMode::Texture); } // assign the texture to the property @@ -531,7 +530,12 @@ void PropertyEditorValue::commitDrop(const QString &dropData) }); } - m_modelNode.view()->model()->endDrag(); + emit dropCommitted(dropData); + + if (!m_modelNode.model()) + return; + + m_modelNode.model()->endDrag(); } void PropertyEditorValue::openMaterialEditor(int idx) diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h index 997640d377e..d8cee333cbb 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.h @@ -200,6 +200,7 @@ signals: void isValidChanged(); void isExplicitChanged(); void hasActiveDragChanged(); + void dropCommitted(QString dropData); private: QStringList generateStringList(const QString &string) const; diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp index 6a4d2eb5a6c..642e16055d5 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp +++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp @@ -339,7 +339,6 @@ void TextEditorWidget::dropEvent(QDropEvent *dropEvent) targetNode); } else if (assetType == Constants::MIME_TYPE_ASSET_TEXTURE3D) { newModelNode = ModelNodeOperations::handleItemLibraryTexture3dDrop(assetPath, - targetProperty, targetNode, moveNodesAfter); } else if (assetType == Constants::MIME_TYPE_ASSET_EFFECT) { diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp index 2c73685c196..9d10644e89f 100644 --- a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp +++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp @@ -58,7 +58,6 @@ TextureEditorView::TextureEditorView(AsynchronousImageCache &imageCache, : AbstractView{externalDependencies} , m_imageCache(imageCache) , m_stackedWidget(new QStackedWidget) - , m_createTexture(new CreateTexture(this)) , m_dynamicPropertiesModel(new DynamicPropertiesModel(true, this)) { m_updateShortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_F12), m_stackedWidget); @@ -399,7 +398,7 @@ void TextureEditorView::handleToolBarAction(int action) case TextureEditorContextObject::AddNewTexture: { if (!model()) break; - m_createTexture->execute(); + CreateTexture(this).execute(); break; } @@ -845,7 +844,7 @@ void TextureEditorView::importsChanged([[maybe_unused]] const Imports &addedImpo void TextureEditorView::duplicateTexture(const ModelNode &texture) { QTC_ASSERT(texture.isValid(), return); - m_createTexture->execute(texture); + CreateTexture(this).execute(texture); } void TextureEditorView::customNotification([[maybe_unused]] const AbstractView *view, diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h index 5611cf3ab6b..00336998b6c 100644 --- a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h +++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h @@ -18,7 +18,6 @@ QT_END_NAMESPACE namespace QmlDesigner { -class CreateTexture; class DynamicPropertiesModel; class ModelNode; class QmlObjectNode; @@ -126,7 +125,6 @@ private: bool m_selectedTextureChanged = false; QPointer m_colorDialog; - QPointer m_createTexture; DynamicPropertiesModel *m_dynamicPropertiesModel = nullptr; }; diff --git a/src/plugins/qmldesigner/libs/CMakeLists.txt b/src/plugins/qmldesigner/libs/CMakeLists.txt index 7cac0a93a3d..be2d12733cb 100644 --- a/src/plugins/qmldesigner/libs/CMakeLists.txt +++ b/src/plugins/qmldesigner/libs/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(designercore) add_subdirectory(qmldesignerutils) +add_subdirectory(designsystem) diff --git a/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt b/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt index 977bced8f23..1ebb8c48322 100644 --- a/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt +++ b/src/plugins/qmldesigner/libs/designercore/CMakeLists.txt @@ -375,6 +375,11 @@ extend_qtc_library(QmlDesignerCore DEFINES QML_DOM_MSVC2019_COMPAT ) +extend_qtc_library(QmlDesignerCore + CONDITION WITH_TESTS + PUBLIC_DEFINES QDS_MODEL_USE_PROJECTSTORAGEINTERFACE +) + extend_qtc_library(QmlDesignerCore SOURCES_PREFIX projectstorage PUBLIC_INCLUDES projectstorage diff --git a/src/plugins/qmldesigner/libs/designercore/include/model.h b/src/plugins/qmldesigner/libs/designercore/include/model.h index 48ec5c7c4c0..d671c8edbba 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/model.h +++ b/src/plugins/qmldesigner/libs/designercore/include/model.h @@ -24,13 +24,6 @@ #include -#ifdef QDS_USE_PROJECTSTORAGE -# define DEPRECATED_OLD_CREATE_MODELNODE \ - [[deprecated("Use unqualified type names and no versions!")]] -#else -# define DEPRECATED_OLD_CREATE_MODELNODE -#endif - QT_BEGIN_NAMESPACE class QPixmap; class QUrl; @@ -91,31 +84,32 @@ public: Imports imports, const QUrl &fileUrl, std::unique_ptr resourceManagement = {}); +#ifndef QDS_USE_PROJECTSTORAGE Model(const TypeName &typeName, int major = 1, int minor = 1, Model *metaInfoProxyModel = nullptr, std::unique_ptr resourceManagement = {}); - +#endif ~Model(); - DEPRECATED_OLD_CREATE_MODELNODE static ModelPointer create( - const TypeName &typeName, - int major = 1, - int minor = 1, - Model *metaInfoProxyModel = nullptr, - std::unique_ptr resourceManagement = {}) +#ifndef QDS_USE_PROJECTSTORAGE + static ModelPointer create(const TypeName &typeName, + int major = 1, + int minor = 1, + Model *metaInfoProxyModel = nullptr, + std::unique_ptr resourceManagement = {}) { return ModelPointer( new Model(typeName, major, minor, metaInfoProxyModel, std::move(resourceManagement))); } +#endif - static ModelPointer create( - ProjectStorageDependencies projectStorageDependencies, - Utils::SmallStringView typeName, - Imports imports, - const QUrl &fileUrl, - std::unique_ptr resourceManagement = {}) + static ModelPointer create(ProjectStorageDependencies projectStorageDependencies, + Utils::SmallStringView typeName, + Imports imports, + const QUrl &fileUrl, + std::unique_ptr resourceManagement = {}) { return ModelPointer(new Model(projectStorageDependencies, typeName, @@ -124,12 +118,12 @@ public: std::move(resourceManagement))); } - DEPRECATED_OLD_CREATE_MODELNODE static ModelPointer create( - ProjectStorageDependencies projectStorageDependencies, - const TypeName &typeName, - int major = 1, - int minor = 1, - std::unique_ptr resourceManagement = {}) +#ifndef QDS_USE_PROJECTSTORAGE + static ModelPointer create(ProjectStorageDependencies projectStorageDependencies, + const TypeName &typeName, + int major = 1, + int minor = 1, + std::unique_ptr resourceManagement = {}) { return ModelPointer(new Model(projectStorageDependencies, typeName, @@ -138,6 +132,7 @@ public: nullptr, std::move(resourceManagement))); } +#endif ModelPointer createModel(const TypeName &typeName, std::unique_ptr resourceManagement = {}); @@ -188,6 +183,7 @@ public: NodeMetaInfo qtQuick3DTextureMetaInfo() const; NodeMetaInfo qtQuick3DTextureInputMetaInfo() const; NodeMetaInfo qtQuickBorderImageMetaInfo() const; + NodeMetaInfo qtQuickControlsLabelMetaInfo() const; NodeMetaInfo qtQuickControlsTextAreaMetaInfo() const; NodeMetaInfo qtQuickImageMetaInfo() const; NodeMetaInfo qtQuickItemMetaInfo() const; diff --git a/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h b/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h index 7cbfdba616a..a58e91a838c 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h +++ b/src/plugins/qmldesigner/libs/designercore/include/modelfwd.h @@ -39,6 +39,8 @@ constexpr bool useProjectStorage() return false; #endif } +class SourcePathStorage; +using PathCache = SourcePathCache; #ifdef QDS_MODEL_USE_PROJECTSTORAGEINTERFACE using ProjectStorageType = ProjectStorageInterface; @@ -46,7 +48,6 @@ class SourcePathCacheInterface; using PathCacheType = SourcePathCacheInterface; #else using ProjectStorageType = ProjectStorage; -class SourcePathStorage; using PathCacheType = SourcePathCache; #endif diff --git a/src/plugins/qmldesigner/libs/designercore/include/nodehints.h b/src/plugins/qmldesigner/libs/designercore/include/nodehints.h index 99470db65f1..5992d7d64a3 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/nodehints.h +++ b/src/plugins/qmldesigner/libs/designercore/include/nodehints.h @@ -49,6 +49,7 @@ public: QStringList visibleNonDefaultProperties() const; bool takesOverRenderingOfChildren() const; bool visibleInNavigator() const; + bool hideInNavigator() const; bool visibleInLibrary() const; QString forceNonDefaultProperty() const; QPair setParentProperty() const; diff --git a/src/plugins/qmldesigner/libs/designercore/include/nodemetainfo.h b/src/plugins/qmldesigner/libs/designercore/include/nodemetainfo.h index fdb29cb10f3..ed2920cac4b 100644 --- a/src/plugins/qmldesigner/libs/designercore/include/nodemetainfo.h +++ b/src/plugins/qmldesigner/libs/designercore/include/nodemetainfo.h @@ -23,22 +23,6 @@ QT_BEGIN_NAMESPACE class QDeclarativeContext; QT_END_NAMESPACE -#ifdef QDS_USE_PROJECTSTORAGE -# define DEPRECATED_TYPENAME [[deprecated("Don't use string based types anymore!")]] -# define DEPRECATED_VERSION_NUMBER \ - [[deprecated( \ - "In most cases you don't need them anymore because the import is setting them!")]] -# define DEPRECATED_COMPONENT_FILE_NAME [[deprecated("Use sourceId() instead.")]] -# define DEPRECATED_IMPORT_DIRECTORY_PATH [[deprecated("Use allExportedTypeNames().")]] -# define DEPRECATED_REQUIRED_IMPORT_STRING [[deprecated("Use allExportedTypeNames().")]] -#else -# define DEPRECATED_TYPENAME -# define DEPRECATED_VERSION_NUMBER -# define DEPRECATED_COMPONENT_FILE_NAME -# define DEPRECATED_IMPORT_DIRECTORY_PATH -# define DEPRECATED_REQUIRED_IMPORT_STRING -#endif - namespace QmlDesigner { class MetaInfo; @@ -54,7 +38,9 @@ class QMLDESIGNERCORE_EXPORT NodeMetaInfo public: NodeMetaInfo(); +#ifndef QDS_USE_PROJECTSTORAGE NodeMetaInfo(Model *model, const TypeName &typeName, int majorVersion, int minorVersion); +#else NodeMetaInfo(TypeId typeId, NotNullPointer projectStorage) : m_typeId{typeId} , m_projectStorage{projectStorage} @@ -62,6 +48,7 @@ public: NodeMetaInfo(NotNullPointer projectStorage) : m_projectStorage{projectStorage} {} +#endif NodeMetaInfo(const NodeMetaInfo &); NodeMetaInfo &operator=(const NodeMetaInfo &); @@ -69,6 +56,7 @@ public: NodeMetaInfo &operator=(NodeMetaInfo &&); ~NodeMetaInfo(); +#ifdef QDS_USE_PROJECTSTORAGE static NodeMetaInfo create(NotNullPointer projectStorage, TypeId typeId) { return {typeId, projectStorage}; @@ -78,6 +66,7 @@ public: { return std::bind_front(&NodeMetaInfo::create, projectStorage); } +#endif bool isValid() const; explicit operator bool() const { return isValid(); } @@ -98,6 +87,7 @@ public: FlagIs isStackedContainer() const; FlagIs takesOverRenderingOfChildren() const; FlagIs visibleInNavigator() const; + FlagIs hideInNavigator() const; FlagIs visibleInLibrary() const; bool hasProperty(::Utils::SmallStringView propertyName) const; @@ -118,11 +108,12 @@ public: bool defaultPropertyIsComponent() const; QString displayName() const; - DEPRECATED_TYPENAME TypeName typeName() const; - DEPRECATED_TYPENAME TypeName simplifiedTypeName() const; - DEPRECATED_VERSION_NUMBER int majorVersion() const; - DEPRECATED_VERSION_NUMBER int minorVersion() const; - +#ifndef QDS_USE_PROJECTSTORAGE + TypeName typeName() const; + TypeName simplifiedTypeName() const; + int majorVersion() const; + int minorVersion() const; +#endif Storage::Info::ExportedTypeNames allExportedTypeNames() const; Storage::Info::ExportedTypeNames exportedTypeNamesForSourceId(SourceId sourceId) const; @@ -131,7 +122,9 @@ public: Storage::Info::ItemLibraryEntries itemLibrariesEntries() const; SourceId sourceId() const; - DEPRECATED_COMPONENT_FILE_NAME QString componentFileName() const; +#ifndef QDS_USE_PROJECTSTORAGE + QString componentFileName() const; +#endif bool isBasedOn(const NodeMetaInfo &metaInfo) const; bool isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo2) const; @@ -214,6 +207,7 @@ public: bool isQtQuick3DCubeMapTexture() const; bool isQtQuick3DView3D() const; bool isQtQuickBorderImage() const; + bool isQtQuickControlsLabel() const; bool isQtQuickControlsSwipeView() const; bool isQtQuickControlsTabBar() const; bool isQtQuickExtrasPicture() const; @@ -226,6 +220,7 @@ public: bool isQtQuickPositioner() const; bool isQtQuickPropertyAnimation() const; bool isQtQuickPropertyChanges() const; + bool isQtQuickRectangle() const; bool isQtQuickRepeater() const; bool isQtQuickState() const; bool isQtQuickStateOperation() const; @@ -251,9 +246,10 @@ public: bool usesCustomParser() const; bool isEnumeration() const; - DEPRECATED_IMPORT_DIRECTORY_PATH QString importDirectoryPath() const; - DEPRECATED_REQUIRED_IMPORT_STRING QString requiredImportString() const; - +#ifndef QDS_USE_PROJECTSTORAGE + QString importDirectoryPath() const; + QString requiredImportString() const; +#endif friend bool operator==(const NodeMetaInfo &first, const NodeMetaInfo &second) { if constexpr (useProjectStorage()) diff --git a/src/plugins/qmldesigner/libs/designercore/metainfo/nodehints.cpp b/src/plugins/qmldesigner/libs/designercore/metainfo/nodehints.cpp index 1f9a3e42bd6..5cbae6861fa 100644 --- a/src/plugins/qmldesigner/libs/designercore/metainfo/nodehints.cpp +++ b/src/plugins/qmldesigner/libs/designercore/metainfo/nodehints.cpp @@ -321,6 +321,19 @@ bool NodeHints::visibleInNavigator() const return evaluateBooleanExpression("visibleInNavigator", false); } +bool NodeHints::hideInNavigator() const +{ + if (!isValid()) + return false; + + auto flagIs = m_modelNode.metaInfo().hideInNavigator(); + + if (flagIs != FlagIs::Set) + return convert(flagIs); + + return evaluateBooleanExpression("hideInNavigator", false); +} + bool NodeHints::visibleInLibrary() const { auto flagIs = m_metaInfo.visibleInLibrary(); diff --git a/src/plugins/qmldesigner/libs/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/libs/designercore/metainfo/nodemetainfo.cpp index e340bc2c357..56836119d06 100644 --- a/src/plugins/qmldesigner/libs/designercore/metainfo/nodemetainfo.cpp +++ b/src/plugins/qmldesigner/libs/designercore/metainfo/nodemetainfo.cpp @@ -614,8 +614,9 @@ public: const TypeName &propertyType(const PropertyName &propertyName) const; void setupPrototypes(); +#ifndef QDS_USE_PROJECTSTORAGE QList prototypes() const; - +#endif bool isPropertyWritable(const PropertyName &propertyName) const; bool isPropertyPointer(const PropertyName &propertyName) const; bool isPropertyList(const PropertyName &propertyName) const; @@ -1429,10 +1430,12 @@ void NodeMetaInfoPrivate::setupPrototypes() } } +#ifndef QDS_USE_PROJECTSTORAGE QList NodeMetaInfoPrivate::prototypes() const { return m_prototypes; } +#endif const CppComponentValue *NodeMetaInfoPrivate::getNearestCppComponentValue() const { @@ -1478,10 +1481,13 @@ NodeMetaInfo &NodeMetaInfo::operator=(const NodeMetaInfo &) = default; NodeMetaInfo::NodeMetaInfo(NodeMetaInfo &&) = default; NodeMetaInfo &NodeMetaInfo::operator=(NodeMetaInfo &&) = default; +#ifndef QDS_USE_PROJECTSTORAGE + NodeMetaInfo::NodeMetaInfo(Model *model, const TypeName &type, int maj, int min) : m_privateData(NodeMetaInfoPrivate::create(model, type, maj, min)) { } +#endif NodeMetaInfo::~NodeMetaInfo() = default; @@ -1774,6 +1780,18 @@ FlagIs NodeMetaInfo::visibleInNavigator() const return FlagIs::Set; } +FlagIs NodeMetaInfo::hideInNavigator() const +{ + if constexpr (useProjectStorage()) { + if (isValid()) + return typeData().traits.hideInNavigator; + + return FlagIs::False; + } + + return FlagIs::Set; +} + FlagIs NodeMetaInfo::visibleInLibrary() const { if constexpr (useProjectStorage()) { @@ -2024,28 +2042,26 @@ std::vector NodeMetaInfo::selfAndPrototypes() const if (!isValid()) return {}; - if constexpr (useProjectStorage()) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get self and prototypes"_t, - category(), - keyValue("type id", m_typeId)}; +#ifdef QDS_USE_PROJECTSTORAGE + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get self and prototypes"_t, category(), keyValue("type id", m_typeId)}; - return Utils::transform(m_projectStorage->prototypeAndSelfIds(m_typeId), - NodeMetaInfo::bind(m_projectStorage)); - } else { - NodeMetaInfos hierarchy = {*this}; - Model *model = m_privateData->model(); - for (const TypeDescription &type : m_privateData->prototypes()) { - auto &last = hierarchy.emplace_back(model, - type.className.toUtf8(), - type.majorVersion, - type.minorVersion); - if (!last.isValid()) - hierarchy.pop_back(); - } - - return hierarchy; + return Utils::transform(m_projectStorage->prototypeAndSelfIds(m_typeId), + NodeMetaInfo::bind(m_projectStorage)); +#else + NodeMetaInfos hierarchy = {*this}; + Model *model = m_privateData->model(); + for (const TypeDescription &type : m_privateData->prototypes()) { + auto &last = hierarchy.emplace_back(model, + type.className.toUtf8(), + type.majorVersion, + type.minorVersion); + if (!last.isValid()) + hierarchy.pop_back(); } + + return hierarchy; +#endif } NodeMetaInfos NodeMetaInfo::prototypes() const @@ -2053,26 +2069,26 @@ NodeMetaInfos NodeMetaInfo::prototypes() const if (!isValid()) return {}; - if constexpr (useProjectStorage()) { - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get prototypes"_t, category(), keyValue("type id", m_typeId)}; - return Utils::transform(m_projectStorage->prototypeIds(m_typeId), - NodeMetaInfo::bind(m_projectStorage)); +#ifdef QDS_USE_PROJECTSTORAGE + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get prototypes"_t, category(), keyValue("type id", m_typeId)}; + return Utils::transform(m_projectStorage->prototypeIds(m_typeId), + NodeMetaInfo::bind(m_projectStorage)); - } else { - NodeMetaInfos hierarchy; - Model *model = m_privateData->model(); - for (const TypeDescription &type : m_privateData->prototypes()) { - auto &last = hierarchy.emplace_back(model, - type.className.toUtf8(), - type.majorVersion, - type.minorVersion); - if (!last.isValid()) - hierarchy.pop_back(); - } - - return hierarchy; +#else + NodeMetaInfos hierarchy; + Model *model = m_privateData->model(); + for (const TypeDescription &type : m_privateData->prototypes()) { + auto &last = hierarchy.emplace_back(model, + type.className.toUtf8(), + type.majorVersion, + type.minorVersion); + if (!last.isValid()) + hierarchy.pop_back(); } + + return hierarchy; +#endif } namespace { @@ -2111,6 +2127,7 @@ QString NodeMetaInfo::displayName() const return {}; } +#ifndef QDS_USE_PROJECTSTORAGE TypeName NodeMetaInfo::typeName() const { if (isValid()) @@ -2146,6 +2163,7 @@ int NodeMetaInfo::minorVersion() const return -1; } +#endif Storage::Info::ExportedTypeNames NodeMetaInfo::allExportedTypeNames() const { @@ -2260,6 +2278,7 @@ SourceId NodeMetaInfo::sourceId() const return SourceId{}; } +#ifndef QDS_USE_PROJECTSTORAGE QString NodeMetaInfo::componentFileName() const { if constexpr (!useProjectStorage()) { @@ -2295,6 +2314,7 @@ QString NodeMetaInfo::requiredImportString() const return {}; } +#endif SourceId NodeMetaInfo::propertyEditorPathId() const { @@ -2333,13 +2353,17 @@ PropertyDeclarationId NodeMetaInfo::defaultPropertyDeclarationId() const return *m_defaultPropertyId; } -bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int minorVersion) const +bool NodeMetaInfo::isSubclassOf([[maybe_unused]] const TypeName &type, + [[maybe_unused]] int majorVersion, + [[maybe_unused]] int minorVersion) const { if (!isValid()) { qWarning() << "NodeMetaInfo is invalid" << type; return false; } +#ifndef QDS_USE_PROJECTSTORAGE + if (typeName().isEmpty()) return false; @@ -2363,6 +2387,7 @@ bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int mino } } m_privateData->prototypeCacheNegatives().insert(stringIdentifier(type, majorVersion, minorVersion)); +#endif return false; } @@ -2402,75 +2427,73 @@ bool NodeMetaInfo::isSuitableForMouseAreaFill() const bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, - category(), - keyValue("type id", m_typeId), - keyValue("meta info type id", metaInfo.m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, + category(), + keyValue("type id", m_typeId), + keyValue("meta info type id", metaInfo.m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, metaInfo.m_typeId); - } else { - if (!isValid()) - return false; - if (majorVersion() == -1 && minorVersion() == -1) - return isSubclassOf(metaInfo.typeName()); - return isSubclassOf(metaInfo.typeName(), metaInfo.majorVersion(), metaInfo.minorVersion()); - } + return m_projectStorage->isBasedOn(m_typeId, metaInfo.m_typeId); +#else + if (!isValid()) + return false; + if (majorVersion() == -1 && minorVersion() == -1) + return isSubclassOf(metaInfo.typeName()); + return isSubclassOf(metaInfo.typeName(), metaInfo.majorVersion(), metaInfo.minorVersion()); +#endif } bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo2) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, metaInfo1.m_typeId, metaInfo2.m_typeId); - } else { - if (!isValid()) - return false; - if (majorVersion() == -1 && minorVersion() == -1) - return (isSubclassOf(metaInfo1.typeName()) || isSubclassOf(metaInfo2.typeName())); + return m_projectStorage->isBasedOn(m_typeId, metaInfo1.m_typeId, metaInfo2.m_typeId); +#else + if (!isValid()) + return false; + if (majorVersion() == -1 && minorVersion() == -1) + return (isSubclassOf(metaInfo1.typeName()) || isSubclassOf(metaInfo2.typeName())); - return ( - isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) + return (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) || isSubclassOf(metaInfo2.typeName(), metaInfo2.majorVersion(), metaInfo2.minorVersion())); - } +#endif } bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo2, const NodeMetaInfo &metaInfo3) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, - metaInfo1.m_typeId, - metaInfo2.m_typeId, - metaInfo3.m_typeId); - } else { - if (!isValid()) - return false; - if (majorVersion() == -1 && minorVersion() == -1) - return (isSubclassOf(metaInfo1.typeName()) || isSubclassOf(metaInfo2.typeName()) - || isSubclassOf(metaInfo3.typeName())); + return m_projectStorage->isBasedOn(m_typeId, + metaInfo1.m_typeId, + metaInfo2.m_typeId, + metaInfo3.m_typeId); +#else + if (!isValid()) + return false; + if (majorVersion() == -1 && minorVersion() == -1) + return (isSubclassOf(metaInfo1.typeName()) || isSubclassOf(metaInfo2.typeName()) + || isSubclassOf(metaInfo3.typeName())); - return ( - isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) + return (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) || isSubclassOf(metaInfo2.typeName(), metaInfo2.majorVersion(), metaInfo2.minorVersion()) || isSubclassOf(metaInfo3.typeName(), metaInfo3.majorVersion(), metaInfo3.minorVersion())); - } +#endif } bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, @@ -2478,31 +2501,27 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo3, const NodeMetaInfo &metaInfo4) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, - metaInfo1.m_typeId, - metaInfo2.m_typeId, - metaInfo3.m_typeId, - metaInfo4.m_typeId); - } else { - return isValid() - && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) - || isSubclassOf(metaInfo2.typeName(), - metaInfo2.majorVersion(), - metaInfo2.minorVersion()) - || isSubclassOf(metaInfo3.typeName(), - metaInfo3.majorVersion(), - metaInfo3.minorVersion()) - || isSubclassOf(metaInfo4.typeName(), - metaInfo4.majorVersion(), - metaInfo4.minorVersion())); - } + return m_projectStorage->isBasedOn(m_typeId, + metaInfo1.m_typeId, + metaInfo2.m_typeId, + metaInfo3.m_typeId, + metaInfo4.m_typeId); +#else + return isValid() + && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) + || isSubclassOf(metaInfo2.typeName(), metaInfo2.majorVersion(), metaInfo2.minorVersion()) + || isSubclassOf(metaInfo3.typeName(), metaInfo3.majorVersion(), metaInfo3.minorVersion()) + || isSubclassOf(metaInfo4.typeName(), + metaInfo4.majorVersion(), + metaInfo4.minorVersion())); +#endif } bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, @@ -2511,35 +2530,29 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo4, const NodeMetaInfo &metaInfo5) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, - metaInfo1.m_typeId, - metaInfo2.m_typeId, - metaInfo3.m_typeId, - metaInfo4.m_typeId, - metaInfo5.m_typeId); - } else { - return isValid() - && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) - || isSubclassOf(metaInfo2.typeName(), - metaInfo2.majorVersion(), - metaInfo2.minorVersion()) - || isSubclassOf(metaInfo3.typeName(), - metaInfo3.majorVersion(), - metaInfo3.minorVersion()) - || isSubclassOf(metaInfo4.typeName(), - metaInfo4.majorVersion(), - metaInfo4.minorVersion()) - || isSubclassOf(metaInfo5.typeName(), - metaInfo5.majorVersion(), - metaInfo5.minorVersion())); - } + return m_projectStorage->isBasedOn(m_typeId, + metaInfo1.m_typeId, + metaInfo2.m_typeId, + metaInfo3.m_typeId, + metaInfo4.m_typeId, + metaInfo5.m_typeId); +#else + return isValid() + && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) + || isSubclassOf(metaInfo2.typeName(), metaInfo2.majorVersion(), metaInfo2.minorVersion()) + || isSubclassOf(metaInfo3.typeName(), metaInfo3.majorVersion(), metaInfo3.minorVersion()) + || isSubclassOf(metaInfo4.typeName(), metaInfo4.majorVersion(), metaInfo4.minorVersion()) + || isSubclassOf(metaInfo5.typeName(), + metaInfo5.majorVersion(), + metaInfo5.minorVersion())); +#endif } bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, @@ -2549,39 +2562,31 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo5, const NodeMetaInfo &metaInfo6) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, - metaInfo1.m_typeId, - metaInfo2.m_typeId, - metaInfo3.m_typeId, - metaInfo4.m_typeId, - metaInfo5.m_typeId, - metaInfo6.m_typeId); - } else { - return isValid() - && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) - || isSubclassOf(metaInfo2.typeName(), - metaInfo2.majorVersion(), - metaInfo2.minorVersion()) - || isSubclassOf(metaInfo3.typeName(), - metaInfo3.majorVersion(), - metaInfo3.minorVersion()) - || isSubclassOf(metaInfo4.typeName(), - metaInfo4.majorVersion(), - metaInfo4.minorVersion()) - || isSubclassOf(metaInfo5.typeName(), - metaInfo5.majorVersion(), - metaInfo5.minorVersion()) - || isSubclassOf(metaInfo6.typeName(), - metaInfo6.majorVersion(), - metaInfo6.minorVersion())); - } + return m_projectStorage->isBasedOn(m_typeId, + metaInfo1.m_typeId, + metaInfo2.m_typeId, + metaInfo3.m_typeId, + metaInfo4.m_typeId, + metaInfo5.m_typeId, + metaInfo6.m_typeId); +#else + return isValid() + && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) + || isSubclassOf(metaInfo2.typeName(), metaInfo2.majorVersion(), metaInfo2.minorVersion()) + || isSubclassOf(metaInfo3.typeName(), metaInfo3.majorVersion(), metaInfo3.minorVersion()) + || isSubclassOf(metaInfo4.typeName(), metaInfo4.majorVersion(), metaInfo4.minorVersion()) + || isSubclassOf(metaInfo5.typeName(), metaInfo5.majorVersion(), metaInfo5.minorVersion()) + || isSubclassOf(metaInfo6.typeName(), + metaInfo6.majorVersion(), + metaInfo6.minorVersion())); +#endif } bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, @@ -2592,43 +2597,33 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo6, const NodeMetaInfo &metaInfo7) const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is based on"_t, category(), keyValue("type id", m_typeId)}; - return m_projectStorage->isBasedOn(m_typeId, - metaInfo1.m_typeId, - metaInfo2.m_typeId, - metaInfo3.m_typeId, - metaInfo4.m_typeId, - metaInfo5.m_typeId, - metaInfo6.m_typeId, - metaInfo7.m_typeId); - } else { - return isValid() - && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) - || isSubclassOf(metaInfo2.typeName(), - metaInfo2.majorVersion(), - metaInfo2.minorVersion()) - || isSubclassOf(metaInfo3.typeName(), - metaInfo3.majorVersion(), - metaInfo3.minorVersion()) - || isSubclassOf(metaInfo4.typeName(), - metaInfo4.majorVersion(), - metaInfo4.minorVersion()) - || isSubclassOf(metaInfo5.typeName(), - metaInfo5.majorVersion(), - metaInfo5.minorVersion()) - || isSubclassOf(metaInfo6.typeName(), - metaInfo6.majorVersion(), - metaInfo6.minorVersion()) - || isSubclassOf(metaInfo7.typeName(), - metaInfo7.majorVersion(), - metaInfo7.minorVersion())); - } + return m_projectStorage->isBasedOn(m_typeId, + metaInfo1.m_typeId, + metaInfo2.m_typeId, + metaInfo3.m_typeId, + metaInfo4.m_typeId, + metaInfo5.m_typeId, + metaInfo6.m_typeId, + metaInfo7.m_typeId); +#else + return isValid() + && (isSubclassOf(metaInfo1.typeName(), metaInfo1.majorVersion(), metaInfo1.minorVersion()) + || isSubclassOf(metaInfo2.typeName(), metaInfo2.majorVersion(), metaInfo2.minorVersion()) + || isSubclassOf(metaInfo3.typeName(), metaInfo3.majorVersion(), metaInfo3.minorVersion()) + || isSubclassOf(metaInfo4.typeName(), metaInfo4.majorVersion(), metaInfo4.minorVersion()) + || isSubclassOf(metaInfo5.typeName(), metaInfo5.majorVersion(), metaInfo5.minorVersion()) + || isSubclassOf(metaInfo6.typeName(), metaInfo6.majorVersion(), metaInfo6.minorVersion()) + || isSubclassOf(metaInfo7.typeName(), + metaInfo7.majorVersion(), + metaInfo7.minorVersion())); +#endif } bool NodeMetaInfo::isGraphicalItem() const @@ -2673,20 +2668,18 @@ bool NodeMetaInfo::isQtObject() const bool NodeMetaInfo::isQtQmlConnections() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is Qt Qml connections"_t, - category(), - keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is Qt Qml connections"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isBasedOnCommonType(m_projectStorage, m_typeId); - } else { - return isValid() && simplifiedTypeName() == "Connections"; - } + using namespace Storage::Info; + return isBasedOnCommonType(m_projectStorage, m_typeId); +#else + return isValid() && simplifiedTypeName() == "Connections"; +#endif } bool NodeMetaInfo::isLayoutable() const @@ -2753,22 +2746,22 @@ bool NodeMetaInfo::isView() const bool NodeMetaInfo::usesCustomParser() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"uses custom parser"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"uses custom parser"_t, category(), keyValue("type id", m_typeId)}; - return typeData().traits.usesCustomParser; - } else { - if (!isValid()) - return false; + return typeData().traits.usesCustomParser; +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); - return type == "VisualItemModel" || type == "VisualDataModel" || type == "ListModel" - || type == "XmlListModel"; - } + auto type = simplifiedTypeName(); + return type == "VisualItemModel" || type == "VisualDataModel" || type == "ListModel" + || type == "XmlListModel"; +#endif } namespace { @@ -3123,6 +3116,23 @@ bool NodeMetaInfo::isQtQuickPropertyAnimation() const } } +bool NodeMetaInfo::isQtQuickRectangle() const +{ +#ifdef QDS_USE_PROJECTSTORAGE + + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Rectange"_t, category(), keyValue("type id", m_typeId)}; + + using namespace Storage::Info; + return isBasedOnCommonType(m_projectStorage, m_typeId); +#else + return isValid() && isSubclassOf("QtQuick.Rectangle"); +#endif +} + bool NodeMetaInfo::isQtQuickRepeater() const { if constexpr (useProjectStorage()) { @@ -3157,6 +3167,24 @@ bool NodeMetaInfo::isQtQuickControlsTabBar() const } } +bool NodeMetaInfo::isQtQuickControlsLabel() const +{ +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; + + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QtQuick.Controls.SwipeView"_t, + category(), + keyValue("type id", m_typeId)}; + + using namespace Storage::Info; + return isBasedOnCommonType(m_projectStorage, m_typeId); +#else + return isValid() && isSubclassOf("QtQuick.Controls.Label"); +#endif +} + bool NodeMetaInfo::isQtQuickControlsSwipeView() const { if constexpr (useProjectStorage()) { @@ -3744,189 +3772,189 @@ bool NodeMetaInfo::isQtQuickStudioUtilsJsonListModel() const bool NodeMetaInfo::isQmlComponent() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is QML.Component"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is QML.Component"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isBasedOnCommonType(m_projectStorage, m_typeId); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isBasedOnCommonType(m_projectStorage, m_typeId); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "Component" || type == "QQmlComponent"; - } + return type == "Component" || type == "QQmlComponent"; +#endif } bool NodeMetaInfo::isFont() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is font"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is font"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->commonTypeId()); - } else { - return isValid() && simplifiedTypeName() == "font"; - } + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->commonTypeId()); +#else + return isValid() && simplifiedTypeName() == "font"; +#endif } bool NodeMetaInfo::isColor() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is color"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is color"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "QColor" || type == "color" || type == "color"; - } + return type == "QColor" || type == "color" || type == "color"; +#endif } bool NodeMetaInfo::isBool() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is bool"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is bool"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "bool" || type == "boolean"; - } + return type == "bool" || type == "boolean"; +#endif } bool NodeMetaInfo::isInteger() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is integer"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is integer"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "int" || type == "integer" || type == "uint"; - } + return type == "int" || type == "integer" || type == "uint"; +#endif } bool NodeMetaInfo::isFloat() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is float"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is float"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - auto floatId = m_projectStorage->builtinTypeId(); - auto doubleId = m_projectStorage->builtinTypeId(); + using namespace Storage::Info; + auto floatId = m_projectStorage->builtinTypeId(); + auto doubleId = m_projectStorage->builtinTypeId(); - return isTypeId(m_typeId, floatId, doubleId); - } else { - if (!isValid()) - return false; + return isTypeId(m_typeId, floatId, doubleId); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "qreal" || type == "double" || type == "float" || type == "real"; - } + return type == "qreal" || type == "double" || type == "float" || type == "real"; +#endif } bool NodeMetaInfo::isVariant() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is variant"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is variant"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); +#else + if (!isValid()) + return false; - const auto type = simplifiedTypeName(); + const auto type = simplifiedTypeName(); - return type == "QVariant" || type == "var" || type == "variant"; - } + return type == "QVariant" || type == "var" || type == "variant"; +#endif } bool NodeMetaInfo::isString() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is string"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is string"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "string" || type == "QString"; - } + return type == "string" || type == "QString"; +#endif } bool NodeMetaInfo::isUrl() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return false; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return false; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"is url"_t, category(), keyValue("type id", m_typeId)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"is url"_t, category(), keyValue("type id", m_typeId)}; - using namespace Storage::Info; - return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); - } else { - if (!isValid()) - return false; + using namespace Storage::Info; + return isValid() && isTypeId(m_typeId, m_projectStorage->builtinTypeId()); +#else + if (!isValid()) + return false; - auto type = simplifiedTypeName(); + auto type = simplifiedTypeName(); - return type == "url" || type == "QUrl"; - } + return type == "url" || type == "QUrl"; +#endif } bool NodeMetaInfo::isQtQuick3DTexture() const @@ -4249,40 +4277,40 @@ PropertyMetaInfo::~PropertyMetaInfo() = default; NodeMetaInfo PropertyMetaInfo::propertyType() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return {}; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return {}; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get property type"_t, - category(), - keyValue("property declaration id", m_id)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property type"_t, + category(), + keyValue("property declaration id", m_id)}; - return {propertyData().propertyTypeId, m_projectStorage}; - } else { - if (isValid()) - return NodeMetaInfo{nodeMetaInfoPrivateData()->model(), - nodeMetaInfoPrivateData()->propertyType(propertyName()), - -1, - -1}; - } + return {propertyData().propertyTypeId, m_projectStorage}; +#else + if (isValid()) + return NodeMetaInfo{nodeMetaInfoPrivateData()->model(), + nodeMetaInfoPrivateData()->propertyType(propertyName()), + -1, + -1}; +#endif return {}; } NodeMetaInfo PropertyMetaInfo::type() const { - if constexpr (useProjectStorage()) { - if (!isValid()) - return {}; +#ifdef QDS_USE_PROJECTSTORAGE + if (!isValid()) + return {}; - using NanotraceHR::keyValue; - NanotraceHR::Tracer tracer{"get property owner type "_t, - category(), - keyValue("property declaration id", m_id)}; + using NanotraceHR::keyValue; + NanotraceHR::Tracer tracer{"get property owner type "_t, + category(), + keyValue("property declaration id", m_id)}; - return NodeMetaInfo(propertyData().typeId, m_projectStorage); - } + return NodeMetaInfo(propertyData().typeId, m_projectStorage); +#endif return {}; } @@ -4530,7 +4558,11 @@ const Storage::Info::PropertyDeclaration &PropertyMetaInfo::propertyData() const TypeName PropertyMetaInfo::propertyTypeName() const { +#ifndef QDS_USE_PROJECTSTORAGE return propertyType().typeName(); +#else + return {}; +#endif } const NodeMetaInfoPrivate *PropertyMetaInfo::nodeMetaInfoPrivateData() const @@ -4554,37 +4586,36 @@ const PropertyName &PropertyMetaInfo::propertyName() const NodeMetaInfo NodeMetaInfo::commonBase(const NodeMetaInfo &metaInfo) const { - if constexpr (useProjectStorage()) { - if (isValid() && metaInfo) { - const auto firstTypeIds = m_projectStorage->prototypeAndSelfIds(m_typeId); - const auto secondTypeIds = m_projectStorage->prototypeAndSelfIds(metaInfo.m_typeId); - auto found = std::ranges::find_if(firstTypeIds, [&](TypeId firstTypeId) { - return std::ranges::find(secondTypeIds, firstTypeId) != secondTypeIds.end(); - }); +#ifdef QDS_USE_PROJECTSTORAGE + if (isValid() && metaInfo) { + const auto firstTypeIds = m_projectStorage->prototypeAndSelfIds(m_typeId); + const auto secondTypeIds = m_projectStorage->prototypeAndSelfIds(metaInfo.m_typeId); + auto found = std::ranges::find_if(firstTypeIds, [&](TypeId firstTypeId) { + return std::ranges::find(secondTypeIds, firstTypeId) != secondTypeIds.end(); + }); - if (found != firstTypeIds.end()) { - return NodeMetaInfo{*found, m_projectStorage}; - } - } - } else { - for (const NodeMetaInfo &info : metaInfo.selfAndPrototypes()) { - if (isBasedOn(info)) { - return info; - } + if (found != firstTypeIds.end()) + return NodeMetaInfo{*found, m_projectStorage}; + } +#else + for (const NodeMetaInfo &info : metaInfo.selfAndPrototypes()) { + if (isBasedOn(info)) { + return info; } } +#endif return {}; } NodeMetaInfo::NodeMetaInfos NodeMetaInfo::heirs() const { - if constexpr (useProjectStorage()) { - if (isValid()) { - return Utils::transform(m_projectStorage->heirIds(m_typeId), - NodeMetaInfo::bind(m_projectStorage)); - } +#ifdef QDS_USE_PROJECTSTORAGE + if (isValid()) { + return Utils::transform(m_projectStorage->heirIds(m_typeId), + NodeMetaInfo::bind(m_projectStorage)); } +#endif return {}; } diff --git a/src/plugins/qmldesigner/libs/designercore/model/model.cpp b/src/plugins/qmldesigner/libs/designercore/model/model.cpp index f54ed1758a8..4b7b776b34e 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/libs/designercore/model/model.cpp @@ -1789,6 +1789,7 @@ Model::Model(ProjectStorageDependencies projectStorageDependencies, std::move(resourceManagement))) {} +#ifndef QDS_USE_PROJECTSTORAGE Model::Model(const TypeName &typeName, int major, int minor, @@ -1797,6 +1798,7 @@ Model::Model(const TypeName &typeName, : d(std::make_unique( this, typeName, major, minor, metaInfoProxyModel, std::move(resourceManagement))) {} +#endif ModelPointer Model::createModel(const TypeName &typeName, std::unique_ptr resourceManagement) @@ -1947,6 +1949,9 @@ void Model::startDrag(std::unique_ptr mimeData, const QPixmap &icon, void Model::endDrag() { + if (!d->drag) + return; + d->notifyDragEnded(); d->drag.reset(); } @@ -2481,6 +2486,16 @@ NodeMetaInfo Model::qtQuickTextEditMetaInfo() const } } +NodeMetaInfo Model::qtQuickControlsLabelMetaInfo() const +{ +#ifdef QDS_USE_PROJECTSTORAGE + using namespace Storage::Info; + return createNodeMetaInfo(); +#else + return metaInfo("QtQuick.Controls.Label"); +#endif +} + NodeMetaInfo Model::qtQuickControlsTextAreaMetaInfo() const { if constexpr (useProjectStorage()) { @@ -2774,24 +2789,26 @@ namespace { } } // namespace -NodeMetaInfo Model::metaInfo(const TypeName &typeName, int majorVersion, int minorVersion) const +NodeMetaInfo Model::metaInfo(const TypeName &typeName, + [[maybe_unused]] int majorVersion, + [[maybe_unused]] int minorVersion) const { - if constexpr (useProjectStorage()) { - return NodeMetaInfo(d->projectStorage->typeId(d->importedTypeNameId(typeName)), - d->projectStorage); - } else { - return NodeMetaInfo(metaInfoProxyModel(), typeName, majorVersion, minorVersion); - } +#ifdef QDS_USE_PROJECTSTORAGE + return NodeMetaInfo(d->projectStorage->typeId(d->importedTypeNameId(typeName)), d->projectStorage); +#else + return NodeMetaInfo(metaInfoProxyModel(), typeName, majorVersion, minorVersion); +#endif } -NodeMetaInfo Model::metaInfo(Module module, Utils::SmallStringView typeName, Storage::Version version) const +NodeMetaInfo Model::metaInfo([[maybe_unused]] Module module, + [[maybe_unused]] Utils::SmallStringView typeName, + [[maybe_unused]] Storage::Version version) const { - if constexpr (useProjectStorage()) { - return NodeMetaInfo(d->projectStorage->typeId(module.id(), typeName, version), - d->projectStorage); - } else { - return {}; - } +#ifdef QDS_USE_PROJECTSTORAGE + return NodeMetaInfo(d->projectStorage->typeId(module.id(), typeName, version), d->projectStorage); +#else + return {}; +#endif } #ifndef QDS_USE_PROJECTSTORAGE diff --git a/src/plugins/qmldesigner/libs/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/libs/designercore/model/modelnode.cpp index 8eba7549bf5..0dc461159fc 100644 --- a/src/plugins/qmldesigner/libs/designercore/model/modelnode.cpp +++ b/src/plugins/qmldesigner/libs/designercore/model/modelnode.cpp @@ -687,14 +687,14 @@ NodeMetaInfo ModelNode::metaInfo() const if (!isValid()) return {}; - if constexpr (useProjectStorage()) { - return NodeMetaInfo(m_internalNode->typeId, m_model->projectStorage()); - } else { - return NodeMetaInfo(m_model->metaInfoProxyModel(), - m_internalNode->typeName, - m_internalNode->majorVersion, - m_internalNode->minorVersion); - } +#ifdef QDS_USE_PROJECTSTORAGE + return NodeMetaInfo(m_internalNode->typeId, m_model->projectStorage()); +#else + return NodeMetaInfo(m_model->metaInfoProxyModel(), + m_internalNode->typeName, + m_internalNode->majorVersion, + m_internalNode->minorVersion); +#endif } bool ModelNode::hasMetaInfo() const diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/commontypecache.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/commontypecache.h index 76305b1fbee..618c9418c18 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/commontypecache.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/commontypecache.h @@ -58,6 +58,7 @@ inline constexpr char Item[] = "Item"; inline constexpr char JsonListModel[] = "JsonListModel"; inline constexpr char KeyframeGroup[] = "KeyframeGroup"; inline constexpr char Keyframe[] = "Keyframe"; +inline constexpr char Label[] = "Label"; inline constexpr char Layout[] = "Layout"; inline constexpr char Light[] = "Light"; inline constexpr char ListElement[] = "ListElement"; @@ -236,6 +237,7 @@ class CommonTypeCache CacheType, CacheType, CacheType, + CacheType, CacheType, CacheType, CacheType, diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.h index 8e83cd2ff04..ae58b229d82 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/filesystem.h @@ -7,6 +7,8 @@ #include "filesysteminterface.h" #include "sourcepathstorage/nonlockingmutex.h" +#include + namespace QmlDesigner { class SourcePathStorage; @@ -16,10 +18,9 @@ class SourcePathCache; class QMLDESIGNERCORE_EXPORT FileSystem : public FileSystemInterface { - using PathCache = SourcePathCache; public: - FileSystem(PathCache &sourcePathCache) + FileSystem(PathCacheType &sourcePathCache) : m_sourcePathCache(sourcePathCache) {} @@ -33,7 +34,7 @@ public: void remove(const SourceIds &sourceIds) override; private: - PathCache &m_sourcePathCache; + PathCacheType &m_sourcePathCache; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinfotypes.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinfotypes.h index 7d1598191d6..8b602ed65a9 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinfotypes.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinfotypes.h @@ -147,6 +147,7 @@ struct TypeTraits , takesOverRenderingOfChildren{FlagIs::False} , visibleInNavigator{FlagIs::False} , visibleInLibrary{FlagIs::False} + , hideInNavigator{FlagIs::False} , dummy2{0U} {} @@ -193,7 +194,8 @@ struct TypeTraits keyValue("is stacked container", typeTraits.isStackedContainer), keyValue("takes over rendering of children", typeTraits.takesOverRenderingOfChildren), keyValue("visible in navigator", typeTraits.visibleInNavigator), - keyValue("visible in library", typeTraits.visibleInLibrary)); + keyValue("visible in library", typeTraits.visibleInLibrary), + keyValue("hide in navigator", typeTraits.hideInNavigator)); convertToString(string, dict); } @@ -228,7 +230,8 @@ struct TypeTraits FlagIs takesOverRenderingOfChildren : 2; FlagIs visibleInNavigator : 2; FlagIs visibleInLibrary : 2; - unsigned int dummy2 : 6; + FlagIs hideInNavigator : 2; + unsigned int dummy2 : 4; }; unsigned int annotation; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h index 69674ffc8bf..9cf0daf4e8c 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageinterface.h @@ -17,7 +17,7 @@ namespace QmlDesigner { class ProjectStorageInterface { - friend Storage::Info::CommonTypeCache; + friend Storage::Info::CommonTypeCache; public: ProjectStorageInterface(const ProjectStorageInterface &) = delete; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h index 344b0543a27..6c3353ff68a 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/projectstorageupdater.h @@ -41,12 +41,10 @@ class QMLDESIGNERCORE_EXPORT ProjectStorageUpdater final : public ProjectStoragePathWatcherNotifierInterface { public: - using PathCache = SourcePathCache; - ProjectStorageUpdater(FileSystemInterface &fileSystem, ProjectStorageType &projectStorage, FileStatusCache &fileStatusCache, - PathCache &pathCache, + PathCacheType &pathCache, QmlDocumentParserInterface &qmlDocumentParser, QmlTypesParserInterface &qmlTypesParser, class ProjectStoragePathWatcherInterface &pathWatcher, @@ -243,7 +241,7 @@ private: FileSystemInterface &m_fileSystem; ProjectStorageType &m_projectStorage; FileStatusCache &m_fileStatusCache; - PathCache &m_pathCache; + PathCacheType &m_pathCache; QmlDocumentParserInterface &m_qmlDocumentParser; QmlTypesParserInterface &m_qmlTypesParser; ProjectStoragePathWatcherInterface &m_pathWatcher; diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.cpp index b571cebac3d..17aa8ca9617 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.cpp @@ -66,7 +66,7 @@ Utils::PathString createNormalizedPath(Utils::SmallStringView directoryPath, Storage::Import createImport(const QmlDom::Import &qmlImport, SourceId sourceId, Utils::SmallStringView directoryPath, - QmlDocumentParser::ProjectStorage &storage) + ProjectStorageType &storage) { using Storage::ModuleKind; using QmlUriKind = QQmlJS::Dom::QmlUri::Kind; @@ -99,7 +99,7 @@ Storage::Import createImport(const QmlDom::Import &qmlImport, QualifiedImports createQualifiedImports(const QList &qmlImports, SourceId sourceId, Utils::SmallStringView directoryPath, - QmlDocumentParser::ProjectStorage &storage) + ProjectStorageType &storage) { NanotraceHR::Tracer tracer{"create qualified imports"_t, category(), @@ -123,7 +123,7 @@ void addImports(Storage::Imports &imports, const QList &qmlImports, SourceId sourceId, Utils::SmallStringView directoryPath, - QmlDocumentParser::ProjectStorage &storage) + ProjectStorageType &storage) { int importCount = 0; for (const QmlDom::Import &qmlImport : qmlImports) { diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.h b/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.h index 7b64322ab4f..bdf50aac23e 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.h +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/qmldocumentparser.h @@ -7,8 +7,8 @@ #include "qmldocumentparserinterface.h" #include "sourcepathstorage/nonlockingmutex.h" +#include #include - namespace QmlDesigner { template @@ -18,16 +18,14 @@ class SourcePathStorage; class QMLDESIGNERCORE_EXPORT QmlDocumentParser final : public QmlDocumentParserInterface { public: - using ProjectStorage = QmlDesigner::ProjectStorage; - using PathCache = QmlDesigner::SourcePathCache; #ifdef QDS_BUILD_QMLPARSER - QmlDocumentParser(ProjectStorage &storage, PathCache &pathCache) + QmlDocumentParser(ProjectStorageType &storage, PathCacheType &pathCache) : m_storage{storage} , m_pathCache{pathCache} {} #else - QmlDocumentParser(ProjectStorage &, PathCache &) + QmlDocumentParser(ProjectStorage &, PathCacheType &) {} #endif @@ -39,8 +37,8 @@ public: private: // m_pathCache and m_storage are only used when compiled for QDS #ifdef QDS_BUILD_QMLPARSER - ProjectStorage &m_storage; - PathCache &m_pathCache; + ProjectStorageType &m_storage; + PathCacheType &m_pathCache; #endif }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.cpp b/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.cpp index 71eba949662..4d604cdf2ea 100644 --- a/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.cpp +++ b/src/plugins/qmldesigner/libs/designercore/projectstorage/typeannotationreader.cpp @@ -400,6 +400,8 @@ void setTrait(QStringView name, FlagIs flag, Storage::TypeTraits &traits) traits.visibleInNavigator = flag; } else if (name == "visibleInLibrary"_L1) { traits.visibleInLibrary = flag; + } else if (name == "hideInNavigator"_L1) { + traits.hideInNavigator = flag; } } diff --git a/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp b/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp index d41fa2cd7a8..b03e0f3b52e 100644 --- a/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/libs/designercore/rewriter/texttomodelmerger.cpp @@ -1432,8 +1432,13 @@ QmlDesigner::PropertyName TextToModelMerger::syncScriptBinding(ModelNode &modelN prefix, script->qualifiedId, astValue); + +#ifndef QDS_USE_PROJECTSTORAGE // Can happen if the type was just created and was not fully processed yet const bool newlyCreatedTypeCase = !modelNode.metaInfo().properties().size(); +#else + const bool newlyCreatedTypeCase = false; +#endif if (enumValue.isValid()) { // It is a qualified enum: AbstractProperty modelProperty = modelNode.property(astPropertyName.toUtf8()); @@ -1805,6 +1810,7 @@ void ModelValidator::shouldBeVariantProperty([[maybe_unused]] AbstractProperty & const QVariant & /*qmlVariantValue*/, const TypeName & /*dynamicTypeName*/) { + QTC_CHECK(modelProperty.isVariantProperty()); Q_ASSERT(modelProperty.isVariantProperty()); Q_ASSERT(0); } @@ -1866,6 +1872,7 @@ void ModelValidator::propertyAbsentFromQml([[maybe_unused]] AbstractProperty &mo { Q_ASSERT(!modelProperty.isValid()); Q_ASSERT(0); + QTC_CHECK(!modelProperty.isValid()); } void ModelValidator::idsDiffer([[maybe_unused]] ModelNode &modelNode, diff --git a/src/plugins/qmldesigner/libs/designsystem/CMakeLists.txt b/src/plugins/qmldesigner/libs/designsystem/CMakeLists.txt new file mode 100644 index 00000000000..05fde136802 --- /dev/null +++ b/src/plugins/qmldesigner/libs/designsystem/CMakeLists.txt @@ -0,0 +1,16 @@ +add_qtc_library(DesignSystem STATIC + PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR} + DEPENDS + Qt::Core Qt::Widgets QmlDesignerCore + SOURCES + dsconstants.h + dsthemegroup.h dsthemegroup.cpp + dsthememanager.h dsthememanager.cpp +) + +extend_qtc_library(DesignSystem + CONDITION ENABLE_COMPILE_WARNING_AS_ERROR + PROPERTIES COMPILE_WARNING_AS_ERROR ON + PUBLIC_COMPILE_OPTIONS + $<$:-Wno-error=maybe-uninitialized> +) diff --git a/src/plugins/qmldesigner/libs/designsystem/designsystem_global.h b/src/plugins/qmldesigner/libs/designsystem/designsystem_global.h new file mode 100644 index 00000000000..835c8b0ad3d --- /dev/null +++ b/src/plugins/qmldesigner/libs/designsystem/designsystem_global.h @@ -0,0 +1,14 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +#if defined(DESIGNSYSTEM_LIBRARY) +# define DESIGNSYSTEM_EXPORT Q_DECL_EXPORT +#elif defined(DESIGNSYSTEM_STATIC_LIBRARY) +# define DESIGNSYSTEM_EXPORT +#else +# define DESIGNSYSTEM_EXPORT Q_DECL_IMPORT +#endif diff --git a/src/plugins/qmldesigner/components/designsystem/dsconstants.h b/src/plugins/qmldesigner/libs/designsystem/dsconstants.h similarity index 100% rename from src/plugins/qmldesigner/components/designsystem/dsconstants.h rename to src/plugins/qmldesigner/libs/designsystem/dsconstants.h diff --git a/src/plugins/qmldesigner/components/designsystem/dsthemegroup.cpp b/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.cpp similarity index 100% rename from src/plugins/qmldesigner/components/designsystem/dsthemegroup.cpp rename to src/plugins/qmldesigner/libs/designsystem/dsthemegroup.cpp diff --git a/src/plugins/qmldesigner/components/designsystem/dsthemegroup.h b/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.h similarity index 94% rename from src/plugins/qmldesigner/components/designsystem/dsthemegroup.h rename to src/plugins/qmldesigner/libs/designsystem/dsthemegroup.h index b76e2f3d504..e61a915623e 100644 --- a/src/plugins/qmldesigner/components/designsystem/dsthemegroup.h +++ b/src/plugins/qmldesigner/libs/designsystem/dsthemegroup.h @@ -2,7 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 #pragma once -#include "qmldesignercomponents_global.h" +#include "designsystem_global.h" #include "dsconstants.h" #include "nodeinstanceglobal.h" @@ -18,7 +18,7 @@ enum class DECORATION_CONTEXT { COMPONENT_THEME, }; -class QMLDESIGNERCOMPONENTS_EXPORT DSThemeGroup +class DESIGNSYSTEM_EXPORT DSThemeGroup { struct PropertyData { diff --git a/src/plugins/qmldesigner/components/designsystem/dsthememanager.cpp b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp similarity index 100% rename from src/plugins/qmldesigner/components/designsystem/dsthememanager.cpp rename to src/plugins/qmldesigner/libs/designsystem/dsthememanager.cpp diff --git a/src/plugins/qmldesigner/components/designsystem/dsthememanager.h b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h similarity index 94% rename from src/plugins/qmldesigner/components/designsystem/dsthememanager.h rename to src/plugins/qmldesigner/libs/designsystem/dsthememanager.h index e3ac9e2e4c9..0972dcd7893 100644 --- a/src/plugins/qmldesigner/components/designsystem/dsthememanager.h +++ b/src/plugins/qmldesigner/libs/designsystem/dsthememanager.h @@ -3,7 +3,7 @@ #pragma once -#include "qmldesignercomponents_global.h" +#include "designsystem_global.h" #include "dsconstants.h" #include "dsthemegroup.h" @@ -15,7 +15,8 @@ namespace QmlDesigner { using ThemeName = PropertyName; class DSTheme; -class QMLDESIGNERCOMPONENTS_EXPORT DSThemeManager + +class DESIGNSYSTEM_EXPORT DSThemeManager { public: diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h index 116dc94dcca..8aef417b3bc 100644 --- a/src/plugins/qmldesigner/qmldesignerconstants.h +++ b/src/plugins/qmldesigner/qmldesignerconstants.h @@ -140,6 +140,18 @@ inline constexpr char EVENT_TOOLBAR_SET_CURRENT_WORKSPACE[] = "ToolBarSetCurrent inline constexpr char EVENT_TOOLBAR_EDIT_GLOBAL_ANNOTATION[] = "ToolBarEditGlobalAnnotation"; inline constexpr char EVENT_STATUSBAR_SHOW_ZOOM[] = "StatusBarShowZoomMenu"; inline constexpr char EVENT_STATUSBAR_SET_STYLE[] = "StatusBarSetCurrentStyle"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_UPLOADED[] = "DesignViewerProjectUploaded"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_DOWNLOADED[] = "DesignViewerProjectDownloaded"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_DELETED[] = "DesignViewerProjectDeleted"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_SHARED[] = "DesignViewerProjectShared"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_UNSHARED[] = "DesignViewerProjectUnshared"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_UNSHARED_ALL[] = "DesignViewerProjectUnsharedAll"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_THUMBNAIL_UPLOADED[] + = "DesignViewerProjectThumbnailUploaded"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_THUMBNAIL_DELETED[] + = "DesignViewerProjectThumbnailDeleted"; +inline constexpr char EVENT_DESIGNVIEWER_PROJECT_THUMBNAIL_DOWNLOADED[] + = "DesignViewerProjectThumbnailDownloaded"; inline constexpr char PROPERTY_EDITOR_CLASSNAME_PROPERTY[] = "__classNamePrivateInternal"; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 2913a8e6f6d..97621d53936 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -702,6 +702,11 @@ Internal::DesignModeWidget *QmlDesignerPlugin::mainWidget() const return d ? &d->mainWidget : nullptr; } +QmlDesignerProjectManager &QmlDesignerPlugin::projectManagerForPluginInitializationOnly() +{ + return m_instance->d->projectManager; +} + QWidget *QmlDesignerPlugin::createProjectExplorerWidget(QWidget *parent) const { return Internal::DesignModeWidget::createProjectExplorerWidget(parent); diff --git a/src/plugins/qmldesigner/qmldesignerplugin.h b/src/plugins/qmldesigner/qmldesignerplugin.h index 8039251b99b..bdb45cc8f42 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.h +++ b/src/plugins/qmldesigner/qmldesignerplugin.h @@ -60,6 +60,8 @@ public: DesignDocument *currentDesignDocument() const; Internal::DesignModeWidget *mainWidget() const; + static QmlDesignerProjectManager &projectManagerForPluginInitializationOnly(); + QWidget *createProjectExplorerWidget(QWidget *parent) const; void switchToTextModeDeferred(); diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp index 6bba6c12369..9c04f9b1bd3 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp @@ -202,7 +202,7 @@ public: FileStatusCache fileStatusCache{fileSystem}; QmlDocumentParser qmlDocumentParser; QmlTypesParser qmlTypesParser{storage}; - ProjectStoragePathWatcher pathWatcher; + ProjectStoragePathWatcher pathWatcher; ProjectPartId projectPartId; ProjectStorageUpdater updater; }; @@ -265,7 +265,7 @@ public: Sqlite::LockingMode::Normal}; QmlDesigner::SourcePathStorage sourcePathStorage{sourcePathDatabase, sourcePathDatabase.isInitialized()}; - PathCacheType pathCache{sourcePathStorage}; + PathCache pathCache{sourcePathStorage}; }; QmlDesignerProjectManager::QmlDesignerProjectManager(ExternalDependenciesInterface &externalDependencies) @@ -322,12 +322,12 @@ AsynchronousImageCache &QmlDesignerProjectManager::asynchronousImageCache() } namespace { -[[maybe_unused]] ProjectStorage *dummyProjectStorage() +[[maybe_unused]] ProjectStorageType *dummyProjectStorage() { return nullptr; } -[[maybe_unused]] ProjectStorageUpdater::PathCache *dummyPathCache() +[[maybe_unused]] PathCacheType *dummyPathCache() { return nullptr; } diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.h b/src/plugins/qmldesigner/qmldesignerprojectmanager.h index 10c0bd42618..4947dbcd437 100644 --- a/src/plugins/qmldesigner/qmldesignerprojectmanager.h +++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.h @@ -5,6 +5,7 @@ #include "modelfwd.h" #include +#include #include #include @@ -28,7 +29,7 @@ namespace QmlDesigner { class ExternalDependenciesInterface; -class QmlDesignerProjectManager +class QMLDESIGNER_EXPORT QmlDesignerProjectManager { class QmlDesignerProjectManagerProjectData; class PreviewImageCacheData; diff --git a/src/plugins/studiowelcome/CMakeLists.txt b/src/plugins/studiowelcome/CMakeLists.txt index c4db40db5e9..ead7b757893 100644 --- a/src/plugins/studiowelcome/CMakeLists.txt +++ b/src/plugins/studiowelcome/CMakeLists.txt @@ -4,6 +4,7 @@ add_qtc_plugin(StudioWelcome PLUGIN_DEPENDS Core ProjectExplorer QtSupport QmlDesigner DEFINES STUDIO_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/qml/" SOURCES + fieldhelper.cpp fieldhelper.h studiowelcomeplugin.cpp studiowelcomeplugin.h newprojectdialogimageprovider.cpp newprojectdialogimageprovider.h presetmodel.cpp presetmodel.h diff --git a/src/plugins/studiowelcome/createproject.cpp b/src/plugins/studiowelcome/createproject.cpp index 6ed783780cb..5ed59a339e4 100644 --- a/src/plugins/studiowelcome/createproject.cpp +++ b/src/plugins/studiowelcome/createproject.cpp @@ -43,6 +43,9 @@ void CreateProject::processFieldPage(ProjectExplorer::JsonFieldPage *page) if (page->jsonField("UseVirtualKeyboard")) m_wizard.setUseVirtualKeyboard(m_useVirtualKeyboard); + if (page->jsonField("EnableCMakeGeneration")) + m_wizard.enableCMakeGeneration(m_enableCMakeGeneration); + auto widthField = dynamic_cast(page->jsonField("CustomScreenWidth")); auto heightField = dynamic_cast(page->jsonField("CustomScreenHeight")); diff --git a/src/plugins/studiowelcome/createproject.h b/src/plugins/studiowelcome/createproject.h index e1b0af34205..b9abe2d2edb 100644 --- a/src/plugins/studiowelcome/createproject.h +++ b/src/plugins/studiowelcome/createproject.h @@ -28,6 +28,11 @@ public: CreateProject &withStyle(int styleIndex) { m_styleIndex = styleIndex; return *this; } CreateProject &useQtVirtualKeyboard(bool value) { m_useVirtualKeyboard = value; return *this; } + CreateProject &enableCMakeGeneration(bool value) + { + m_enableCMakeGeneration = value; + return *this; + } CreateProject &saveAsDefaultLocation(bool value) { m_saveAsDefaultLocation = value; return *this; } CreateProject &withTargetQtVersion(int targetQtVersionIndex) { m_targetQtVersionIndex = targetQtVersionIndex; return *this; } @@ -48,6 +53,7 @@ private: QString m_customHeight; int m_styleIndex = -1; bool m_useVirtualKeyboard = false; + bool m_enableCMakeGeneration = false; bool m_saveAsDefaultLocation = false; int m_targetQtVersionIndex = -1; }; diff --git a/src/plugins/studiowelcome/fieldhelper.cpp b/src/plugins/studiowelcome/fieldhelper.cpp new file mode 100644 index 00000000000..5fdf3532be3 --- /dev/null +++ b/src/plugins/studiowelcome/fieldhelper.cpp @@ -0,0 +1,89 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "fieldhelper.h" + +#include +#include + +#include + +using namespace StudioWelcome::FieldHelper; + +CheckBoxHelper::CheckBoxHelper(ProjectExplorer::JsonFieldPage *detailsPage, const QString &fieldName) + : m_field(dynamic_cast(detailsPage->jsonField(fieldName))) +{} + +void CheckBoxHelper::setChecked(bool value) +{ + QTC_ASSERT(m_field, return); + + m_field->setChecked(value); +} + +ComboBoxHelper::ComboBoxHelper(ProjectExplorer::JsonFieldPage *detailsPage, const QString &fieldName) + : m_field(dynamic_cast(detailsPage->jsonField(fieldName))) +{} + +void ComboBoxHelper::selectIndex(int index) +{ + QTC_ASSERT(m_field, return); + + m_field->selectRow(index); +} + +QString ComboBoxHelper::text(int index) const +{ + QTC_ASSERT(m_field, return {}); + + QStandardItemModel *model = m_field->model(); + if (index < 0 || index >= model->rowCount()) + return {}; + + return model->item(index)->text(); +} + +int ComboBoxHelper::indexOf(const QString &text) const +{ + QTC_ASSERT(m_field, return -1); + + const QStandardItemModel *model = m_field->model(); + for (int i = 0; i < model->rowCount(); ++i) { + const QStandardItem *item = model->item(i, 0); + const QString text = item->text(); + + if (text == text) + return i; + } + + return -1; +} + +int ComboBoxHelper::selectedIndex() const +{ + QTC_ASSERT(m_field, return -1); + + return m_field->selectedRow(); +} + +QStandardItemModel *ComboBoxHelper::model() const +{ + QTC_ASSERT(m_field, return {}); + + return m_field->model(); +} + +QStringList ComboBoxHelper::allTexts() const +{ + QTC_ASSERT(m_field, return {}); + + QStandardItemModel *model = m_field->model(); + const int rows = model->rowCount(); + QStringList result; + result.reserve(rows); + + for (int i = 0; i < rows; ++i) + result.append(model->item(i)->text()); + + return result; +} diff --git a/src/plugins/studiowelcome/fieldhelper.h b/src/plugins/studiowelcome/fieldhelper.h new file mode 100644 index 00000000000..886e49d0df8 --- /dev/null +++ b/src/plugins/studiowelcome/fieldhelper.h @@ -0,0 +1,46 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include + +QT_FORWARD_DECLARE_CLASS(QStandardItemModel) + +namespace ProjectExplorer { +class JsonFieldPage; +class CheckBoxField; +class ComboBoxField; +} + +namespace StudioWelcome::FieldHelper { + +class CheckBoxHelper +{ +public: + CheckBoxHelper(ProjectExplorer::JsonFieldPage *detailsPage, const QString &fieldName); + + void setChecked(bool value); + +private: + ProjectExplorer::CheckBoxField *m_field = nullptr; +}; + +class ComboBoxHelper +{ +public: + ComboBoxHelper(ProjectExplorer::JsonFieldPage *detailsPage, const QString &fieldName); + + void selectIndex(int index); + + QString text(int index) const; + int indexOf(const QString &text) const; + int selectedIndex() const; + QStandardItemModel *model() const; + QStringList allTexts() const; + +private: + ProjectExplorer::ComboBoxField *m_field = nullptr; +}; + +} // namespace StudioWelcome::FieldHelper diff --git a/src/plugins/studiowelcome/presetmodel.cpp b/src/plugins/studiowelcome/presetmodel.cpp index 06e8def612b..e4562872b7a 100644 --- a/src/plugins/studiowelcome/presetmodel.cpp +++ b/src/plugins/studiowelcome/presetmodel.cpp @@ -93,6 +93,7 @@ PresetItems PresetData::makeUserPresets(const PresetItems &wizardPresets, presetItem->qtVersion = userPresetData.qtVersion; presetItem->styleName = userPresetData.styleName; presetItem->useQtVirtualKeyboard = userPresetData.useQtVirtualKeyboard; + presetItem->enableCMakeGeneration = userPresetData.enableCMakeGeneration; presetItem->create = foundPreset->create; presetItem->description = foundPreset->description; diff --git a/src/plugins/studiowelcome/presetmodel.h b/src/plugins/studiowelcome/presetmodel.h index f23ec2ea778..94f11fb9aff 100644 --- a/src/plugins/studiowelcome/presetmodel.h +++ b/src/plugins/studiowelcome/presetmodel.h @@ -80,6 +80,7 @@ struct UserPresetItem : public PresetItem public: QString userName; bool useQtVirtualKeyboard; + bool enableCMakeGeneration; QString qtVersion; QString styleName; }; diff --git a/src/plugins/studiowelcome/qdsnewdialog.cpp b/src/plugins/studiowelcome/qdsnewdialog.cpp index 1fa82e55034..1032e7fceea 100644 --- a/src/plugins/studiowelcome/qdsnewdialog.cpp +++ b/src/plugins/studiowelcome/qdsnewdialog.cpp @@ -133,6 +133,15 @@ void QdsNewDialog::setProjectLocation(const QString &location) m_wizard.setProjectLocation(m_qmlProjectLocation); } +void QdsNewDialog::setHasCMakeGeneration(bool haveCmakeGen) +{ + if (m_qmlHasCMakeGeneration == haveCmakeGen) + return; + + m_qmlHasCMakeGeneration = haveCmakeGen; + emit hasCMakeGenerationChanged(); +} + void QdsNewDialog::onStatusMessageChanged(Utils::InfoLabel::InfoType type, const QString &message) { switch (type) { @@ -192,9 +201,16 @@ void QdsNewDialog::onWizardCreated(QStandardItemModel *screenSizeModel, QStandar auto userPreset = m_currentPreset->asUserPreset(); if (m_qmlDetailsLoaded) { + setHasCMakeGeneration(m_wizard.hasCMakeGeneration()); + + if (m_currentPreset->isUserPreset()) { + if (getHaveVirtualKeyboard()) + setUseVirtualKeyboard(userPreset->useQtVirtualKeyboard); + if (hasCMakeGeneration()) + setEnableCMakeGeneration(userPreset->enableCMakeGeneration); + } + m_targetQtVersions.clear(); - if (m_currentPreset->isUserPreset() && m_wizard.haveVirtualKeyboard()) - setUseVirtualKeyboard(userPreset->useQtVirtualKeyboard); if (m_wizard.haveTargetQtVersion()) { m_targetQtVersions = m_wizard.targetQtVersionNames(); int index = m_currentPreset->isUserPreset() ? m_wizard.targetQtVersionIndex(userPreset->qtVersion) @@ -227,6 +243,15 @@ void QdsNewDialog::onWizardCreated(QStandardItemModel *screenSizeModel, QStandar } } +void QdsNewDialog::setEnableCMakeGeneration(bool newQmlEnableCMakeGeneration) +{ + if (m_qmlEnableCMakeGeneration == newQmlEnableCMakeGeneration) + return; + + m_qmlEnableCMakeGeneration = newQmlEnableCMakeGeneration; + emit enableCMakeGenerationChanged(); +} + QString QdsNewDialog::currentPresetQmlPath() const { if (!m_currentPreset || m_currentPreset->qmlPath.isEmpty()) @@ -385,6 +410,11 @@ bool QdsNewDialog::getHaveTargetQtVersion() const return m_wizard.haveTargetQtVersion(); } +bool QdsNewDialog::hasCMakeGeneration() const +{ + return m_qmlHasCMakeGeneration; +} + void QdsNewDialog::accept() { CreateProject create{m_wizard}; @@ -395,6 +425,7 @@ void QdsNewDialog::accept() .withScreenSizes(m_qmlScreenSizeIndex, m_qmlCustomWidth, m_qmlCustomHeight) .withStyle(getStyleIndex()) .useQtVirtualKeyboard(m_qmlUseVirtualKeyboard) + .enableCMakeGeneration(m_qmlEnableCMakeGeneration) .saveAsDefaultLocation(m_qmlSaveAsDefaultLocation) .withTargetQtVersion(m_qmlTargetQtVersionIndex) .execute(); @@ -446,6 +477,7 @@ UserPresetData QdsNewDialog::currentUserPresetData(const QString &displayName) c QString targetQtVersion = ""; QString styleName = ""; bool useVirtualKeyboard = false; + bool enableCMakeGeneration = false; if (m_wizard.haveTargetQtVersion()) targetQtVersion = m_wizard.targetQtVersionName(m_qmlTargetQtVersionIndex); @@ -456,13 +488,18 @@ UserPresetData QdsNewDialog::currentUserPresetData(const QString &displayName) c if (m_wizard.haveVirtualKeyboard()) useVirtualKeyboard = m_qmlUseVirtualKeyboard; - UserPresetData preset = {m_currentPreset->categoryId, - m_currentPreset->wizardName, - displayName, - screenSize, - useVirtualKeyboard, - targetQtVersion, - styleName}; + if (m_wizard.hasCMakeGeneration()) + enableCMakeGeneration = m_qmlEnableCMakeGeneration; + + UserPresetData preset{ + m_currentPreset->categoryId, + m_currentPreset->wizardName, + displayName, + screenSize, + useVirtualKeyboard, + enableCMakeGeneration, + targetQtVersion, + styleName}; return preset; } diff --git a/src/plugins/studiowelcome/qdsnewdialog.h b/src/plugins/studiowelcome/qdsnewdialog.h index 95bfa52fe9b..b5aee2ff065 100644 --- a/src/plugins/studiowelcome/qdsnewdialog.h +++ b/src/plugins/studiowelcome/qdsnewdialog.h @@ -34,7 +34,13 @@ public: Q_PROPERTY(QString customHeight MEMBER m_qmlCustomHeight) Q_PROPERTY(int styleIndex MEMBER m_qmlStyleIndex READ getStyleIndex WRITE setStyleIndex) Q_PROPERTY(bool useVirtualKeyboard MEMBER m_qmlUseVirtualKeyboard READ getUseVirtualKeyboard WRITE setUseVirtualKeyboard NOTIFY useVirtualKeyboardChanged) + Q_PROPERTY( + bool enableCMakeGeneration + MEMBER m_qmlEnableCMakeGeneration + WRITE setEnableCMakeGeneration + NOTIFY enableCMakeGenerationChanged) Q_PROPERTY(bool haveVirtualKeyboard MEMBER m_qmlHaveVirtualKeyboard READ getHaveVirtualKeyboard NOTIFY haveVirtualKeyboardChanged) + Q_PROPERTY(bool hasCMakeGeneration READ hasCMakeGeneration NOTIFY hasCMakeGenerationChanged) Q_PROPERTY(bool haveTargetQtVersion MEMBER m_qmlHaveTargetQtVersion READ getHaveTargetQtVersion NOTIFY haveTargetQtVersionChanged) Q_PROPERTY(int targetQtVersionIndex MEMBER m_qmlTargetQtVersionIndex READ getTargetQtVersionIndex WRITE setTargetQtVersionIndex NOTIFY targetQtVersionIndexChanged) Q_PROPERTY(bool saveAsDefaultLocation MEMBER m_qmlSaveAsDefaultLocation WRITE setSaveAsDefaultLocation) @@ -85,12 +91,15 @@ public: bool getFieldsValid() const { return m_qmlFieldsValid; } bool getHaveVirtualKeyboard() const; bool getHaveTargetQtVersion() const; + bool hasCMakeGeneration() const; void setSaveAsDefaultLocation(bool value) { m_qmlSaveAsDefaultLocation = value; } QString getStatusMessage() const { return m_qmlStatusMessage; } QString getStatusType() const { return m_qmlStatusType; } + void setEnableCMakeGeneration(bool newQmlEnableCMakeGeneration); + public slots: void accept(); void reject(); @@ -102,7 +111,9 @@ signals: void projectLocationChanged(); void projectDescriptionChanged(); void useVirtualKeyboardChanged(); + void enableCMakeGenerationChanged(); void haveVirtualKeyboardChanged(); + void hasCMakeGenerationChanged(); void haveTargetQtVersionChanged(); void statusMessageChanged(); void statusTypeChanged(); @@ -129,6 +140,8 @@ private: emit projectDescriptionChanged(); } + void setHasCMakeGeneration(bool haveCmakeGen); + QString projectDescription() const { return m_qmlProjectDescription; } void updateScreenSizes(); @@ -156,7 +169,9 @@ private: // m_qmlStyleIndex is like a cache, so it needs to be updated on get() mutable int m_qmlStyleIndex = -1; bool m_qmlUseVirtualKeyboard = false; + bool m_qmlEnableCMakeGeneration = false; bool m_qmlHaveVirtualKeyboard = false; + bool m_qmlHasCMakeGeneration = false; bool m_qmlHaveTargetQtVersion = false; bool m_qmlSaveAsDefaultLocation = false; bool m_qmlFieldsValid = false; diff --git a/src/plugins/studiowelcome/userpresets.cpp b/src/plugins/studiowelcome/userpresets.cpp index ddc8a406261..cd551f5efe0 100644 --- a/src/plugins/studiowelcome/userpresets.cpp +++ b/src/plugins/studiowelcome/userpresets.cpp @@ -67,13 +67,16 @@ void UserPresetsStore::savePresets(const std::vector &presetItem QJsonArray jsonArray; for (const auto &preset : presetItems) { - QJsonObject obj({{"categoryId", preset.categoryId}, - {"wizardName", preset.wizardName}, - {"name", preset.name}, - {"screenSize", preset.screenSize}, - {"useQtVirtualKeyboard", preset.useQtVirtualKeyboard}, - {"qtVersion", preset.qtVersion}, - {"styleName", preset.styleName}}); + QJsonObject obj{ + {"categoryId", preset.categoryId}, + {"wizardName", preset.wizardName}, + {"name", preset.name}, + {"screenSize", preset.screenSize}, + {"useQtVirtualKeyboard", preset.useQtVirtualKeyboard}, + {"enableCMakeGeneration", preset.enableCMakeGeneration}, + {"qtVersion", preset.qtVersion}, + {"styleName", preset.styleName}, + }; jsonArray.append(QJsonValue{obj}); } @@ -164,6 +167,7 @@ std::vector UserPresetsStore::fetchAll() const preset.name = obj["name"].toString(); preset.screenSize = obj["screenSize"].toString(); preset.useQtVirtualKeyboard = obj["useQtVirtualKeyboard"].toBool(); + preset.enableCMakeGeneration = obj["enableCMakeGeneration"].toBool(); preset.qtVersion = obj["qtVersion"].toString(); preset.styleName = obj["styleName"].toString(); diff --git a/src/plugins/studiowelcome/userpresets.h b/src/plugins/studiowelcome/userpresets.h index 6ea15e8b60f..ae6686279d8 100644 --- a/src/plugins/studiowelcome/userpresets.h +++ b/src/plugins/studiowelcome/userpresets.h @@ -20,6 +20,7 @@ struct UserPresetData QString screenSize; bool useQtVirtualKeyboard; + bool enableCMakeGeneration; QString qtVersion; QString styleName; @@ -36,6 +37,7 @@ inline QDebug &operator<<(QDebug &d, const UserPresetData &preset) d << "UserPreset{category = " << preset.categoryId; d << "; wizardName = " << preset.wizardName; d << "; name = " << preset.name; + d << "; cmakeGeneration = " << preset.enableCMakeGeneration; d << "; screenSize = " << preset.screenSize; d << "; keyboard = " << preset.useQtVirtualKeyboard; d << "; qt = " << preset.qtVersion; @@ -48,9 +50,10 @@ inline QDebug &operator<<(QDebug &d, const UserPresetData &preset) inline bool operator==(const UserPresetData &lhs, const UserPresetData &rhs) { return lhs.categoryId == rhs.categoryId && lhs.wizardName == rhs.wizardName - && lhs.name == rhs.name && lhs.screenSize == rhs.screenSize + && lhs.enableCMakeGeneration == rhs.enableCMakeGeneration && lhs.name == rhs.name + && lhs.screenSize == rhs.screenSize && lhs.useQtVirtualKeyboard == rhs.useQtVirtualKeyboard && lhs.qtVersion == rhs.qtVersion - && lhs.styleName == rhs.styleName;; + && lhs.styleName == rhs.styleName; } enum class StorePolicy {UniqueNames, UniqueValues}; diff --git a/src/plugins/studiowelcome/wizardhandler.cpp b/src/plugins/studiowelcome/wizardhandler.cpp index b86d33a1dfb..a1882f50a2e 100644 --- a/src/plugins/studiowelcome/wizardhandler.cpp +++ b/src/plugins/studiowelcome/wizardhandler.cpp @@ -1,20 +1,21 @@ // Copyright (C) 2021 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 -#include -#include - #include "wizardhandler.h" +#include "fieldhelper.h" #include #include - #include #include #include +#include +#include + using namespace StudioWelcome; +using namespace StudioWelcome::FieldHelper; void WizardHandler::reset(const std::shared_ptr &presetInfo, int presetSelection) { @@ -57,8 +58,8 @@ void WizardHandler::setupWizard() emit wizardCreationFailed(); return; } - auto *screenFactorModel = getScreenFactorModel(m_detailsPage); - auto *styleModel = getStyleModel(m_detailsPage); + auto *screenFactorModel = getScreenFactorModel(); + auto *styleModel = getStyleModel(); emit wizardCreated(screenFactorModel, styleModel); } @@ -105,16 +106,9 @@ void WizardHandler::initializeFieldsPage(QWizardPage *page) fieldsPage->initializePage(); } -QStandardItemModel *WizardHandler::getScreenFactorModel(ProjectExplorer::JsonFieldPage *page) +QStandardItemModel *WizardHandler::getScreenFactorModel() { - auto *field = page->jsonField("ScreenFactor"); - if (!field) - return nullptr; - - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return nullptr); - - return cbfield->model(); + return ComboBoxHelper(m_detailsPage, "ScreenFactor").model(); } bool WizardHandler::haveStyleModel() const @@ -122,16 +116,9 @@ bool WizardHandler::haveStyleModel() const return m_wizard->hasField("ControlsStyle"); } -QStandardItemModel *WizardHandler::getStyleModel(ProjectExplorer::JsonFieldPage *page) +QStandardItemModel *WizardHandler::getStyleModel() { - auto *field = page->jsonField("ControlsStyle"); - if (!field) - return nullptr; - - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return nullptr); - - return cbfield->model(); + return ComboBoxHelper(m_detailsPage, "ControlsStyle").model(); } void WizardHandler::onWizardResetting() @@ -147,61 +134,27 @@ void WizardHandler::onWizardResetting() void WizardHandler::setScreenSizeIndex(int index) { - auto *field = m_detailsPage->jsonField("ScreenFactor"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return); - - cbfield->selectRow(index); + ComboBoxHelper(m_detailsPage, "ScreenFactor").selectIndex(index); } QString WizardHandler::screenSizeName(int index) const { - auto *field = m_detailsPage->jsonField("ScreenFactor"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return ""); - - QStandardItemModel *model = cbfield->model(); - if (index < 0 || index >= model->rowCount()) - return {}; - - QString text = model->item(index)->text(); - return text; + return ComboBoxHelper(m_detailsPage, "ScreenFactor").text(index); } int WizardHandler::screenSizeIndex() const { - auto *field = m_detailsPage->jsonField("ScreenFactor"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return -1); - - return cbfield->selectedRow(); + return ComboBoxHelper(m_detailsPage, "ScreenFactor").selectedIndex(); } int WizardHandler::screenSizeIndex(const QString &sizeName) const { - auto *field = m_detailsPage->jsonField("ScreenFactor"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return false); - - const QStandardItemModel *model = cbfield->model(); - for (int i = 0; i < model->rowCount(); ++i) { - const QStandardItem *item = model->item(i, 0); - const QString text = item->text(); - - if (text == sizeName) - return i; - } - - return -1; + return ComboBoxHelper(m_detailsPage, "ScreenFactor").indexOf(sizeName); } void WizardHandler::setTargetQtVersionIndex(int index) { - auto *field = m_detailsPage->jsonField("TargetQtVersion"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return); - - cbfield->selectRow(index); + ComboBoxHelper(m_detailsPage, "TargetQtVersion").selectIndex(index); } bool WizardHandler::haveTargetQtVersion() const @@ -211,117 +164,47 @@ bool WizardHandler::haveTargetQtVersion() const QString WizardHandler::targetQtVersionName(int index) const { - auto *field = m_detailsPage->jsonField("TargetQtVersion"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return ""); - - QStandardItemModel *model = cbfield->model(); - if (index < 0 || index >= model->rowCount()) - return {}; - - QString text = model->item(index)->text(); - return text; + return ComboBoxHelper(m_detailsPage, "TargetQtVersion").text(index); } QStringList WizardHandler::targetQtVersionNames() const { - auto *field = m_detailsPage->jsonField("TargetQtVersion"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return {}); - - QStandardItemModel *model = cbfield->model(); - QStringList targetVersions; - - for (int i = 0; i < model->rowCount(); ++i) - targetVersions.append(model->item(i)->text()); - - return targetVersions; + return ComboBoxHelper(m_detailsPage, "TargetQtVersion").allTexts(); } int WizardHandler::targetQtVersionIndex(const QString &qtVersionName) const { - auto *field = m_detailsPage->jsonField("TargetQtVersion"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return -1); - - const QStandardItemModel *model = cbfield->model(); - for (int i = 0; i < model->rowCount(); ++i) { - const QStandardItem *item = model->item(i, 0); - const QString text = item->text(); - - if (text == qtVersionName) - return i; - } - - return -1; + return ComboBoxHelper(m_detailsPage, "TargetQtVersion").indexOf(qtVersionName); } int WizardHandler::targetQtVersionIndex() const { - auto *field = m_detailsPage->jsonField("TargetQtVersion"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return -1); - - return cbfield->selectedRow(); + return ComboBoxHelper(m_detailsPage, "TargetQtVersion").selectedIndex(); } void WizardHandler::setStyleIndex(int index) { - auto *field = m_detailsPage->jsonField("ControlsStyle"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return); - - cbfield->selectRow(index); + ComboBoxHelper(m_detailsPage, "ControlsStyle").selectIndex(index); } int WizardHandler::styleIndex() const { - auto *field = m_detailsPage->jsonField("ControlsStyle"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return -1); - - return cbfield->selectedRow(); + return ComboBoxHelper(m_detailsPage, "ControlsStyle").selectedIndex(); } int WizardHandler::styleIndex(const QString &styleName) const { - auto *field = m_detailsPage->jsonField("ControlsStyle"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return -1); - - const QStandardItemModel *model = cbfield->model(); - for (int i = 0; i < model->rowCount(); ++i) { - const QStandardItem *item = model->item(i, 0); - const QString text = item->text(); - - if (text == styleName) - return i; - } - - return -1; + return ComboBoxHelper(m_detailsPage, "ControlsStyle").indexOf(styleName); } QString WizardHandler::styleName(int index) const { - auto *field = m_detailsPage->jsonField("ControlsStyle"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return ""); - - QStandardItemModel *model = cbfield->model(); - if (index < 0 || index >= model->rowCount()) - return {}; - - QString text = model->item(index)->text(); - return text; + return ComboBoxHelper(m_detailsPage, "ControlsStyle").text(index); } void WizardHandler::setUseVirtualKeyboard(bool value) { - auto *field = m_detailsPage->jsonField("UseVirtualKeyboard"); - auto *cbfield = dynamic_cast(field); - QTC_ASSERT(cbfield, return); - - cbfield->setChecked(value); + CheckBoxHelper(m_detailsPage, "UseVirtualKeyboard").setChecked(value); } bool WizardHandler::haveVirtualKeyboard() const @@ -329,6 +212,16 @@ bool WizardHandler::haveVirtualKeyboard() const return m_wizard->hasField("UseVirtualKeyboard"); } +void WizardHandler::enableCMakeGeneration(bool value) +{ + CheckBoxHelper(m_detailsPage, "EnableCMakeGeneration").setChecked(value); +} + +bool WizardHandler::hasCMakeGeneration() const +{ + return m_wizard->hasField("EnableCMakeGeneration"); +} + void WizardHandler::run(const std::function &processPage) { m_wizard->restart(); diff --git a/src/plugins/studiowelcome/wizardhandler.h b/src/plugins/studiowelcome/wizardhandler.h index e6009dd9362..640ebb41342 100644 --- a/src/plugins/studiowelcome/wizardhandler.h +++ b/src/plugins/studiowelcome/wizardhandler.h @@ -48,6 +48,9 @@ public: void setUseVirtualKeyboard(bool value); bool haveVirtualKeyboard() const; + void enableCMakeGeneration(bool value); + bool hasCMakeGeneration() const; + void setProjectName(const QString &name); void setProjectLocation(const Utils::FilePath &location); @@ -67,8 +70,8 @@ private: void initializeProjectPage(QWizardPage *page); void initializeFieldsPage(QWizardPage *page); - QStandardItemModel *getScreenFactorModel(ProjectExplorer::JsonFieldPage *page); - QStandardItemModel *getStyleModel(ProjectExplorer::JsonFieldPage *page); + QStandardItemModel *getScreenFactorModel(); + QStandardItemModel *getStyleModel(); private slots: void onWizardResetting(); diff --git a/src/tools/qml2puppet/mockfiles/qt6/EditView3D.qml b/src/tools/qml2puppet/mockfiles/qt6/EditView3D.qml index e159b532c34..c4cae6c5c2d 100644 --- a/src/tools/qml2puppet/mockfiles/qt6/EditView3D.qml +++ b/src/tools/qml2puppet/mockfiles/qt6/EditView3D.qml @@ -971,10 +971,6 @@ Item { } } - DropArea { - anchors.fill: parent - } - Overlay2D { id: gizmoLabel targetNode: activeOverlayView.moveGizmo.visible ? activeOverlayView.moveGizmo diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp index 4d57c0d1646..19c50cfba0a 100644 --- a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp +++ b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp @@ -704,7 +704,16 @@ bool GeneralHelper::isSceneObject(QQuick3DNode *node) const const QQuick3DObject *sceneObject = importSceneManager->m_nodeMap.value(objectPrivate->spatialNode, nullptr); - return sceneObject != nullptr; + if (!sceneObject) + return false; + + QQuick3DNode *parentNode = node->parentNode(); + while (parentNode) { + if (parentNode->inherits("QQuick3DSceneRootNode")) + return true; + parentNode = parentNode->parentNode(); + } + return false; } // Emitter gizmo model creation is done in C++ as creating dynamic properties and diff --git a/tests/unit/tests/printers/gtest-creator-printing.cpp b/tests/unit/tests/printers/gtest-creator-printing.cpp index fac58b7bd90..d7a63fe6900 100644 --- a/tests/unit/tests/printers/gtest-creator-printing.cpp +++ b/tests/unit/tests/printers/gtest-creator-printing.cpp @@ -656,6 +656,9 @@ std::ostream &operator<<(std::ostream &out, TypeTraits traits) if (traits.visibleInLibrary != QmlDesigner::FlagIs::False) out << " | visibleInLibrary(" << traits.visibleInLibrary << ")"; + if (traits.hideInNavigator != QmlDesigner::FlagIs::False) + out << " | hideInNavigator(" << traits.hideInNavigator << ")"; + return out << ")"; } diff --git a/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp index b17a38098ee..f3f55136f27 100644 --- a/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp +++ b/tests/unit/tests/unittests/metainfo/nodemetainfo-test.cpp @@ -3061,6 +3061,43 @@ TEST_F(NodeMetaInfo, invalid_is_not_visible_in_library) ASSERT_THAT(visibleInLibrary, FlagIs::False); } +TEST_F(NodeMetaInfo, object_is_not_hide_in_navigator) +{ + auto hideInNavigator = objectMetaInfo.hideInNavigator(); + + ASSERT_THAT(hideInNavigator, FlagIs::False); +} + +TEST_F(NodeMetaInfo, default_is_not_hide_in_navigator) +{ + auto hideInNavigator = QmlDesigner::NodeMetaInfo{}.hideInNavigator(); + + ASSERT_THAT(hideInNavigator, FlagIs::False); +} + +TEST_F(NodeMetaInfo, invalid_is_not_hide_in_navigator) +{ + auto node = model.createModelNode("Foo"); + auto metaInfo = node.metaInfo(); + + auto hideInNavigator = metaInfo.hideInNavigator(); + + ASSERT_THAT(hideInNavigator, FlagIs::False); +} + +TEST_F(NodeMetaInfo, component_is_hide_in_navigator) +{ + auto moduleId = projectStorageMock.createModule("/path/to/project", ModuleKind::PathLibrary); + TypeTraits traits{TypeTraitsKind::Reference}; + traits.hideInNavigator = FlagIs::True; + auto typeId = projectStorageMock.createType(moduleId, "Foo", traits); + QmlDesigner::NodeMetaInfo metaInfo{typeId, &projectStorageMock}; + + auto hideInNavigator = metaInfo.hideInNavigator(); + + ASSERT_THAT(hideInNavigator, FlagIs::True); +} + TEST_F(NodeMetaInfo, component_is_visible_in_library) { auto moduleId = projectStorageMock.createModule("/path/to/project", ModuleKind::PathLibrary); diff --git a/tests/unit/tests/unittests/model/model-test.cpp b/tests/unit/tests/unittests/model/model-test.cpp index b6d453e74de..a374eb321c7 100644 --- a/tests/unit/tests/unittests/model/model-test.cpp +++ b/tests/unit/tests/unittests/model/model-test.cpp @@ -1041,7 +1041,7 @@ TEST_F(Model_MetaInfo, get_meta_info_by_module) ASSERT_THAT(metaInfo, model.qmlQtObjectMetaInfo()); } -TEST_F(Model_MetaInfo, get_invalid_meta_info_by_module_for_wrong_name) +TEST_F(Model_MetaInfo, get_invalid_meta_info_by_module_and_name_for_wrong_name) { auto module = model.module("QML", ModuleKind::QmlLibrary); diff --git a/tests/unit/tests/unittests/projectstorage/typeannotationreader-test.cpp b/tests/unit/tests/unittests/projectstorage/typeannotationreader-test.cpp index b91a89bbaf7..2959a19799c 100644 --- a/tests/unit/tests/unittests/projectstorage/typeannotationreader-test.cpp +++ b/tests/unit/tests/unittests/projectstorage/typeannotationreader-test.cpp @@ -236,6 +236,35 @@ TEST_F(TypeAnnotationReader, parse_false_canBeDroppedInNavigator) IsEmpty()))); } +TEST_F(TypeAnnotationReader, parse_true_hideInNavigator) +{ + using QmlDesigner::FlagIs; + auto content = QString{R"xy( + MetaInfo { + Type { + name: "QtQuick.Controls.Frame" + icon: "images/frame-icon16.png" + + Hints { + hideInNavigator: true + } + } + })xy"}; + traits.hideInNavigator = FlagIs::True; + + auto annotations = reader.parseTypeAnnotation(content, "/path", sourceId, directorySourceId); + + ASSERT_THAT(annotations, + ElementsAre(IsTypeAnnotation(sourceId, + directorySourceId, + "Frame", + moduleId("QtQuick.Controls"), + "/path/images/frame-icon16.png", + traits, + IsEmpty(), + IsEmpty()))); +} + TEST_F(TypeAnnotationReader, parse_true_canBeDroppedInView3D) { using QmlDesigner::FlagIs; diff --git a/tests/unit/tests/unittests/sourcepathstorage/CMakeLists.txt b/tests/unit/tests/unittests/sourcepathstorage/CMakeLists.txt index 6a2ec39146c..9325ae72324 100644 --- a/tests/unit/tests/unittests/sourcepathstorage/CMakeLists.txt +++ b/tests/unit/tests/unittests/sourcepathstorage/CMakeLists.txt @@ -7,5 +7,3 @@ extend_qtc_test(unittest sourcepathview-test.cpp storagecache-test.cpp ) - -unittest_copy_data_folder()