summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/qtcreatordev/src/qtcreator-documentation.qdoc81
-rw-r--r--doc/qtdesignstudio/examples/doc/StateTransitions.qdoc4
-rw-r--r--doc/qtdesignstudio/examples/doc/images/loginui1-library-assets.jpgbin58564 -> 68266 bytes
-rw-r--r--doc/qtdesignstudio/examples/doc/images/loginui1-project.pngbin41456 -> 35138 bytes
-rw-r--r--doc/qtdesignstudio/examples/doc/loginui1.qdoc310
-rw-r--r--doc/qtdesignstudio/examples/doc/loginui2.qdoc43
-rw-r--r--doc/qtdesignstudio/examples/doc/loginui3.qdoc55
-rw-r--r--doc/qtdesignstudio/examples/doc/loginui4.qdoc2
-rw-r--r--doc/qtdesignstudio/examples/doc/sidemenu.qdoc2
-rw-r--r--doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc2
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-buttons.qdoc2
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc2
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-components.qdoc2
-rw-r--r--doc/qtdesignstudio/src/overviews/qtquick-creating-ui-logic.qdoc4
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc4
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc2
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-terms.qdoc4
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc4
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-adding-dynamics.qdoc4
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc2
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-designer.qdoc4
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-navigator.qdoc4
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-properties-view.qdoc2
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-properties.qdoc2
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-states-view.qdoc4
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-states.qdoc2
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc2
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml512
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsContextMenu.qml120
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsView.qml246
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/ConfirmDeleteFolderDialog.qml92
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/NewFolderDialog.qml102
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/RenameFolderDialog.qml124
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/BundleMaterialItem.qml46
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml43
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/UnimportBundleMaterialDialog.qml85
-rw-r--r--share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml1
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QML/QtObjectPane.qml29
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml9
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml21
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItem.qml11
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml242
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttfbin24432 -> 23968 bytes
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json4
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json4
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/common/asset_imports.txt1
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json4
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json4
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json4
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json4
-rw-r--r--src/app/main.cpp37
-rw-r--r--src/plugins/mcusupport/mcusupportsdk.cpp2
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp148
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/theme.h4
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp16
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp4
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/bundleimporter.cpp51
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/bundleimporter.h5
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/bundlematerial.cpp16
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/bundlematerial.h6
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.cpp10
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.h1
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.cpp50
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.h13
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp58
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h1
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp171
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h6
-rw-r--r--src/plugins/qmldesigner/designercore/include/modelnode.h1
-rw-r--r--src/plugins/qmldesigner/designercore/model/modelnode.cpp12
-rw-r--r--src/plugins/qtsupport/qtoptionspage.cpp4
-rw-r--r--src/plugins/texteditor/texteditor.cpp16
-rw-r--r--tests/system/suite_tools/tst_git_clone/test.py6
74 files changed, 1783 insertions, 1114 deletions
diff --git a/doc/qtcreatordev/src/qtcreator-documentation.qdoc b/doc/qtcreatordev/src/qtcreator-documentation.qdoc
index 08ab05b3fc..58ccbb3c88 100644
--- a/doc/qtcreatordev/src/qtcreator-documentation.qdoc
+++ b/doc/qtcreatordev/src/qtcreator-documentation.qdoc
@@ -299,22 +299,26 @@
users, but always place example values also in the text.
\list
- \li Use the screen resolution of 1366x768 (available on the most
+ \li Use the screen resolution of 1920x1080 (available on the most
commonly used screens, as of this writing).
-
- \li Use the aspect ratio of 16:9.
-
- \li Open the application in the maximum size on full screen.
+ \note Use display scaling 100%.
\li Use your favorite tool to take the screen shot.
\li Include only the part of the screen that you need (you can crop the
- image also in the screen capture tool).
+ image also in the screen capture tool). In \QDS, close all
+ unnecessary views to avoid clutter.
+
+ \li Do not scale or resize the images in the tool because it causes
+ reduced visual quality and bigger file size. Also, the CSS we use
+ online scales down images if needed (their width is larger than 800
+ pixels).
\li To highlight parts of the screen shot, use the images of numbers
- that are stored in \c{doc/images/numbers} in the \QC repository.
+ that are stored in \c{qtcreator/doc/qtcreator/images/numbers} in
+ the \QC repository.
- \li Before you submit the images to the repository, optimize them to
+ \li Before you submit PNG images to the repository, optimize them to
save space.
\endlist
@@ -322,9 +326,9 @@
You can use number icons in screenshots to highlight parts of the screenshot
(instead of using red arrows or borders, or something similar). You can then
- refer to the numbers in text. For and example, see the
- \l{https://doc.qt.io/qt/topics-app-development.html}{Development Tools}
- topic in the Qt reference documentation.
+ refer to the numbers in text. For an example, see the
+ \l{https://doc.qt.io/qtcreator/creator-quick-tour.html}{User Interface}
+ topic in the \QC Manual.
This improves the consistency of the look and feel of Qt documentation,
and eliminates the need to describe parts of the UI in the text because
@@ -332,8 +336,8 @@
brackets.
You can find a set of images that show the numbers from 1 to 10 in the
- \c doc/images/numbers directory (or in the \c qtdoc module sources in
- \c doc/images/numbers).
+ \c qtcreator/doc/qtcreator/images/numbers directory (or in the \c qtdoc
+ module sources in \c doc/images/numbers).
To use the numbers, copy-paste the number images on the screenshot to the
places that you want to refer to from text.
@@ -358,6 +362,13 @@
recolors icons in \c qtcreator/doc/qtcreator/images/icons. Use the
\c -docspath option to specify the path to another icon source directory.
+ For example, if you saved the new icons in \c {C:\iconconversions}, switch to
+ the \c {qtcreator\src\tools\icons} folder and enter:
+
+ \badcode
+ recolordocsicons.py -docspath C:\iconconversions
+ \endcode
+
To run the script, you will need to install the following tools and add them
to the PATH:
@@ -367,20 +378,26 @@
\li optipng
\endlist
- \section2 Optimizing Images
+ \section2 Saving Images
- Save images in the PNG format in the \QC project folder in the
- \c {doc/images} folder. Binary images can easily add megabytes to the Git
+ Save images in PNG or WebP format in the \QC project folder in the
+ \c doc/qtcreator/images or \c doc/qtdesignstudio/images folder. Binary
+ images can easily add megabytes to the Git
history. To keep the history as small as possible, the Git post-commit hooks
- remind you to try to keep image size below 50 kilobytes. To achieve this
+ remind you to try to keep image file size below 50 kilobytes. To achieve this
goal, crop images so that only relevant information is visible in them.
- Before committing images, optimize them by using an image optimization tool.
- Optimization should not visibly reduce image quality. If it does, do not do
- it.
+ If your screenshot contains lots of colorful content or a photo, for example,
+ consider saving it in WebP format for a smaller image file size.
+
+ \section2 Optimizing Images
+
+ Before committing PNG images, optimize them by using an image optimization
+ tool. Optimization should not visibly reduce image quality. If it does, try
+ saving the image as WebP instead.
You can use a web service, such as \l{https://tinypng.com}, or an image
- optimization tool to shrink the images. For example, you can use the Radical
+ optimization tool to shrink PNG images. For example, you can use the Radical
Image Optimization Tool (RIOT) or OptiPNG on Windows, ImageOptim on
\macos, or some other tool available on Linux.
@@ -425,6 +442,16 @@
optipng -o 7 -strip all doc/images/<screenshot_name>
\endcode
+ \section2 Creating GIF Videos
+
+ Sometimes it is easier to explain how something works by recording
+ a short GIF video. You can use any tool you like, for example
+ \l {https://www.screentogif.com/}{ScreenToGif}. GIF videos are typically
+ bigger than screenshots, so try to make them as short and to the point as
+ you can.
+
+ Use the \c {\image} command to add GIF files to the documentation.
+
\section2 Linking to Youtube Videos
You can use the \c {\youtube} macro to link to a video on Youtube. The HTML
@@ -477,11 +504,7 @@
\section2 Setting Up Documentation Builds
- For more information about setting up the build environment with a
- self-built Qt if you do not want to build the whole Qt, see
- \l{https://wiki.qt.io/Building_Qt_Documentation}{Building Qt Documentation}
- on the Qt wiki.
-
+ You can use an installed Qt version to build the documentation.
The content and formatting of documentation are separated in QDoc.
The documentation configuration, style sheets, and templates have
changed over time, so they differ between Qt and \QC versions.
@@ -532,7 +555,7 @@
For example (all on one line):
\badcode
C:\dev\qtc-doc-build>cmake -DWITH_DOCS=ON
- "-DCMAKE_PREFIX_PATH=C:\Qt\5.15.1\msvc2019_64"
+ "-DCMAKE_PREFIX_PATH=C:\Qt\6.4.0\msvc2019_64"
C:\dev\qtc-super\qtcreator
\endcode
\li To also build Extending \QC Manual, add the following option:
@@ -544,7 +567,7 @@
\badcode
C:\dev\qtc-doc-build>cmake -DWITH_DOCS=ON -DBUILD_DEVELOPER_DOCS=ON
"-DCMAKE_MODULE_PATH=C:\dev\tqtc-plugin-qtquickdesigner\studiodata\branding"
- "-DCMAKE_PREFIX_PATH=C:\Qt\5.15.1\msvc2019_64"
+ "-DCMAKE_PREFIX_PATH=C:\Qt\6.4.0\msvc2019_64"
C:\dev\qtc-super\qtcreator
\endcode
\li To build the docs using the online style, use the following option
@@ -556,7 +579,7 @@
C:\dev\qtc-doc-build>cmake -DWITH_ONLINE_DOCS=ON
-DBUILD_DEVELOPER_DOCS=ON
"-DCMAKE_MODULE_PATH=C:\dev\tqtc-plugin-qtquickdesigner\studiodata\branding"
- "-DCMAKE_PREFIX_PATH=C:\Qt\5.15.1\msvc2019_64"
+ "-DCMAKE_PREFIX_PATH=C:\Qt\6.4.0\msvc2019_64"
C:\dev\qtc-super\qtcreator
\endcode
\note If you already ran CMake \c {-DWITH_DOCS=ON} in a folder and
diff --git a/doc/qtdesignstudio/examples/doc/StateTransitions.qdoc b/doc/qtdesignstudio/examples/doc/StateTransitions.qdoc
index 4352e0c5f7..2c2729d77a 100644
--- a/doc/qtdesignstudio/examples/doc/StateTransitions.qdoc
+++ b/doc/qtdesignstudio/examples/doc/StateTransitions.qdoc
@@ -4,7 +4,7 @@
/*!
\page state-transition-animations.html
\ingroup gstutorials
- \sa States, {Transitions}, {Adding States}
+ \sa States, {Transitions}, {Working with States}
\title Animated State Transitions
\brief Illustrates how to create animated state transitions.
@@ -12,7 +12,7 @@
\image animated-state-transitions.jpg
The \e{Animated State Transitions} tutorial illustrates how you can animate
- the transition between \l{Adding States}{states}.
+ the transition between \l{Working with States}{states}.
The starting point of this tutorial is the Car Demo project, you can
download it from
diff --git a/doc/qtdesignstudio/examples/doc/images/loginui1-library-assets.jpg b/doc/qtdesignstudio/examples/doc/images/loginui1-library-assets.jpg
index 999959b20b..4dc8e4e910 100644
--- a/doc/qtdesignstudio/examples/doc/images/loginui1-library-assets.jpg
+++ b/doc/qtdesignstudio/examples/doc/images/loginui1-library-assets.jpg
Binary files differ
diff --git a/doc/qtdesignstudio/examples/doc/images/loginui1-project.png b/doc/qtdesignstudio/examples/doc/images/loginui1-project.png
index 93ca7c6c8c..28984175b9 100644
--- a/doc/qtdesignstudio/examples/doc/images/loginui1-project.png
+++ b/doc/qtdesignstudio/examples/doc/images/loginui1-project.png
Binary files differ
diff --git a/doc/qtdesignstudio/examples/doc/loginui1.qdoc b/doc/qtdesignstudio/examples/doc/loginui1.qdoc
index c75dea8b70..c10c118fdd 100644
--- a/doc/qtdesignstudio/examples/doc/loginui1.qdoc
+++ b/doc/qtdesignstudio/examples/doc/loginui1.qdoc
@@ -8,23 +8,18 @@
\title Log In UI - Components
\brief Illustrates how to use wizard templates to create a simple UI
- wireframe that contains a text label, images, and push buttons.
+ that contains a text label, images, and push buttons.
\image loginui1.jpg
- \e{Log In UI - Components} is the first in a series of tutorials that build
- on each other to illustrate how to use \QDS to create a simple UI with some
- basic UI components, such as pages, buttons, and fields. The first tutorial
- in the series describes how to use the \QDS wizard templates to create a
- project and a button UI control, and how to modify the files generated by
- the wizard templates to wireframe the UI.
+ \e{Log In UI - Components} is the first tutorial in a series of tutorials
+ that describes how to use the \QDS wizard templates to create a project and
+ a button UI control, and how to modify the files generated by the wizard
+ templates to design the UI.
You can donwnload the completed project from
\l{https://git.qt.io/public-demos/qtdesign-studio/-/tree/master/tutorial%20projects/Loginui1}{here}.
- The \e {Learn More} sections provide additional information about the
- tasks performed by the wizards and about other basic tasks and concepts.
-
\section1 Creating the UI Project
For the purposes of this tutorial, you will use the empty wizard template.
@@ -47,6 +42,7 @@
\li Set \uicontrol Width to 720 and \uicontrol Height to 1280.
You can change the screen size later in \l Properties.
\endlist
+
\li Select \uicontrol Create to create the project.
\endlist
@@ -57,7 +53,7 @@
The wizard constructs the \e Screen01 \l{glossary-component}{component}
using instances of a \l{basic-rectangle}{Rectangle} component that forms
- the background and a \l Text component that displays some text.
+ the background, a \l Button, and a \l Text component that displays some text.
\note The visibility of views depends on the selected workspace,
so your \QDS might look somewhat different from the above image.
@@ -65,53 +61,14 @@
in the \uicontrol Design mode. For more information about moving
views around, see \l {Managing Workspaces}.
- \section2 Learn More - Projects and Files
-
- \QDS creates a set of boilerplate files and folders that you need to create
- a UI. The files are listed in the \l{File System} view.
-
- \image loginui1-project-files.png
-
- \list
- \li The \e {loginui1.qmlproject} project file defines that all
- component, JavaScript, and image files in the project folder belong
- to the project. Therefore, you do not need to individually list new
- files when you add them to the project.
- \li The \e {loginui1.qml} file defines the functionality of
- the UI. For the time being, it does not do anything.
- \li The \e {Screen01.ui.qml} file is a custom component created by
- the wizard template. For more information, see \l {UI Files}.
-
- By default, this is the main file in the project, but you can
- change that in the .qmlproject file. While the custom component
- is a good starting point for new users, you don't have to use it.
- Specifically, if you export and import designs using \QB, your main
- file is most likely called something else. For more information,
- see \l {Exporting from Design Tools}.
- \li The \e CMakeLists.txt project configuration file allowing you to
- share your project as a fully working C++ application with
- developers.
- \li The \e {qtquickcontrols2.conf} file specifies the selected
- \l {Styling Qt Quick Controls}{UI style} and some style-specific
- arguments.
- \li The \e imports folder contains \e {Constants.qml} and
- \e {DirectoryFontLoader.qml} files that specify a font loader
- and a \e qmldir module definition file that declares the Constant
- component. For more information, see
- \l {Module Definition qmldir Files}. The \e EventListModel.qml and
- \e EventListSimulator.qml files are not used in this example, so
- you can ignore them for now.
- \endlist
+ You should remove this \l Button for now from the UI
+ to have a clean workspace. You'll add this later in the course of the tutorial.
+ Then you shall know how to modify and adjust it as you need.
- \l{UI Files}{UI files} define a hierarchy of components with a
- highly-readable, structured layout. Every UI file consists of two parts:
- an imports section and an component declaration section. The components and
- functionality most common to UIs are provided in the \c QtQuick import. You
- can view the code of a \e .ui.qml file in the \l{Code} view.
+ To remove this Button, just select it and press \key {Backspace}.
Next, you will edit the values of the properties of the component instances
to create the main page of the UI.
-
\section1 Creating the Main Page
You will now change the values of the properties of the \l Text component
@@ -123,9 +80,9 @@
You can download the logo and the background image from here:
\list
- \li \l{https://doc.qt.io/qtdesignstudio/images/used-in-examples/loginui1/images/qt_logo_green_128x128px.png}
+ \li \l{https://git.qt.io/public-demos/qtdesign-studio/-/blob/master/tutorial%20projects/Loginui1/content/images/qt_logo_green_128x128px.png}
{qt_logo_green_128x128px.png}
- \li \l{https://doc.qt.io/qtdesignstudio/images/used-in-examples/loginui1/images/adventurePage.jpg}
+ \li \l{https://git.qt.io/public-demos/qtdesign-studio/-/blob/master/tutorial%20projects/Loginui1/content/images/adventurePage.jpg}
{Background image} (\e adventurePage.jpg)
Photo by \l{https://unsplash.com/photos/a2MgJdG6UvE}
@@ -139,7 +96,8 @@
To add the assets:
\list 1
\li Select \uicontrol Assets > \inlineimage icons/plus.png
- .
+ (Select \uicontrol View > \uicontrol Views > \uicontrol Assets to enable it,
+ if you can't find it).
\li Select the asset files, and then select \uicontrol Open.
\li Select the location where the files will be saved in the
\uicontrol {Add Resources} dialog.
@@ -158,8 +116,8 @@
To modify the \e Screen01 component in the \uicontrol {2D} view:
\list 1
- \li Drag-and-drop the background image from \uicontrol Assets to the
- rectangle in \l Navigator.
+ \li Drag-and-drop the background image (1) from \uicontrol Assets to the
+ \l{basic-rectangle}{Rectangle} (2) in \l Navigator.
\image loginui1-library-assets.jpg "Assets view"
\li \QDS automatically creates an instance of the \l{Images}{Image}
component for you with the path to the image file set as the
@@ -167,7 +125,7 @@
\image loginui1-image-properties.png "Image properties"
\li Drag-and-drop the Qt logo from \uicontrol Assets to the rectangle
in \uicontrol Navigator and move it to the top-center of the
- background image in \uicontrol the {2D} view.
+ background image in the \uicontrol {2D} view.
\li Select \e Text in \uicontrol Navigator and drag it below the logo
in the \uicontrol {2D} view. If the text is hidden behind the
background, select \inlineimage icons/navigator-arrowdown.png
@@ -182,8 +140,8 @@
line: \e {Are you ready to explore?}.
\image loginui1-text-properties.png "Text properties"
\li In \uicontrol Font, select \e {Titillium Web ExtraLight}.
- \li In \uicontrol Size, set the font size of the tag line to
- \e 50 pixels (\uicontrol px).
+ \li In \uicontrol Size, first select the scale to pixels (\uicontrol px),
+ then set font size of the tag line to \e 50 (\uicontrol px).
\li In \uicontrol {Text color}, set the text color to white
(\e #ffffff).
\endlist
@@ -197,74 +155,6 @@
\image loginui1-main-page.jpg "Modified UI in the Design mode"
You can resize the preview dialog to display the whole screen.
-
- \section2 Learn More - Components
-
- \QDS provides preset \l{glossary-component}{components} for creating
- UIs, including components for creating and animating visual components,
- receiving user input, and creating data models and views.
-
- To be able to use the functionality of preset components, the wizard template
- adds the following \e import statements to the UI files (.ui.qml) that it
- creates:
-
- \quotefromfile Loginui1/content/Screen01.ui.qml
- \skipto import
- \printuntil Controls
-
- You can view the import statements in the \uicontrol {Code} view.
-
- The \l Components view lists the components in each module that are
- supported by \QDS. You can use the basic components to create your own
- components, and they will be listed in \uicontrol {My Components}.
- This section is only visible if you have created custom components.
-
- The \l {basic-rectangle}{Rectangle}, \l Text, and \l {Images}{Image}
- components used in this tutorial are based on the \l Item component.
- It is the base component for all visual elements, with implementation
- of basic functions and properties, such as component type, ID, position,
- size, and visibility.
-
- For more information, see \l{Use Case - Visual Elements In QML}. For
- descriptions of all components, see \l{All QML Types} in the Qt reference
- documentation.
-
- \section3 Regtangle Properties
-
- The default \l {basic-rectangle}{Rectangle} component is used for drawing
- shapes with four sides and four corners. You can fill rectangles either with
- a solid fill color or a gradient. You can specify the border color separately.
- By setting the value of the radius property, you can create shapes with
- rounded corners.
-
- If you want to specify the radius of each corner separately, you can use the
- \l{studio-rectangle}{Rectangle} component from the
- \uicontrol {Qt Quick Studio Components} module instead of the basic rectangle
- component. It is available in \uicontrol Components
- > \uicontrol {Qt Quick Studio Components}.
-
- \section3 Text Properties
-
- The \l Text component is used for adding static text to the UI, such as
- titles and labels. You can select the font to use and specify extensive
- properties for each text component, such as size in points or pixels,
- weight, style, and spacing.
-
- If you want to create a label with a background, use the \l Label component
- from the \uicontrol {Qt Quick Controls} module instead of the Text component.
-
- \section3 Image Properties
-
- The \l {Images}{Image} component is used for adding images to the UI in several
- supported formats, including bitmap formats such as PNG and JPEG and vector
- graphics formats such as SVG. To add an image to \uicontrol Assets, select
- \inlineimage icons/plus.png
- , and then select the image file.
-
- If you need to display animated images, use the \l {Animated Image}
- component, also available in \uicontrol Components >
- \uicontrol {Default Components} > \uicontrol Basic.
-
\section1 Creating a Push Button
You can use another wizard template to create a push button and to add it to
@@ -298,21 +188,9 @@
\image loginui1-button.png "Button in the Design mode."
- \section2 Learn More - UI Controls
-
- The \e {Custom Button} wizard template creates a button component
- based on the \l {Button} control in the \l {Qt Quick Controls} module. It
- is a push-button control that can be pushed or clicked by the user. Buttons
- are normally used to perform an action or to answer a question. The
- properties and functionality inherited from the Button component enable
- you to set text, display an icon, react to mouse clicks, and so on.
-
- To be able to use the functionality of the Button control, the wizard template
- adds the following \e import statements to the \e EntryField.ui.qml file:
-
- \quotefromfile Loginui1/content/EntryField.ui.qml
- \skipto import
- \printuntil Controls
+ \note To open the \uicontrol States view, select it from
+ \uicontrol View > \uicontrol Views > \uicontrol States, if
+ it is not available by default.
Next, you will change the appearance of the EntryField component by
modifying its properties.
@@ -353,8 +231,8 @@
properties in \uicontrol Properties.
\li In \uicontrol Character > \uicontrol Font, select
\e {Titillium Web ExtraLight}.
- \li In \uicontrol Size, set the font size to \e 34 pixels
- (\uicontrol px).
+ \li In \uicontrol Size, first select the scale to pixels (\uicontrol px),
+ then set font size to \e 34 (\uicontrol px).
\li In \uicontrol {Text color}, set the text color to white
(\e #ffffff).
\li In \uicontrol {Alignment H}, select the \uicontrol Left button to
@@ -374,6 +252,10 @@
\image loginui1-entry-field-styled.jpg "Modified button in the 2D view"
+ \note Do not edit the the value of \uicontrol Text in the \uicontrol Character
+ property, because this will break the connection, and later you won't be able
+ to change the text in \uicontrol {Button Content} > \uicontrol Text.
+
Next, you will add instances of the \e EntryField component to the
\e Screen01 component and modify their properties.
@@ -437,7 +319,8 @@
its properties in \uicontrol Properties.
\li In \uicontrol Character > \uicontrol Font, select
\e {Titillium Web ExtraLight}.
- \li In \uicontrol Size, set the font size to \e 34 pixels.
+ \li In \uicontrol Size, first select the scale to pixels (\uicontrol px),
+ then set font size to \e 34 (\uicontrol px).
\li In \uicontrol {Text color}, set the text color to \e #41cd52.
\li In the \uicontrol States view, select the \e normal state and repeat
the changes, as necessary.
@@ -481,7 +364,136 @@
\image loginui1-ready.jpg "The finished UI in the 2D view"
- \section2 Learn More - Component IDs
+ \section1 Learn More
+ The \e {Learn More} sections provide additional information about the
+ tasks performed by the wizards and about other basic tasks and concepts.
+
+ \section2 Projects and Files
+ \QDS creates a set of files and folders that you need to create
+ a UI. The files are listed in the \l{File System} view.
+
+ \image loginui1-project-files.png
+ \list
+ \li The \e {loginui1.qmlproject} project file defines that all
+ component, JavaScript, and image files in the project folder belong
+ to the project. Therefore, you do not need to individually list new
+ files when you add them to the project.
+ \li The \e {loginui1.qml} file defines the functionality of
+ the UI. For the time being, it does not do anything.
+ \li The \e {Screen01.ui.qml} file is a custom component created by
+ the wizard template. For more information, see \l {UI Files}.
+
+ By default, this is the main file in the project, but you can
+ change that in the .qmlproject file. While the custom component
+ is a good starting point for new users, you don't have to use it.
+ Specifically, if you export and import designs using \QB, your main
+ file is most likely called something else. For more information,
+ see \l {Exporting from Design Tools}.
+ \li The \e CMakeLists.txt project configuration file allowing you to
+ share your project as a fully working C++ application with
+ developers.
+ \li The \e {qtquickcontrols2.conf} file specifies the selected
+ \l {Styling Qt Quick Controls}{UI style} and some style-specific
+ arguments.
+ \li The \e imports folder contains \e {Constants.qml} and
+ \e {DirectoryFontLoader.qml} files that specify a font loader
+ and a \e qmldir module definition file that declares the Constant
+ component. For more information, see
+ \l {Module Definition qmldir Files}. The \e EventListModel.qml and
+ \e EventListSimulator.qml files are not used in this example, so
+ you can ignore them for now.
+ \endlist
+ \l{UI Files}{UI files} define a hierarchy of components with a
+ highly-readable, structured layout. Every UI file consists of two parts:
+ an imports section and an component declaration section. The components and
+ functionality most common to UIs are provided in the \c QtQuick import. You
+ can view the code of a \e .ui.qml file in the \l{Code} view.
+
+
+ \section2 Components
+
+ \QDS provides preset \l{glossary-component}{components} for creating
+ UIs, including components for creating and animating visual components,
+ receiving user input, and creating data models and views.
+
+ To be able to use the functionality of preset components, the wizard template
+ adds the following \e import statements to the UI files (.ui.qml) that it
+ creates:
+
+ \quotefromfile Loginui1/content/Screen01.ui.qml
+ \skipto import
+ \printuntil Controls
+
+ You can view the import statements in the \uicontrol {Code} view.
+
+ The \l Components view lists the components in each module that are
+ supported by \QDS. You can use the basic components to create your own
+ components, and they will be listed in \uicontrol {My Components}.
+ This section is only visible if you have created custom components.
+
+ The \l {basic-rectangle}{Rectangle}, \l Text, and \l {Images}{Image}
+ components used in this tutorial are based on the \l Item component.
+ It is the base component for all visual elements, with implementation
+ of basic functions and properties, such as component type, ID, position,
+ size, and visibility.
+
+ For more information, see \l{Use Case - Visual Elements In QML}. For
+ descriptions of all components, see \l{All QML Types} in the Qt reference
+ documentation.
+
+ \section3 Regtangle Properties
+
+ The default \l {basic-rectangle}{Rectangle} component is used for drawing
+ shapes with four sides and four corners. You can fill rectangles either with
+ a solid fill color or a gradient. You can specify the border color separately.
+ By setting the value of the radius property, you can create shapes with
+ rounded corners.
+
+ If you want to specify the radius of each corner separately, you can use the
+ \l{studio-rectangle}{Rectangle} component from the
+ \uicontrol {Qt Quick Studio Components} module instead of the basic rectangle
+ component. It is available in \uicontrol Components
+ > \uicontrol {Qt Quick Studio Components}.
+
+ \section3 Text Properties
+
+ The \l Text component is used for adding static text to the UI, such as
+ titles and labels. You can select the font to use and specify extensive
+ properties for each text component, such as size in points or pixels,
+ weight, style, and spacing.
+
+ If you want to create a label with a background, use the \l Label component
+ from the \uicontrol {Qt Quick Controls} module instead of the Text component.
+
+ \section3 Image Properties
+
+ The \l {Images}{Image} component is used for adding images to the UI in several
+ supported formats, including bitmap formats such as PNG and JPEG and vector
+ graphics formats such as SVG. To add an image to \uicontrol Assets, select
+ \inlineimage icons/plus.png
+ , and then select the image file.
+
+ If you need to display animated images, use the \l {Animated Image}
+ component, also available in \uicontrol Components >
+ \uicontrol {Default Components} > \uicontrol Basic.
+
+ \section2 UI Controls
+
+ The \e {Custom Button} wizard template creates a button component
+ based on the \l {Button} control in the \l {Qt Quick Controls} module. It
+ is a push-button control that can be pushed or clicked by the user. Buttons
+ are normally used to perform an action or to answer a question. The
+ properties and functionality inherited from the Button component enable
+ you to set text, display an icon, react to mouse clicks, and so on.
+
+ To be able to use the functionality of the Button control, the wizard template
+ adds the following \e import statements to the \e EntryField.ui.qml file:
+
+ \quotefromfile Loginui1/content/EntryField.ui.qml
+ \skipto import
+ \printuntil Controls
+
+ \section2 Component IDs
Each component and each instance of a component has an \e ID that uniquely
identifies it and enables other components' properties to be bound to it.
diff --git a/doc/qtdesignstudio/examples/doc/loginui2.qdoc b/doc/qtdesignstudio/examples/doc/loginui2.qdoc
index 8b8787cbf4..5fbf175044 100644
--- a/doc/qtdesignstudio/examples/doc/loginui2.qdoc
+++ b/doc/qtdesignstudio/examples/doc/loginui2.qdoc
@@ -76,13 +76,11 @@
rectangle at the top, while keeping its horizontal center aligned
with that of the rectangle.
\li Select \e tagLine in \uicontrol Navigator.
- \li In \uicontrol Properties > \uicontrol Layout, deselect the
- \inlineimage icons/anchor-center-vertical.png
- button to remove the vertical center anchor, and then select the
- \inlineimage icons/anchor-top.png
- button to anchor the tag line to
- \e qt_logo_green_128x128px in the \uicontrol Target field with a
- 40-pixel margin. This attaches the top of the tag line to the
+ \li In \uicontrol Properties > \uicontrol Layout,
+ select the \inlineimage icons/anchor-top.png
+ button and then select \e qt_logo_green_128x128px
+ as \uicontrol Target to anchor \e tagLine with a 40-pixel margin.
+ This attaches the top of the tag line to the
bottom of the logo, while keeping its horizontal center aligned
with that of the rectangle.
\image loginui2-layout-text.png "Text Layout properties"
@@ -101,20 +99,6 @@
\image loginui2-loginpage.jpg "Login page in the Design mode and live preview"
- \section2 Learn More - Anchors
-
- In an anchor-based layout, each component instance can be thought of as
- having a set of invisible \e anchor lines: top, bottom, left, right, fill,
- horizontal center, vertical center, and baseline.
-
- Anchors enable placing a component instance either adjacent to or inside of
- another component instance, by attaching one or more of the instance's
- anchor lines to the anchor lines of the other component instance. If a
- component instance changes, the instances that are anchored to it will
- adjust automatically to maintain the anchoring.
-
- For more information, see \l{Positioning with Anchors}.
-
\section1 Using Column Positioners
You will now position the entry fields and buttons in columns
@@ -150,7 +134,7 @@
\li Select \e fields in \uicontrol Navigator.
\li In \uicontrol Properties > \uicontrol Layout, select the
\inlineimage icons/anchor-top.png
- button to anchor the top of the field column to
+ button to anchor the top of the fields column to
the bottom of \e tagLine with a 170-pixel margin.
\li Select the \inlineimage icons/anchor-center-horizontal.png
button to anchor the column horizontally to its parent.
@@ -170,7 +154,20 @@
\image loginui2-loginpage-ready.jpg "Login page in the Design mode and live preview"
- \section1 Learn More - Positioners
+ \section1 Learn More
+ \section2 Anchors
+ In an anchor-based layout, each component instance can be thought of as
+ having a set of invisible \e anchor lines: top, bottom, left, right, fill,
+ horizontal center, vertical center, and baseline.
+
+ Anchors enable placing a component instance either adjacent to or inside of
+ another component instance, by attaching one or more of the instance's
+ anchor lines to the anchor lines of the other component instance. If a
+ component instance changes, the instances that are anchored to it will
+ adjust automatically to maintain the anchoring.
+
+ For more information, see \l{Positioning with Anchors}.
+ \section2 Positioners
For many use cases, the best positioner to use is a simple grid, row, or
column, and \QDS provides components that will position children in these
diff --git a/doc/qtdesignstudio/examples/doc/loginui3.qdoc b/doc/qtdesignstudio/examples/doc/loginui3.qdoc
index cf9d98b6cd..59501c199d 100644
--- a/doc/qtdesignstudio/examples/doc/loginui3.qdoc
+++ b/doc/qtdesignstudio/examples/doc/loginui3.qdoc
@@ -77,7 +77,7 @@
\section1 Using States to Simulate Page Changes
- You will now add \l{Adding States}{states} to the UI to show and hide UI
+ You will now add \l{Working with States}{states} to the UI to show and hide UI
components in the \uicontrol {2D} view, depending on the current page:
\list 1
@@ -115,29 +115,6 @@
\image loginui3-login-state-preview.jpg "Preview of the login state"
- \section2 Learn More - States
-
- The \l{Adding States}{state} of a particular visual component is the set of
- information which describes how and where the individual parts of the visual
- component are displayed within it, and all the data associated with that
- state. Most visual components in a UI will have a limited number of states,
- each with well-defined properties.
-
- For example, a list item may be either selected or not, and if
- selected, it may either be the currently active single selection or it
- may be part of a selection group. Each of those states may have certain
- associated visual appearance (neutral, highlighted, expanded, and so on).
-
- Youn can apply states to trigger behavior or animations. UI components
- typically have a default state that contains all of a component's initial
- property values and is therefore useful for managing property values before
- state changes.
-
- You can specify additional states by adding new states. Each state within a
- component has a unique name. To change the current state of an component,
- the state property is set to the name of the state. State changes can be
- bound to conditions by using the \c when property.
-
Next, you will create connections to specify that clicking the
\uicontrol {Create Account} button on the login page triggers a
transition to the account creation page.
@@ -162,9 +139,13 @@
\e createAccount should apply.
\li Double-click the value \uicontrol Action column and select
\uicontrol {Change state to createAccount} in the drop-down menu.
- \image loginui3-connections.png "Connections tab"
+ \note Or, you can right-click the \e createAccount button in \l Navigator.
+ Then select \uicontrol {Connections} > \uicontrol {Add signal handler} >
+ \uicontrol {clicked} > \uicontrol {Change State to createAccount}.
+ \image loginui3-connections.png "Connections tab"
\li Select \uicontrol File > \uicontrol Save or press \key {Ctrl+S}
to save your changes.
+
\endlist
In the live preview, you can now click the \uicontrol {Create Account}
@@ -172,8 +153,30 @@
\image loginui3.gif "Moving between login page and account creation page"
+ \section1 Learn More
+ \section2 States
+ The \l{Working with States}{state} of a particular visual component is the set of
+ information which describes how and where the individual parts of the visual
+ component are displayed within it, and all the data associated with that
+ state. Most visual components in a UI will have a limited number of states,
+ each with well-defined properties.
+
+ For example, a list item may be either selected or not, and if
+ selected, it may either be the currently active single selection or it
+ may be part of a selection group. Each of those states may have certain
+ associated visual appearance (neutral, highlighted, expanded, and so on).
+
+ Youn can apply states to trigger behavior or animations. UI components
+ typically have a default state that contains all of a component's initial
+ property values and is therefore useful for managing property values before
+ state changes.
+
+ You can specify additional states by adding new states. Each state within a
+ component has a unique name. To change the current state of an component,
+ the state property is set to the name of the state. State changes can be
+ bound to conditions by using the \c when property.
- \section2 Learn More - Signal and Event Handlers
+ \section2 Signal and Event Handlers
UI components need to communicate with each other. For example, a button
needs to know that the user has clicked on it. In response, the button may
diff --git a/doc/qtdesignstudio/examples/doc/loginui4.qdoc b/doc/qtdesignstudio/examples/doc/loginui4.qdoc
index e9bdc4b269..407866f5cf 100644
--- a/doc/qtdesignstudio/examples/doc/loginui4.qdoc
+++ b/doc/qtdesignstudio/examples/doc/loginui4.qdoc
@@ -240,7 +240,7 @@
\section1 Binding Animation to States
- You will now bring back the \l{Adding States}{states} in the
+ You will now bring back the \l{Working with States}{states} in the
\uicontrol States view and bind them to the animation settings
in \uicontrol Timeline:
diff --git a/doc/qtdesignstudio/examples/doc/sidemenu.qdoc b/doc/qtdesignstudio/examples/doc/sidemenu.qdoc
index 5f12aa0e2c..d1db82c8ee 100644
--- a/doc/qtdesignstudio/examples/doc/sidemenu.qdoc
+++ b/doc/qtdesignstudio/examples/doc/sidemenu.qdoc
@@ -31,7 +31,7 @@
The button can have the following states: checked, hover, pressed, and
normal. We construct the button using different images for the button
- background, frame, and front. We then add \l{Adding States}{states} in
+ background, frame, and front. We then add \l{Working with States}{states} in
the \l States view for each of the button states. In each state, we turn
the visibility of the appropriate images on or off in the button properties,
to change the appearance of the button.
diff --git a/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc b/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc
index 674ee37829..45ab960f7d 100644
--- a/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc
+++ b/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc
@@ -166,7 +166,7 @@
in the top-left corner of the root component.
Then, we open the \uicontrol States view to create the \e start,
- \e settings, \e presets, and \e running \l{Adding States}{states} for
+ \e settings, \e presets, and \e running \l{Working with States}{states} for
displaying a particular screen by selecting \uicontrol {Create New State}.
\image washingmachineui-states.png "States view"
diff --git a/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc b/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc
index 53b801811c..088e133d8b 100644
--- a/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc
@@ -117,7 +117,7 @@
PNG file, as a border and a background.
Use two border images and suitable graphics to change the appearance of
- a button when it is clicked. You can use use \l{Adding States}{states}
+ a button when it is clicked. You can use use \l{Working with States}{states}
to determine which image is visible depending on whether the mouse
button is pressed down. You could add more images and states to
change the appearance of the button depending on other mouse events,
diff --git a/doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc b/doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc
index 09f8d2e28b..ada17fae01 100644
--- a/doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-component-instances.qdoc
@@ -43,7 +43,7 @@
\image qmldesigner-bindings.png "Connections view Bindings tab"
\li Add states to apply sets of changes to the property values of one
or several component instances in the \uicontrol States view.
- For more information, see \l{Adding States}.
+ For more information, see \l{Working with States}.
\li Animate the properties of component instances in the
\uicontrol Timeline view. For more information, see
\l{Creating Timeline Animations}.
diff --git a/doc/qtdesignstudio/src/components/qtquick-components.qdoc b/doc/qtdesignstudio/src/components/qtquick-components.qdoc
index 7c3b09fc84..092a8bea3b 100644
--- a/doc/qtdesignstudio/src/components/qtquick-components.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-components.qdoc
@@ -63,7 +63,7 @@
your UI.
\li Use as few components as necessary. To minimize the number of
components, use \l{Adding Property Aliases}{alias properties} and
- \l{Adding States}{states} to create the differences in your
+ \l{Working with States}{states} to create the differences in your
component instances. We recommend reusing components
instead of duplicating them, so the components do not need to be
processed as completely new component types. This reduces loading
diff --git a/doc/qtdesignstudio/src/overviews/qtquick-creating-ui-logic.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-creating-ui-logic.qdoc
index 3aebd6ae17..226c2a4982 100644
--- a/doc/qtdesignstudio/src/overviews/qtquick-creating-ui-logic.qdoc
+++ b/doc/qtdesignstudio/src/overviews/qtquick-creating-ui-logic.qdoc
@@ -32,7 +32,7 @@
exported as a public property of the relevant component. For example,
a speedometer should have a property for speed to which the UI is bound.
- You can declare various \l{Adding States}{UI states} that describe how
+ You can declare various \l{Working with States}{UI states} that describe how
property values change from a base state. States can be a useful way of
organizing your UI logic. You can associate transitions with components
to define how their properties will animate when they change due to a
@@ -100,7 +100,7 @@
\li \l{Adding Property Aliases}
\row
\li Referencing a state from within a specific component
- \li \l{Adding States}
+ \li \l{Working with States}
\row
\li Switching to a state when a particular property changes
\li \l{Applying States}
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc
index 7408d0a826..5514acd2f2 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-app-flows.qdoc
@@ -49,7 +49,7 @@
\uicontrol {Flow Decision} components from
\uicontrol Components > \uicontrol {Flow View}, as described in
\l{Simulating Conditions}.
- \li Use \l{Adding States}{states} in flows to modify the appearance
+ \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
@@ -620,7 +620,7 @@
\title Applying States in Flows
- You can use \l{Adding States}{states} in flows to modify the appearance
+ You can use \l{Working with States}{states} in flows to modify the appearance
of \l{glossary-component}{components} in flow items in response to user
interaction, for example. For this purpose, you use the
\uicontrol {Flow Item} components available in
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc b/doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc
index 7f237dfc49..d0ab93d928 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-components.qdocinc
@@ -28,7 +28,7 @@
\endtable
You can edit the properties of the controls in all the preset
- \l{Adding States}{states} to apply your own style to them.
+ \l{Working with States}{states} to apply your own style to them.
\note For buttons and check boxes, you can disable the misbehaving hover
effects by selecting \l Properties > \uicontrol Control, and then disabling
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-terms.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-terms.qdoc
index d26f96652c..dd5c1609b1 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-terms.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-terms.qdoc
@@ -121,7 +121,7 @@
\list
\li \l{Connections}
- \li \l{Adding Connections}
+ \li \l{Working with Connections}
\endlist
\section1 Device
@@ -249,7 +249,7 @@
\list
\li \l{States}
- \li \l{Adding States}
+ \li \l{Working with States}
\endlist
\section1 Transition
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc
index 070bf4ae25..567bb6fcb2 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc
@@ -118,13 +118,13 @@
\endlist
\li \l{Dynamic Behaviors}
\list
- \li \l{Adding Connections}
+ \li \l{Working with Connections}
\list
\li\l{Connecting Components to Signals}
\li\l{Adding Bindings Between Properties}
\li\l{Specifying Custom Properties}
\endlist
- \li \l{Adding States}
+ \li \l{Working with States}
\endlist
\li \l{Validating with Target Hardware}
\list
diff --git a/doc/qtdesignstudio/src/views/qtquick-adding-dynamics.qdoc b/doc/qtdesignstudio/src/views/qtquick-adding-dynamics.qdoc
index bb574daefe..ab9ed074f4 100644
--- a/doc/qtdesignstudio/src/views/qtquick-adding-dynamics.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-adding-dynamics.qdoc
@@ -13,7 +13,7 @@
when the values of other components or the UI state change.
\list
- \li \l {Adding Connections}
+ \li \l {Working with Connections}
You can create connections between the UI components and
the application to enable them to communicate with each other. For
@@ -25,7 +25,7 @@
binding their properties together. This way, when the value of a
property changes in a parent component, it can be automatically
changed in all the child components, for example.
- \li \l {Adding States}
+ \li \l {Working with States}
You can declare various UI states that describe how component
properties change from a base state. Therefore, states can be
diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc
index d17dbcb003..0512af58ad 100644
--- a/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc
@@ -6,7 +6,7 @@
\previouspage qtquick-adding-dynamics.html
\nextpage quick-signals.html
- \title Adding Connections
+ \title Working with Connections
\list
\li \l{Connecting Components to Signals}
diff --git a/doc/qtdesignstudio/src/views/qtquick-designer.qdoc b/doc/qtdesignstudio/src/views/qtquick-designer.qdoc
index adf94ae7a5..4dfe24718b 100644
--- a/doc/qtdesignstudio/src/views/qtquick-designer.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-designer.qdoc
@@ -75,14 +75,14 @@
\li \l{Connections}
\li Enables you to add functionality to the UI by creating
connections between components, signals, and component properties.
- \li \l{Adding Connections}
+ \li \l{Working with Connections}
\row
\li \l States
\li Displays the different states that can be applied to a component.
Typically, states describe UI configurations, such as the
visibility and behavior of components and the available user
actions.
- \li \l{Adding States}
+ \li \l{Working with States}
\row
\li \l{Transitions}
\li Enables you to make movement between states smooth by animating
diff --git a/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc b/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc
index 90735297f7..0c322c750d 100644
--- a/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-navigator.qdoc
@@ -124,7 +124,7 @@
the \l {3D} view nor access their properties in
\uicontrol Properties.
- If you attempt to \l{Adding States}{remove a state} that changes the
+ If you attempt to \l{Working with States}{remove a state} that changes the
properties of a locked component, you are prompted to confirm the removal.
If you have \l{Editing Animation Curves}{added easing curves} to keyframe
@@ -212,7 +212,7 @@
\image qmldesigner-export-item.png
You can then use the property alias in other components to
- \l{Adding Connections}{create connections} to this component.
+ \l{Working with Connections}{create connections} to this component.
\section1 Moving Within Components
diff --git a/doc/qtdesignstudio/src/views/qtquick-properties-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-properties-view.qdoc
index d8f1f01d15..acde01a951 100644
--- a/doc/qtdesignstudio/src/views/qtquick-properties-view.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-properties-view.qdoc
@@ -86,7 +86,7 @@
The default values of properties are displayed in white color, while the
values that you specify explicitly are highlighted with blue color. In
- addition, property changes in \l{Adding States}{states} are highlighted
+ addition, property changes in \l{Working with States}{states} are highlighted
with blue.
This allows you to easily see which values are set in the component
diff --git a/doc/qtdesignstudio/src/views/qtquick-properties.qdoc b/doc/qtdesignstudio/src/views/qtquick-properties.qdoc
index d716932d94..0f7547c119 100644
--- a/doc/qtdesignstudio/src/views/qtquick-properties.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-properties.qdoc
@@ -153,7 +153,7 @@
If the \uicontrol Clip check box is selected, the component and its children
are clipped to the bounding rectangle of the component.
- in the \uicontrol State field, select the \l{Adding States}{state} to
+ in the \uicontrol State field, select the \l{Working with States}{state} to
change the value of a property in that state.
\section1 Picking Colors
diff --git a/doc/qtdesignstudio/src/views/qtquick-states-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-states-view.qdoc
index 4e22c1c52a..884b180461 100644
--- a/doc/qtdesignstudio/src/views/qtquick-states-view.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-states-view.qdoc
@@ -8,8 +8,8 @@
\title States
- The \uicontrol States view displays the different \l{Adding States}{states}
- of a UI.
+ The \uicontrol States view displays the different
+ \l{Working with States}{states} of a UI.
\image qmldesigner-transitions.png "States view"
diff --git a/doc/qtdesignstudio/src/views/qtquick-states.qdoc b/doc/qtdesignstudio/src/views/qtquick-states.qdoc
index 72aba97f1f..e4e23f899c 100644
--- a/doc/qtdesignstudio/src/views/qtquick-states.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-states.qdoc
@@ -11,7 +11,7 @@
\nextpage exporting-3d-assets.html
\endif
- \title Adding States
+ \title Working with States
You can define states for components and component instances in the
\l States view by selecting \inlineimage icons/plus.png
diff --git a/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc
index 120f34de83..ba8375e365 100644
--- a/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc
@@ -12,7 +12,7 @@
\uicontrol {Transitions} to animate the changes between
states.
- First, you need to \l{Adding States}{add states} in the \l States view
+ First, you need to \l{Working with States}{add states} in the \l States view
and \l{Specifying Component Properties}{edit some properties} that can be
animated, such as colors or numbers, in the \l Properties view. For example,
you can animate the changes in the position of a component.
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml
index 1b9a284ce1..f8c0605734 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml
@@ -24,6 +24,10 @@ Item {
// Array of supported externally dropped files that trigger custom import process
property var dropComplexExtFiles: []
+ AssetsContextMenu {
+ id: contextMenu
+ }
+
function clearSearchFilter()
{
searchBox.clear();
@@ -103,307 +107,11 @@ Item {
root.selectedAssetsChanged()
}
- StudioControls.Menu {
- id: contextMenu
-
- closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape
-
- onOpened: {
- var numSelected = Object.values(root.selectedAssets).filter(p => p).length
- deleteFileItem.text = numSelected > 1 ? qsTr("Delete Files") : qsTr("Delete File")
- }
-
- StudioControls.MenuItem {
- text: qsTr("Expand All")
- enabled: root.allExpandedState !== 1
- visible: root.isDirContextMenu
- height: visible ? implicitHeight : 0
- onTriggered: assetsModel.toggleExpandAll(true)
- }
-
- StudioControls.MenuItem {
- text: qsTr("Collapse All")
- enabled: root.allExpandedState !== 2
- visible: root.isDirContextMenu
- height: visible ? implicitHeight : 0
- onTriggered: assetsModel.toggleExpandAll(false)
- }
-
- StudioControls.MenuSeparator {
- visible: root.isDirContextMenu
- height: visible ? StudioTheme.Values.border : 0
- }
-
- StudioControls.MenuItem {
- id: deleteFileItem
- text: qsTr("Delete File")
- visible: root.contextFilePath
- height: deleteFileItem.visible ? deleteFileItem.implicitHeight : 0
- onTriggered: {
- assetsModel.deleteFiles(Object.keys(root.selectedAssets).filter(p => root.selectedAssets[p]))
- }
- }
-
- StudioControls.MenuSeparator {
- visible: root.contextFilePath
- height: visible ? StudioTheme.Values.border : 0
- }
-
- StudioControls.MenuItem {
- text: qsTr("Rename Folder")
- visible: root.isDirContextMenu
- height: visible ? implicitHeight : 0
- onTriggered: renameFolderDialog.open()
- }
-
- StudioControls.MenuItem {
- text: qsTr("New Folder")
- onTriggered: newFolderDialog.open()
- }
-
- StudioControls.MenuItem {
- text: qsTr("Delete Folder")
- visible: root.isDirContextMenu
- height: visible ? implicitHeight : 0
- onTriggered: {
- var dirEmpty = !(root.contextDir.dirsModel && root.contextDir.dirsModel.rowCount() > 0)
- && !(root.contextDir.filesModel && root.contextDir.filesModel.rowCount() > 0);
-
- if (dirEmpty)
- assetsModel.deleteFolder(root.contextDir.dirPath)
- else
- confirmDeleteFolderDialog.open()
- }
- }
- }
-
RegExpValidator {
id: folderNameValidator
regExp: /^(\w[^*/><?\\|:]*)$/
}
- Dialog {
- id: renameFolderDialog
-
- title: qsTr("Rename Folder")
- anchors.centerIn: parent
- closePolicy: Popup.CloseOnEscape
- implicitWidth: 280
- modal: true
-
- property bool renameError: false
-
- contentItem: Column {
- spacing: 2
-
- StudioControls.TextField {
- id: folderRename
-
- actionIndicator.visible: false
- translationIndicator.visible: false
- width: renameFolderDialog.width - 12
- validator: folderNameValidator
-
- onEditChanged: renameFolderDialog.renameError = false
- Keys.onEnterPressed: btnRename.onClicked()
- Keys.onReturnPressed: btnRename.onClicked()
- }
-
- Text {
- text: qsTr("Folder name cannot be empty.")
- color: "#ff0000"
- visible: folderRename.text === "" && !renameFolderDialog.renameError
- }
-
- Text {
- text: qsTr("Could not rename folder. Make sure no folder with the same name exists.")
- wrapMode: Text.WordWrap
- width: renameFolderDialog.width - 12
- color: "#ff0000"
- visible: renameFolderDialog.renameError
- }
-
- Item { // spacer
- width: 1
- height: 10
- }
-
- Text {
- text: qsTr("If the folder has assets in use, renaming it might cause the project to not work correctly.")
- color: StudioTheme.Values.themeTextColor
- wrapMode: Text.WordWrap
- width: renameFolderDialog.width
- leftPadding: 10
- rightPadding: 10
- }
-
- Item { // spacer
- width: 1
- height: 20
- }
-
- Row {
- anchors.right: parent.right
-
- Button {
- id: btnRename
-
- text: qsTr("Rename")
- enabled: folderRename.text !== ""
- onClicked: {
- var success = assetsModel.renameFolder(root.contextDir.dirPath, folderRename.text)
- if (success)
- renameFolderDialog.accept()
-
- renameFolderDialog.renameError = !success
- }
- }
-
- Button {
- text: qsTr("Cancel")
- onClicked: renameFolderDialog.reject()
- }
- }
- }
-
- onOpened: {
- folderRename.text = root.contextDir.dirName
- folderRename.selectAll()
- folderRename.forceActiveFocus()
- renameFolderDialog.renameError = false
- }
- }
-
- Dialog {
- id: newFolderDialog
-
- title: qsTr("Create New Folder")
- anchors.centerIn: parent
- closePolicy: Popup.CloseOnEscape
- modal: true
-
- contentItem: Column {
- spacing: 2
-
- Row {
- Text {
- text: qsTr("Folder name: ")
- anchors.verticalCenter: parent.verticalCenter
- color: StudioTheme.Values.themeTextColor
- }
-
- StudioControls.TextField {
- id: folderName
-
- actionIndicator.visible: false
- translationIndicator.visible: false
- validator: folderNameValidator
-
- Keys.onEnterPressed: btnCreate.onClicked()
- Keys.onReturnPressed: btnCreate.onClicked()
- }
- }
-
- Text {
- text: qsTr("Folder name cannot be empty.")
- color: "#ff0000"
- anchors.right: parent.right
- visible: folderName.text === ""
- }
-
- Item { // spacer
- width: 1
- height: 20
- }
-
- Row {
- anchors.right: parent.right
-
- Button {
- id: btnCreate
-
- text: qsTr("Create")
- enabled: folderName.text !== ""
- onClicked: {
- assetsModel.addNewFolder(root.contextDir.dirPath + '/' + folderName.text)
- newFolderDialog.accept()
- }
- }
-
- Button {
- text: qsTr("Cancel")
- onClicked: newFolderDialog.reject()
- }
- }
- }
-
- onOpened: {
- folderName.text = "New folder"
- folderName.selectAll()
- folderName.forceActiveFocus()
- }
- }
-
- Dialog {
- id: confirmDeleteFolderDialog
-
- title: qsTr("Folder Not Empty")
- anchors.centerIn: parent
- closePolicy: Popup.CloseOnEscape
- implicitWidth: 300
- modal: true
-
- contentItem: Column {
- spacing: 20
- width: parent.width
-
- Text {
- id: folderNotEmpty
-
- text: qsTr("Folder \"%1\" is not empty. Delete it anyway?")
- .arg(root.contextDir ? root.contextDir.dirName : "")
- color: StudioTheme.Values.themeTextColor
- wrapMode: Text.WordWrap
- width: confirmDeleteFolderDialog.width
- leftPadding: 10
- rightPadding: 10
-
- Keys.onEnterPressed: btnDelete.onClicked()
- Keys.onReturnPressed: btnDelete.onClicked()
- }
-
- Text {
- text: qsTr("If the folder has assets in use, deleting it might cause the project to not work correctly.")
- color: StudioTheme.Values.themeTextColor
- wrapMode: Text.WordWrap
- width: confirmDeleteFolderDialog.width
- leftPadding: 10
- rightPadding: 10
- }
-
- Row {
- anchors.right: parent.right
- Button {
- id: btnDelete
-
- text: qsTr("Delete")
-
- onClicked: {
- assetsModel.deleteFolder(root.contextDir.dirPath)
- confirmDeleteFolderDialog.accept()
- }
- }
-
- Button {
- text: qsTr("Cancel")
- onClicked: confirmDeleteFolderDialog.reject()
- }
- }
- }
-
- onOpened: folderNotEmpty.forceActiveFocus()
- }
-
Column {
anchors.fill: parent
anchors.topMargin: 5
@@ -507,220 +215,10 @@ Item {
}
}
- ScrollView { // TODO: experiment using ListView instead of ScrollView + Column
+ AssetsView {
id: assetsView
width: parent.width
height: parent.height - y
- clip: true
- interactive: assetsView.verticalScrollBarVisible && !contextMenu.opened
-
- Column {
- Repeater {
- model: assetsModel // context property
- delegate: dirSection
- }
-
- Component {
- id: dirSection
-
- Section {
- id: section
-
- width: assetsView.width -
- (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) - 5
- caption: dirName
- sectionHeight: 30
- sectionFontSize: 15
- leftPadding: 0
- topPadding: dirDepth > 0 ? 5 : 0
- bottomPadding: 0
- hideHeader: dirDepth === 0
- showLeftBorder: dirDepth > 0
- expanded: dirExpanded
- visible: dirVisible
- expandOnClick: false
- useDefaulContextMenu: false
- dropEnabled: true
-
- onToggleExpand: {
- dirExpanded = !dirExpanded
- }
-
- onDropEnter: (drag)=> {
- root.updateDropExtFiles(drag)
- section.highlight = drag.accepted && root.dropSimpleExtFiles.length > 0
- }
-
- onDropExit: {
- section.highlight = false
- }
-
- onDrop: {
- section.highlight = false
- rootView.handleExtFilesDrop(root.dropSimpleExtFiles,
- root.dropComplexExtFiles,
- dirPath)
- }
-
- onShowContextMenu: {
- root.contextFilePath = ""
- root.contextDir = model
- root.isDirContextMenu = true
- root.allExpandedState = assetsModel.getAllExpandedState()
- contextMenu.popup()
- }
-
- Column {
- spacing: 5
- leftPadding: 5
-
- Repeater {
- model: dirsModel
- delegate: dirSection
- }
-
- Repeater {
- model: filesModel
- delegate: fileSection
- }
-
- Text {
- text: qsTr("Empty folder")
- color: StudioTheme.Values.themeTextColorDisabled
- font.pixelSize: 12
- visible: !(dirsModel && dirsModel.rowCount() > 0)
- && !(filesModel && filesModel.rowCount() > 0)
-
- MouseArea {
- anchors.fill: parent
- acceptedButtons: Qt.RightButton
- onClicked: {
- root.contextFilePath = ""
- root.contextDir = model
- root.isDirContextMenu = true
- contextMenu.popup()
- }
- }
- }
- }
- }
- }
-
- Component {
- id: fileSection
-
- Rectangle {
- width: assetsView.width -
- (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0)
- height: img.height
- color: root.selectedAssets[filePath]
- ? StudioTheme.Values.themeInteraction
- : (mouseArea.containsMouse ? StudioTheme.Values.themeSectionHeadBackground
- : "transparent")
-
- Row {
- spacing: 5
-
- Image {
- id: img
- asynchronous: true
- fillMode: Image.PreserveAspectFit
- width: 48
- height: 48
- source: "image://qmldesigner_assets/" + filePath
- }
-
- Text {
- text: fileName
- color: StudioTheme.Values.themeTextColor
- font.pixelSize: 14
- anchors.verticalCenter: parent.verticalCenter
- }
- }
-
- readonly property string suffix: fileName.substr(-4)
- readonly property bool isFont: suffix === ".ttf" || suffix === ".otf"
- property bool currFileSelected: false
-
- MouseArea {
- id: mouseArea
-
- property bool allowTooltip: true
-
- anchors.fill: parent
- hoverEnabled: true
- acceptedButtons: Qt.LeftButton | Qt.RightButton
-
- onExited: tooltipBackend.hideTooltip()
- onEntered: allowTooltip = true
- onCanceled: {
- tooltipBackend.hideTooltip()
- allowTooltip = true
- }
- onPositionChanged: tooltipBackend.reposition()
- onPressed: (mouse)=> {
- forceActiveFocus()
- allowTooltip = false
- tooltipBackend.hideTooltip()
- var ctrlDown = mouse.modifiers & Qt.ControlModifier
- if (mouse.button === Qt.LeftButton) {
- if (!root.selectedAssets[filePath] && !ctrlDown)
- root.selectedAssets = {}
- currFileSelected = ctrlDown ? !root.selectedAssets[filePath] : true
- root.selectedAssets[filePath] = currFileSelected
- root.selectedAssetsChanged()
-
- if (currFileSelected) {
- rootView.startDragAsset(
- Object.keys(root.selectedAssets).filter(p => root.selectedAssets[p]),
- mapToGlobal(mouse.x, mouse.y))
- }
- } else {
- if (!root.selectedAssets[filePath] && !ctrlDown)
- root.selectedAssets = {}
- currFileSelected = root.selectedAssets[filePath] || !ctrlDown
- root.selectedAssets[filePath] = currFileSelected
- root.selectedAssetsChanged()
-
- root.contextFilePath = filePath
- root.contextDir = model.fileDir
- root.isDirContextMenu = false
-
- contextMenu.popup()
- }
- }
-
- onReleased: (mouse)=> {
- allowTooltip = true
- if (mouse.button === Qt.LeftButton) {
- if (!(mouse.modifiers & Qt.ControlModifier))
- root.selectedAssets = {}
- root.selectedAssets[filePath] = currFileSelected
- root.selectedAssetsChanged()
- }
- }
-
- ToolTip {
- visible: !isFont && mouseArea.containsMouse && !contextMenu.visible
- text: filePath
- delay: 1000
- }
-
- Timer {
- interval: 1000
- running: mouseArea.containsMouse && mouseArea.allowTooltip
- onTriggered: {
- if (suffix === ".ttf" || suffix === ".otf") {
- tooltipBackend.name = fileName
- tooltipBackend.path = filePath
- tooltipBackend.showTooltip()
- }
- }
- }
- }
- }
- }
- }
}
}
}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsContextMenu.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsContextMenu.qml
new file mode 100644
index 0000000000..5caa139651
--- /dev/null
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsContextMenu.qml
@@ -0,0 +1,120 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuickDesignerTheme
+import HelperWidgets as HelperWidgets
+import StudioControls as StudioControls
+import StudioTheme as StudioTheme
+
+StudioControls.Menu {
+ id: contextMenu
+
+ closePolicy: Popup.CloseOnPressOutside | Popup.CloseOnEscape
+
+ onOpened: {
+ var numSelected = Object.values(root.selectedAssets).filter(p => p).length
+ deleteFileItem.text = numSelected > 1 ? qsTr("Delete Files") : qsTr("Delete File")
+ }
+
+ StudioControls.MenuItem {
+ text: qsTr("Expand All")
+ enabled: root.allExpandedState !== 1
+ visible: root.isDirContextMenu
+ height: visible ? implicitHeight : 0
+ onTriggered: assetsModel.toggleExpandAll(true)
+ }
+
+ StudioControls.MenuItem {
+ text: qsTr("Collapse All")
+ enabled: root.allExpandedState !== 2
+ visible: root.isDirContextMenu
+ height: visible ? implicitHeight : 0
+ onTriggered: assetsModel.toggleExpandAll(false)
+ }
+
+ StudioControls.MenuSeparator {
+ visible: root.isDirContextMenu
+ height: visible ? StudioTheme.Values.border : 0
+ }
+
+ StudioControls.MenuItem {
+ id: deleteFileItem
+ text: qsTr("Delete File")
+ visible: root.contextFilePath
+ height: deleteFileItem.visible ? deleteFileItem.implicitHeight : 0
+ onTriggered: {
+ assetsModel.deleteFiles(Object.keys(root.selectedAssets).filter(p => root.selectedAssets[p]))
+ }
+ }
+
+ StudioControls.MenuSeparator {
+ visible: root.contextFilePath
+ height: visible ? StudioTheme.Values.border : 0
+ }
+
+ StudioControls.MenuItem {
+ text: qsTr("Rename Folder")
+ visible: root.isDirContextMenu
+ height: visible ? implicitHeight : 0
+ onTriggered: renameFolderDialog.open()
+
+ RenameFolderDialog {
+ id: renameFolderDialog
+ }
+ }
+
+ StudioControls.MenuItem {
+ text: qsTr("New Folder")
+
+ NewFolderDialog {
+ id: newFolderDialog
+ }
+
+ onTriggered: newFolderDialog.open()
+ }
+
+ StudioControls.MenuItem {
+ text: qsTr("Delete Folder")
+ visible: root.isDirContextMenu
+ height: visible ? implicitHeight : 0
+
+ ConfirmDeleteFolderDialog {
+ id: confirmDeleteFolderDialog
+ }
+
+ onTriggered: {
+ var dirEmpty = !(root.contextDir.dirsModel && root.contextDir.dirsModel.rowCount() > 0)
+ && !(root.contextDir.filesModel && root.contextDir.filesModel.rowCount() > 0);
+
+ if (dirEmpty)
+ assetsModel.deleteFolder(root.contextDir.dirPath)
+ else
+ confirmDeleteFolderDialog.open()
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsView.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsView.qml
new file mode 100644
index 0000000000..e1c017814d
--- /dev/null
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/AssetsView.qml
@@ -0,0 +1,246 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuickDesignerTheme
+import HelperWidgets
+import StudioControls as StudioControls
+import StudioTheme as StudioTheme
+
+ScrollView { // TODO: experiment using ListView instead of ScrollView + Column
+ id: assetsView
+ clip: true
+ interactive: assetsView.verticalScrollBarVisible && !contextMenu.opened
+
+ Column {
+ Repeater {
+ model: assetsModel // context property
+ delegate: dirSection
+ }
+
+ Component {
+ id: dirSection
+
+ Section {
+ id: section
+
+ width: assetsView.width -
+ (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) - 5
+ caption: dirName
+ sectionHeight: 30
+ sectionFontSize: 15
+ leftPadding: 0
+ topPadding: dirDepth > 0 ? 5 : 0
+ bottomPadding: 0
+ hideHeader: dirDepth === 0
+ showLeftBorder: dirDepth > 0
+ expanded: dirExpanded
+ visible: dirVisible
+ expandOnClick: false
+ useDefaulContextMenu: false
+ dropEnabled: true
+
+ onToggleExpand: {
+ dirExpanded = !dirExpanded
+ }
+
+ onDropEnter: (drag)=> {
+ root.updateDropExtFiles(drag)
+ section.highlight = drag.accepted && root.dropSimpleExtFiles.length > 0
+ }
+
+ onDropExit: {
+ section.highlight = false
+ }
+
+ onDrop: {
+ section.highlight = false
+ rootView.handleExtFilesDrop(root.dropSimpleExtFiles,
+ root.dropComplexExtFiles,
+ dirPath)
+ }
+
+ onShowContextMenu: {
+ root.contextFilePath = ""
+ root.contextDir = model
+ root.isDirContextMenu = true
+ root.allExpandedState = assetsModel.getAllExpandedState()
+ contextMenu.popup()
+ }
+
+ Column {
+ spacing: 5
+ leftPadding: 5
+
+ Repeater {
+ model: dirsModel
+ delegate: dirSection
+ }
+
+ Repeater {
+ model: filesModel
+ delegate: fileSection
+ }
+
+ Text {
+ text: qsTr("Empty folder")
+ color: StudioTheme.Values.themeTextColorDisabled
+ font.pixelSize: 12
+ visible: !(dirsModel && dirsModel.rowCount() > 0)
+ && !(filesModel && filesModel.rowCount() > 0)
+
+ MouseArea {
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton
+ onClicked: {
+ root.contextFilePath = ""
+ root.contextDir = model
+ root.isDirContextMenu = true
+ contextMenu.popup()
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Component {
+ id: fileSection
+
+ Rectangle {
+ width: assetsView.width -
+ (assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0)
+ height: img.height
+ color: root.selectedAssets[filePath]
+ ? StudioTheme.Values.themeInteraction
+ : (mouseArea.containsMouse ? StudioTheme.Values.themeSectionHeadBackground
+ : "transparent")
+
+ Row {
+ spacing: 5
+
+ Image {
+ id: img
+ asynchronous: true
+ fillMode: Image.PreserveAspectFit
+ width: 48
+ height: 48
+ source: "image://qmldesigner_assets/" + filePath
+ }
+
+ Text {
+ text: fileName
+ color: StudioTheme.Values.themeTextColor
+ font.pixelSize: 14
+ anchors.verticalCenter: parent.verticalCenter
+ }
+ }
+
+ readonly property string suffix: fileName.substr(-4)
+ readonly property bool isFont: suffix === ".ttf" || suffix === ".otf"
+ property bool currFileSelected: false
+
+ MouseArea {
+ id: mouseArea
+
+ property bool allowTooltip: true
+
+ anchors.fill: parent
+ hoverEnabled: true
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+
+ onExited: tooltipBackend.hideTooltip()
+ onEntered: allowTooltip = true
+ onCanceled: {
+ tooltipBackend.hideTooltip()
+ allowTooltip = true
+ }
+ onPositionChanged: tooltipBackend.reposition()
+ onPressed: (mouse)=> {
+ forceActiveFocus()
+ allowTooltip = false
+ tooltipBackend.hideTooltip()
+ var ctrlDown = mouse.modifiers & Qt.ControlModifier
+ if (mouse.button === Qt.LeftButton) {
+ if (!root.selectedAssets[filePath] && !ctrlDown)
+ root.selectedAssets = {}
+ currFileSelected = ctrlDown ? !root.selectedAssets[filePath] : true
+ root.selectedAssets[filePath] = currFileSelected
+ root.selectedAssetsChanged()
+
+ if (currFileSelected) {
+ rootView.startDragAsset(
+ Object.keys(root.selectedAssets).filter(p => root.selectedAssets[p]),
+ mapToGlobal(mouse.x, mouse.y))
+ }
+ } else {
+ if (!root.selectedAssets[filePath] && !ctrlDown)
+ root.selectedAssets = {}
+ currFileSelected = root.selectedAssets[filePath] || !ctrlDown
+ root.selectedAssets[filePath] = currFileSelected
+ root.selectedAssetsChanged()
+
+ root.contextFilePath = filePath
+ root.contextDir = model.fileDir
+ root.isDirContextMenu = false
+
+ contextMenu.popup()
+ }
+ }
+
+ onReleased: (mouse)=> {
+ allowTooltip = true
+ if (mouse.button === Qt.LeftButton) {
+ if (!(mouse.modifiers & Qt.ControlModifier))
+ root.selectedAssets = {}
+ root.selectedAssets[filePath] = currFileSelected
+ root.selectedAssetsChanged()
+ }
+ }
+
+ ToolTip {
+ visible: !isFont && mouseArea.containsMouse && !contextMenu.visible
+ text: filePath
+ delay: 1000
+ }
+
+ Timer {
+ interval: 1000
+ running: mouseArea.containsMouse && mouseArea.allowTooltip
+ onTriggered: {
+ if (suffix === ".ttf" || suffix === ".otf") {
+ tooltipBackend.name = fileName
+ tooltipBackend.path = filePath
+ tooltipBackend.showTooltip()
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/ConfirmDeleteFolderDialog.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ConfirmDeleteFolderDialog.qml
new file mode 100644
index 0000000000..a4fd300975
--- /dev/null
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/ConfirmDeleteFolderDialog.qml
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuickDesignerTheme
+import HelperWidgets
+import StudioControls as StudioControls
+import StudioTheme as StudioTheme
+
+Dialog {
+ id: confirmDeleteFolderDialog
+
+ title: qsTr("Folder Not Empty")
+ anchors.centerIn: parent
+ closePolicy: Popup.CloseOnEscape
+ implicitWidth: 300
+ modal: true
+
+ contentItem: Column {
+ spacing: 20
+ width: parent.width
+
+ Text {
+ id: folderNotEmpty
+
+ text: qsTr("Folder \"%1\" is not empty. Delete it anyway?")
+ .arg(root.contextDir ? root.contextDir.dirName : "")
+ color: StudioTheme.Values.themeTextColor
+ wrapMode: Text.WordWrap
+ width: confirmDeleteFolderDialog.width
+ leftPadding: 10
+ rightPadding: 10
+
+ Keys.onEnterPressed: btnDelete.onClicked()
+ Keys.onReturnPressed: btnDelete.onClicked()
+ }
+
+ Text {
+ text: qsTr("If the folder has assets in use, deleting it might cause the project to not work correctly.")
+ color: StudioTheme.Values.themeTextColor
+ wrapMode: Text.WordWrap
+ width: confirmDeleteFolderDialog.width
+ leftPadding: 10
+ rightPadding: 10
+ }
+
+ Row {
+ anchors.right: parent.right
+ Button {
+ id: btnDelete
+
+ text: qsTr("Delete")
+
+ onClicked: {
+ assetsModel.deleteFolder(root.contextDir.dirPath)
+ confirmDeleteFolderDialog.accept()
+ }
+ }
+
+ Button {
+ text: qsTr("Cancel")
+ onClicked: confirmDeleteFolderDialog.reject()
+ }
+ }
+ }
+
+ onOpened: folderNotEmpty.forceActiveFocus()
+}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/NewFolderDialog.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/NewFolderDialog.qml
new file mode 100644
index 0000000000..130026ddce
--- /dev/null
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/NewFolderDialog.qml
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuickDesignerTheme
+import HelperWidgets
+import StudioControls as StudioControls
+import StudioTheme as StudioTheme
+
+Dialog {
+ id: newFolderDialog
+
+ title: qsTr("Create New Folder")
+ anchors.centerIn: parent
+ closePolicy: Popup.CloseOnEscape
+ modal: true
+
+ contentItem: Column {
+ spacing: 2
+
+ Row {
+ Text {
+ text: qsTr("Folder name: ")
+ anchors.verticalCenter: parent.verticalCenter
+ color: StudioTheme.Values.themeTextColor
+ }
+
+ StudioControls.TextField {
+ id: folderName
+
+ actionIndicator.visible: false
+ translationIndicator.visible: false
+ validator: folderNameValidator
+
+ Keys.onEnterPressed: btnCreate.onClicked()
+ Keys.onReturnPressed: btnCreate.onClicked()
+ }
+ }
+
+ Text {
+ text: qsTr("Folder name cannot be empty.")
+ color: "#ff0000"
+ anchors.right: parent.right
+ visible: folderName.text === ""
+ }
+
+ Item { // spacer
+ width: 1
+ height: 20
+ }
+
+ Row {
+ anchors.right: parent.right
+
+ Button {
+ id: btnCreate
+
+ text: qsTr("Create")
+ enabled: folderName.text !== ""
+ onClicked: {
+ assetsModel.addNewFolder(root.contextDir.dirPath + '/' + folderName.text)
+ newFolderDialog.accept()
+ }
+ }
+
+ Button {
+ text: qsTr("Cancel")
+ onClicked: newFolderDialog.reject()
+ }
+ }
+ }
+
+ onOpened: {
+ folderName.text = qsTr("New folder")
+ folderName.selectAll()
+ folderName.forceActiveFocus()
+ }
+}
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/RenameFolderDialog.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/RenameFolderDialog.qml
new file mode 100644
index 0000000000..351c0a35fc
--- /dev/null
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/RenameFolderDialog.qml
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuickDesignerTheme
+import HelperWidgets
+import StudioControls as StudioControls
+import StudioTheme as StudioTheme
+
+Dialog {
+ id: renameFolderDialog
+
+ title: qsTr("Rename Folder")
+ anchors.centerIn: parent
+ closePolicy: Popup.CloseOnEscape
+ implicitWidth: 280
+ modal: true
+
+ property bool renameError: false
+
+ contentItem: Column {
+ spacing: 2
+
+ StudioControls.TextField {
+ id: folderRename
+
+ actionIndicator.visible: false
+ translationIndicator.visible: false
+ width: renameFolderDialog.width - 12
+ validator: folderNameValidator
+
+ onEditChanged: renameFolderDialog.renameError = false
+ Keys.onEnterPressed: btnRename.onClicked()
+ Keys.onReturnPressed: btnRename.onClicked()
+ }
+
+ Text {
+ text: qsTr("Folder name cannot be empty.")
+ color: "#ff0000"
+ visible: folderRename.text === "" && !renameFolderDialog.renameError
+ }
+
+ Text {
+ text: qsTr("Could not rename folder. Make sure no folder with the same name exists.")
+ wrapMode: Text.WordWrap
+ width: renameFolderDialog.width - 12
+ color: "#ff0000"
+ visible: renameFolderDialog.renameError
+ }
+
+ Item { // spacer
+ width: 1
+ height: 10
+ }
+
+ Text {
+ text: qsTr("If the folder has assets in use, renaming it might cause the project to not work correctly.")
+ color: StudioTheme.Values.themeTextColor
+ wrapMode: Text.WordWrap
+ width: renameFolderDialog.width
+ leftPadding: 10
+ rightPadding: 10
+ }
+
+ Item { // spacer
+ width: 1
+ height: 20
+ }
+
+ Row {
+ anchors.right: parent.right
+
+ Button {
+ id: btnRename
+
+ text: qsTr("Rename")
+ enabled: folderRename.text !== ""
+ onClicked: {
+ var success = assetsModel.renameFolder(root.contextDir.dirPath, folderRename.text)
+ if (success)
+ renameFolderDialog.accept()
+
+ renameFolderDialog.renameError = !success
+ }
+ }
+
+ Button {
+ text: qsTr("Cancel")
+ onClicked: renameFolderDialog.reject()
+ }
+ }
+ }
+
+ onOpened: {
+ folderRename.text = root.contextDir.dirName
+ folderRename.selectAll()
+ folderRename.forceActiveFocus()
+ renameFolderDialog.renameError = false
+ }
+}
diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/BundleMaterialItem.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/BundleMaterialItem.qml
index 4b8b45be56..59541f47d3 100644
--- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/BundleMaterialItem.qml
+++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/BundleMaterialItem.qml
@@ -27,6 +27,8 @@ import QtQuick 2.15
import QtQuick.Layouts 1.15
import QtQuickDesignerTheme 1.0
import HelperWidgets 2.0
+import QtQuick.Controls
+
import StudioTheme 1.0 as StudioTheme
Item {
@@ -43,7 +45,7 @@ Item {
acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: (mouse) => {
- if (mouse.button === Qt.LeftButton)
+ if (mouse.button === Qt.LeftButton && !materialBrowserBundleModel.importerRunning)
rootView.startDragBundleMaterial(modelData, mapToGlobal(mouse.x, mouse.y))
else if (mouse.button === Qt.RightButton)
root.showContextMenu()
@@ -64,6 +66,48 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter
source: modelData.bundleMaterialIcon
cache: false
+
+ Rectangle { // circular indicator for imported bundle materials
+ width: 10
+ height: 10
+ radius: 5
+ anchors.right: img.right
+ anchors.top: img.top
+ anchors.margins: 5
+ color: "#00ff00"
+ border.color: "#555555"
+ border.width: 1
+ visible: modelData.bundleMaterialImported
+
+ ToolTip {
+ visible: indicatorMouseArea.containsMouse
+ text: qsTr("Material is imported to project")
+ delay: 1000
+ }
+
+ MouseArea {
+ id: indicatorMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ }
+ }
+
+ IconButton {
+ icon: StudioTheme.Constants.plus
+ tooltip: qsTr("Add an instance to project")
+ buttonSize: 22
+ property color c: StudioTheme.Values.themeIconColor
+ normalColor: Qt.hsla(c.hslHue, c.hslSaturation, c.hslLightness, .2)
+ hoverColor: Qt.hsla(c.hslHue, c.hslSaturation, c.hslLightness, .3)
+ pressColor: Qt.hsla(c.hslHue, c.hslSaturation, c.hslLightness, .4)
+ anchors.right: img.right
+ anchors.bottom: img.bottom
+ enabled: !materialBrowserBundleModel.importerRunning
+
+ onClicked: {
+ materialBrowserBundleModel.addToProject(modelData)
+ }
+ }
}
TextInput {
diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml
index 4e3d921385..f60f4f150b 100644
--- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml
+++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml
@@ -24,8 +24,8 @@ Item {
// Called also from C++ to close context menu on focus out
function closeContextMenu()
{
- cxtMenu.close()
- cxtMenuBundle.close()
+ ctxMenu.close()
+ ctxMenuBundle.close()
}
// Called from C++ to refresh a preview material after it changes
@@ -57,7 +57,7 @@ Item {
if (!materialBrowserModel.hasMaterialRoot && (!materialBrowserBundleModel.matBundleExists
|| mouse.y < userMatsSecBottom)) {
root.currentMaterial = null
- cxtMenu.popup()
+ ctxMenu.popup()
}
}
}
@@ -75,8 +75,12 @@ Item {
}
}
+ UnimportBundleMaterialDialog {
+ id: unimportBundleMaterialDialog
+ }
+
StudioControls.Menu {
- id: cxtMenu
+ id: ctxMenu
closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
@@ -103,7 +107,10 @@ Item {
width: parent.width
onAboutToShow: {
- root.matSectionsModel = ["All"];
+ if (root.currentMaterial.hasDynamicProperties)
+ root.matSectionsModel = ["All", "Custom"];
+ else
+ root.matSectionsModel = ["All"];
switch (root.currentMaterial.materialType) {
case "DefaultMaterial":
@@ -180,7 +187,7 @@ Item {
}
StudioControls.Menu {
- id: cxtMenuBundle
+ id: ctxMenuBundle
closePolicy: StudioControls.Menu.CloseOnEscape | StudioControls.Menu.CloseOnPressOutside
@@ -199,9 +206,22 @@ Item {
StudioControls.MenuSeparator {}
StudioControls.MenuItem {
- text: qsTr("Add to project")
+ enabled: !materialBrowserBundleModel.importerRunning
+ text: qsTr("Add an instance to project")
- onTriggered: materialBrowserBundleModel.addMaterial(root.currentBundleMaterial)
+ onTriggered: {
+ materialBrowserBundleModel.addToProject(root.currentBundleMaterial)
+ }
+ }
+
+ StudioControls.MenuItem {
+ enabled: !materialBrowserBundleModel.importerRunning && root.currentBundleMaterial.bundleMaterialImported
+ text: qsTr("Remove from project")
+
+ onTriggered: {
+ unimportBundleMaterialDialog.targetBundleMaterial = root.currentBundleMaterial
+ unimportBundleMaterialDialog.open()
+ }
}
}
@@ -276,13 +296,14 @@ Item {
height: root.height - searchBox.height
clip: true
visible: materialBrowserModel.hasQuick3DImport && !materialBrowserModel.hasMaterialRoot
+ interactive: !ctxMenu.opened && !ctxMenuBundle.opened
Column {
Section {
id: userMaterialsSection
width: root.width
- caption: qsTr("User materials")
+ caption: qsTr("Materials")
hideHeader: !materialBrowserBundleModel.matBundleExists
Grid {
@@ -304,7 +325,7 @@ Item {
onShowContextMenu: {
root.currentMaterial = model
- cxtMenu.popup()
+ ctxMenu.popup()
}
}
}
@@ -367,7 +388,7 @@ Item {
onShowContextMenu: {
root.currentBundleMaterial = modelData
- cxtMenuBundle.popup()
+ ctxMenuBundle.popup()
}
}
}
diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/UnimportBundleMaterialDialog.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/UnimportBundleMaterialDialog.qml
new file mode 100644
index 0000000000..82708467a8
--- /dev/null
+++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/UnimportBundleMaterialDialog.qml
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuickDesignerTheme
+import HelperWidgets
+import StudioControls as StudioControls
+import StudioTheme as StudioTheme
+
+Dialog {
+ id: root
+
+ title: qsTr("Bundle material might be in use")
+ anchors.centerIn: parent
+ closePolicy: Popup.CloseOnEscape
+ implicitWidth: 300
+ modal: true
+
+ property var targetBundleMaterial
+
+ contentItem: Column {
+ spacing: 20
+ width: parent.width
+
+ Text {
+ id: folderNotEmpty
+
+ text: qsTr("If the material you are removing is in use, it might cause the project to malfunction.\n\nAre you sure you want to remove the material?")
+ color: StudioTheme.Values.themeTextColor
+ wrapMode: Text.WordWrap
+ anchors.right: parent.right
+ anchors.left: parent.left
+ leftPadding: 10
+ rightPadding: 10
+
+ Keys.onEnterPressed: btnRemove.onClicked()
+ Keys.onReturnPressed: btnRemove.onClicked()
+ }
+
+ Row {
+ anchors.right: parent.right
+ Button {
+ id: btnRemove
+
+ text: qsTr("Remove")
+
+ onClicked: {
+ materialBrowserBundleModel.removeFromProject(root.targetBundleMaterial)
+ root.accept()
+ }
+ }
+
+ Button {
+ text: qsTr("Cancel")
+ onClicked: root.reject()
+ }
+ }
+ }
+
+ onOpened: folderNotEmpty.forceActiveFocus()
+}
diff --git a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml
index cf767972e6..73e9865c19 100644
--- a/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml
+++ b/share/qtcreator/qmldesigner/materialEditorQmlSources/MaterialEditorTopSection.qml
@@ -175,6 +175,7 @@ Column {
// Section with hidden header is used so properties are aligned with the other sections' properties
hideHeader: true
width: parent.width
+ collapsible: false
SectionLayout {
PropertyLabel { text: qsTr("Name") }
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QML/QtObjectPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QML/QtObjectPane.qml
new file mode 100644
index 0000000000..cac322fcf8
--- /dev/null
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QML/QtObjectPane.qml
@@ -0,0 +1,29 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+import QtQuick 2.15
+import "../QtQuick" as Original
+
+Original.QtObjectPane {}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
index f532fee7e3..69a10570f8 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
@@ -29,6 +29,7 @@ Item {
property int level: 0
property int levelShift: 10
property bool hideHeader: false
+ property bool collapsible: true
property bool expandOnClick: true // if false, toggleExpand signal will be emitted instead
property bool addTopPadding: true
property bool addBottomPadding: true
@@ -48,7 +49,10 @@ Item {
Connections {
target: Controller
- function onCollapseAll() { section.expanded = false }
+ function onCollapseAll() {
+ if (collapsible)
+ section.expanded = false
+ }
function onExpandAll() { section.expanded = true }
}
@@ -120,6 +124,9 @@ Item {
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: function(mouse) {
if (mouse.button === Qt.LeftButton) {
+ if (!section.collapsible && section.expanded)
+ return
+
transition.enabled = true
if (section.expandOnClick)
section.expanded = !section.expanded
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml
index 5da47ce386..a1e39a9452 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/FilterComboBox.qml
@@ -521,21 +521,28 @@ Item {
]
Text {
- visible: root.autocompleteString !== ""
+ id: tmpSelectionName
+ visible: root.autocompleteString !== "" && root.open
text: root.autocompleteString
x: textInput.leftPadding + textMetrics.advanceWidth
- y: (textInput.height - Math.ceil(textMetrics.height)) / 2
+ y: (textInput.height - Math.ceil(tmpSelectionTextMetrics.height)) / 2
color: "gray" // TODO proper color value
font: textInput.font
renderType: textInput.renderType
- }
- TextMetrics {
- id: textMetrics
- font: textInput.font
- text: textInput.text
+ TextMetrics {
+ id: textMetrics
+ font: textInput.font
+ text: textInput.text
+ }
+ TextMetrics {
+ id: tmpSelectionTextMetrics
+ font: tmpSelectionName.font
+ text: "Xq"
+ }
}
+
Rectangle {
id: checkIndicator
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItem.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItem.qml
index 294446a637..e9925741b5 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItem.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/MenuItem.qml
@@ -48,6 +48,17 @@ T.MenuItem {
}
}
+ arrow: T.Label {
+ id: arrow
+ x: parent.width - (StudioTheme.Values.height + arrow.width) / 2
+ y: (parent.height - arrow.height) / 2
+ visible: control.subMenu
+ text: StudioTheme.Constants.startNode
+ color: StudioTheme.Values.themeTextColor
+ font.pixelSize: 8
+ font.family: StudioTheme.Constants.iconFont.family
+ }
+
background: Rectangle {
implicitWidth: textLabel.implicitWidth + control.labelSpacing + shortcutLabel.implicitWidth
+ control.leftPadding + control.rightPadding
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
index 9339fda0da..bc5fc4c538 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/InternalConstants.qml
@@ -49,128 +49,126 @@ QtObject {
readonly property string centerHorizontal: "\u0042"
readonly property string centerVertical: "\u0043"
readonly property string closeCross: "\u0044"
- readonly property string closeLink: "\u0045"
- readonly property string colorPopupClose: "\u0046"
- readonly property string columnsAndRows: "\u0047"
- readonly property string copyLink: "\u0048"
- readonly property string copyStyle: "\u0049"
- readonly property string cornerA: "\u004A"
- readonly property string cornerB: "\u004B"
- readonly property string cornersAll: "\u004C"
- readonly property string curveDesigner: "\u004D"
- readonly property string curveEditor: "\u004E"
- readonly property string customMaterialEditor: "\u004F"
- readonly property string decisionNode: "\u0050"
- readonly property string deleteColumn: "\u0051"
- readonly property string deleteMaterial: "\u0052"
- readonly property string deleteRow: "\u0053"
- readonly property string deleteTable: "\u0054"
- readonly property string detach: "\u0055"
- readonly property string distributeBottom: "\u0056"
- readonly property string distributeCenterHorizontal: "\u0057"
- readonly property string distributeCenterVertical: "\u0058"
- readonly property string distributeLeft: "\u0059"
- readonly property string distributeOriginBottomRight: "\u005A"
- readonly property string distributeOriginCenter: "\u005B"
- readonly property string distributeOriginNone: "\u005C"
- readonly property string distributeOriginTopLeft: "\u005D"
- readonly property string distributeRight: "\u005E"
- readonly property string distributeSpacingHorizontal: "\u005F"
- readonly property string distributeSpacingVertical: "\u0060"
- readonly property string distributeTop: "\u0061"
- readonly property string download: "\u0062"
- readonly property string downloadUnavailable: "\u0063"
- readonly property string downloadUpdate: "\u0064"
- readonly property string downloaded: "\u0065"
- readonly property string edit: "\u0066"
- readonly property string eyeDropper: "\u0067"
- readonly property string favorite: "\u0068"
- readonly property string flowAction: "\u0069"
- readonly property string flowTransition: "\u006A"
- readonly property string fontStyleBold: "\u006B"
- readonly property string fontStyleItalic: "\u006C"
- readonly property string fontStyleStrikethrough: "\u006D"
- readonly property string fontStyleUnderline: "\u006E"
- readonly property string gradient: "\u006F"
- readonly property string gridView: "\u0070"
- readonly property string idAliasOff: "\u0071"
- readonly property string idAliasOn: "\u0072"
- readonly property string infinity: "\u0073"
- readonly property string keyframe: "\u0074"
- readonly property string linkTriangle: "\u0075"
- readonly property string linked: "\u0076"
- readonly property string listView: "\u0077"
- readonly property string lockOff: "\u0078"
- readonly property string lockOn: "\u0079"
- readonly property string materialPreviewEnvironment: "\u007A"
- readonly property string materialPreviewModel: "\u007B"
- readonly property string mergeCells: "\u007C"
- readonly property string minus: "\u007D"
- readonly property string mirror: "\u007E"
- readonly property string newMaterial: "\u007F"
- readonly property string openLink: "\u0080"
- readonly property string openMaterialBrowser: "\u0081"
- readonly property string orientation: "\u0082"
- readonly property string paddingEdge: "\u0083"
- readonly property string paddingFrame: "\u0084"
- readonly property string pasteStyle: "\u0085"
- readonly property string pause: "\u0086"
- readonly property string pin: "\u0087"
- readonly property string play: "\u0088"
- readonly property string plus: "\u0089"
- readonly property string promote: "\u008A"
- readonly property string readOnly: "\u008B"
- readonly property string redo: "\u008C"
- readonly property string rotationFill: "\u008D"
- readonly property string rotationOutline: "\u008E"
- readonly property string search: "\u008F"
- readonly property string sectionToggle: "\u0090"
- readonly property string splitColumns: "\u0091"
- readonly property string splitRows: "\u0092"
- readonly property string startNode: "\u0093"
- readonly property string testIcon: "\u0094"
- readonly property string textAlignBottom: "\u0095"
- readonly property string textAlignCenter: "\u0096"
- readonly property string textAlignJustified: "\u0097"
- readonly property string textAlignLeft: "\u0098"
- readonly property string textAlignMiddle: "\u0099"
- readonly property string textAlignRight: "\u009A"
- readonly property string textAlignTop: "\u009B"
- readonly property string textBulletList: "\u009D"
- readonly property string textFullJustification: "\u009E"
- readonly property string textNumberedList: "\u009F"
- readonly property string tickIcon: "\u00A0"
- readonly property string translationCreateFiles: "\u00A1"
- readonly property string translationCreateReport: "\u00A2"
- readonly property string translationExport: "\u00A3"
- readonly property string translationImport: "\u00A4"
- readonly property string translationSelectLanguages: "\u00A5"
- readonly property string translationTest: "\u00A6"
- readonly property string transparent: "\u00A7"
- readonly property string triState: "\u00A8"
- readonly property string triangleArcA: "\u00A9"
- readonly property string triangleArcB: "\u00AA"
- readonly property string triangleCornerA: "\u00AB"
- readonly property string triangleCornerB: "\u00AC"
- readonly property string unLinked: "\u00AE"
- readonly property string undo: "\u00AF"
- readonly property string unpin: "\u00B0"
- readonly property string upDownIcon: "\u00B1"
- readonly property string upDownSquare2: "\u00B2"
- readonly property string visibilityOff: "\u00B3"
- readonly property string visibilityOn: "\u00B4"
- readonly property string wildcard: "\u00B5"
- readonly property string wizardsAutomotive: "\u00B6"
- readonly property string wizardsDesktop: "\u00B7"
- readonly property string wizardsGeneric: "\u00B8"
- readonly property string wizardsMcuEmpty: "\u00B9"
- readonly property string wizardsMcuGraph: "\u00BA"
- readonly property string wizardsMobile: "\u00BB"
- readonly property string wizardsUnknown: "\u00BC"
- readonly property string zoomAll: "\u00BD"
- readonly property string zoomIn: "\u00BE"
- readonly property string zoomOut: "\u00BF"
- readonly property string zoomSelection: "\u00C0"
+ readonly property string colorPopupClose: "\u0045"
+ readonly property string columnsAndRows: "\u0046"
+ readonly property string copyStyle: "\u0047"
+ readonly property string cornerA: "\u0048"
+ readonly property string cornerB: "\u0049"
+ readonly property string cornersAll: "\u004A"
+ readonly property string curveDesigner: "\u004B"
+ readonly property string curveEditor: "\u004C"
+ readonly property string customMaterialEditor: "\u004D"
+ readonly property string decisionNode: "\u004E"
+ readonly property string deleteColumn: "\u004F"
+ readonly property string deleteMaterial: "\u0050"
+ readonly property string deleteRow: "\u0051"
+ readonly property string deleteTable: "\u0052"
+ readonly property string detach: "\u0053"
+ readonly property string distributeBottom: "\u0054"
+ readonly property string distributeCenterHorizontal: "\u0055"
+ readonly property string distributeCenterVertical: "\u0056"
+ readonly property string distributeLeft: "\u0057"
+ readonly property string distributeOriginBottomRight: "\u0058"
+ readonly property string distributeOriginCenter: "\u0059"
+ readonly property string distributeOriginNone: "\u005A"
+ readonly property string distributeOriginTopLeft: "\u005B"
+ readonly property string distributeRight: "\u005C"
+ readonly property string distributeSpacingHorizontal: "\u005D"
+ readonly property string distributeSpacingVertical: "\u005E"
+ readonly property string distributeTop: "\u005F"
+ readonly property string download: "\u0060"
+ readonly property string downloadUnavailable: "\u0061"
+ readonly property string downloadUpdate: "\u0062"
+ readonly property string downloaded: "\u0063"
+ readonly property string edit: "\u0064"
+ readonly property string eyeDropper: "\u0065"
+ readonly property string favorite: "\u0066"
+ readonly property string flowAction: "\u0067"
+ readonly property string flowTransition: "\u0068"
+ readonly property string fontStyleBold: "\u0069"
+ readonly property string fontStyleItalic: "\u006A"
+ readonly property string fontStyleStrikethrough: "\u006B"
+ readonly property string fontStyleUnderline: "\u006C"
+ readonly property string gradient: "\u006D"
+ readonly property string gridView: "\u006E"
+ readonly property string idAliasOff: "\u006F"
+ readonly property string idAliasOn: "\u0070"
+ readonly property string imported: "\u0071"
+ readonly property string infinity: "\u0072"
+ readonly property string keyframe: "\u0073"
+ readonly property string linkTriangle: "\u0074"
+ readonly property string linked: "\u0075"
+ readonly property string listView: "\u0076"
+ readonly property string lockOff: "\u0077"
+ readonly property string lockOn: "\u0078"
+ readonly property string materialPreviewEnvironment: "\u0079"
+ readonly property string materialPreviewModel: "\u007A"
+ readonly property string mergeCells: "\u007B"
+ readonly property string minus: "\u007C"
+ readonly property string mirror: "\u007D"
+ readonly property string newMaterial: "\u007E"
+ readonly property string openMaterialBrowser: "\u007F"
+ readonly property string orientation: "\u0080"
+ readonly property string paddingEdge: "\u0081"
+ readonly property string paddingFrame: "\u0082"
+ readonly property string pasteStyle: "\u0083"
+ readonly property string pause: "\u0084"
+ readonly property string pin: "\u0085"
+ readonly property string play: "\u0086"
+ readonly property string plus: "\u0087"
+ readonly property string promote: "\u0088"
+ readonly property string readOnly: "\u0089"
+ readonly property string redo: "\u008A"
+ readonly property string rotationFill: "\u008B"
+ readonly property string rotationOutline: "\u008C"
+ readonly property string search: "\u008D"
+ readonly property string sectionToggle: "\u008E"
+ readonly property string splitColumns: "\u008F"
+ readonly property string splitRows: "\u0090"
+ readonly property string startNode: "\u0091"
+ readonly property string testIcon: "\u0092"
+ readonly property string textAlignBottom: "\u0093"
+ readonly property string textAlignCenter: "\u0094"
+ readonly property string textAlignJustified: "\u0095"
+ readonly property string textAlignLeft: "\u0096"
+ readonly property string textAlignMiddle: "\u0097"
+ readonly property string textAlignRight: "\u0098"
+ readonly property string textAlignTop: "\u0099"
+ readonly property string textBulletList: "\u009A"
+ readonly property string textFullJustification: "\u009B"
+ readonly property string textNumberedList: "\u009D"
+ readonly property string tickIcon: "\u009E"
+ readonly property string translationCreateFiles: "\u009F"
+ readonly property string translationCreateReport: "\u00A0"
+ readonly property string translationExport: "\u00A1"
+ readonly property string translationImport: "\u00A2"
+ readonly property string translationSelectLanguages: "\u00A3"
+ readonly property string translationTest: "\u00A4"
+ readonly property string transparent: "\u00A5"
+ readonly property string triState: "\u00A6"
+ readonly property string triangleArcA: "\u00A7"
+ readonly property string triangleArcB: "\u00A8"
+ readonly property string triangleCornerA: "\u00A9"
+ readonly property string triangleCornerB: "\u00AA"
+ readonly property string unLinked: "\u00AB"
+ readonly property string undo: "\u00AC"
+ readonly property string unpin: "\u00AE"
+ readonly property string upDownIcon: "\u00AF"
+ readonly property string upDownSquare2: "\u00B0"
+ readonly property string visibilityOff: "\u00B1"
+ readonly property string visibilityOn: "\u00B2"
+ readonly property string wildcard: "\u00B3"
+ readonly property string wizardsAutomotive: "\u00B4"
+ readonly property string wizardsDesktop: "\u00B5"
+ readonly property string wizardsGeneric: "\u00B6"
+ readonly property string wizardsMcuEmpty: "\u00B7"
+ readonly property string wizardsMcuGraph: "\u00B8"
+ readonly property string wizardsMobile: "\u00B9"
+ readonly property string wizardsUnknown: "\u00BA"
+ readonly property string zoomAll: "\u00BB"
+ readonly property string zoomIn: "\u00BC"
+ readonly property string zoomOut: "\u00BD"
+ readonly property string zoomSelection: "\u00BE"
readonly property font iconFont: Qt.font({
"family": controlIcons.name,
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
index acd8df6ce3..e3b40281c8 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/icons.ttf
Binary files differ
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 9d60367997..3510d3e190 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json
@@ -329,6 +329,10 @@
"target": "%{ProjectDirectory}/content/fonts/fonts.txt"
},
{
+ "source": "../common/asset_imports.txt",
+ "target": "%{ProjectDirectory}/asset_imports/asset_imports.txt"
+ },
+ {
"source": "../common/CMakeLists.imports.txt.tpl",
"target": "%{ProjectDirectory}/imports/CMakeLists.txt"
},
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json
index 6912200c14..68ffb6cff1 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json
@@ -325,6 +325,10 @@
"target": "%{ProjectDirectory}/content/fonts/fonts.txt"
},
{
+ "source": "../common/asset_imports.txt",
+ "target": "%{ProjectDirectory}/asset_imports/asset_imports.txt"
+ },
+ {
"source": "../common/CMakeLists.imports.txt.tpl",
"target": "%{ProjectDirectory}/imports/CMakeLists.txt"
},
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/asset_imports.txt b/share/qtcreator/qmldesigner/studio_templates/projects/common/asset_imports.txt
new file mode 100644
index 0000000000..84c843f100
--- /dev/null
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/asset_imports.txt
@@ -0,0 +1 @@
+Imported 3D assets and components imported from bundles will be created in this folder.
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json
index 20a3baba9c..ab1830752b 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json
@@ -324,6 +324,10 @@
"target": "%{ProjectDirectory}/content/fonts/fonts.txt"
},
{
+ "source": "../common/asset_imports.txt",
+ "target": "%{ProjectDirectory}/asset_imports/asset_imports.txt"
+ },
+ {
"source": "../common/CMakeLists.imports.txt.tpl",
"target": "%{ProjectDirectory}/imports/CMakeLists.txt"
},
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json
index 3117c7e054..1a9e07cb63 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json
@@ -281,6 +281,10 @@
"target": "%{ProjectDirectory}/content/fonts/fonts.txt"
},
{
+ "source": "../common/asset_imports.txt",
+ "target": "%{ProjectDirectory}/asset_imports/asset_imports.txt"
+ },
+ {
"source": "../common/CMakeLists.imports.txt.tpl",
"target": "%{ProjectDirectory}/imports/CMakeLists.txt"
},
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json
index cb083e84f4..2e07c4725a 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json
@@ -285,6 +285,10 @@
"target": "%{ProjectDirectory}/content/fonts/fonts.txt"
},
{
+ "source": "../common/asset_imports.txt",
+ "target": "%{ProjectDirectory}/asset_imports/asset_imports.txt"
+ },
+ {
"source": "../common/CMakeLists.imports.txt.tpl",
"target": "%{ProjectDirectory}/imports/CMakeLists.txt"
},
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json
index 1c1137afdd..422db17349 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json
@@ -285,6 +285,10 @@
"target": "%{ProjectDirectory}/content/fonts/fonts.txt"
},
{
+ "source": "../common/asset_imports.txt",
+ "target": "%{ProjectDirectory}/asset_imports/asset_imports.txt"
+ },
+ {
"source": "../common/CMakeLists.imports.txt.tpl",
"target": "%{ProjectDirectory}/imports/CMakeLists.txt"
},
diff --git a/src/app/main.cpp b/src/app/main.cpp
index db8ce6bde8..fbb02042c6 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -220,22 +220,35 @@ static void setupInstallSettings(QString &installSettingspath)
QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR), QLatin1String(Core::Constants::IDE_CASED_ID)));
installSettingspath.clear();
}
- // Check if the default install settings contain a setting for the actual install settings.
- // This can be an absolute path, or a path relative to applicationDirPath().
- // The result is interpreted like -settingspath, but for SystemScope
static const char kInstallSettingsKey[] = "Settings/InstallSettings";
QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope,
installSettingspath.isEmpty() ? resourcePath() : installSettingspath);
- QSettings installSettings(QSettings::IniFormat, QSettings::UserScope,
- QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR),
- QLatin1String(Core::Constants::IDE_CASED_ID));
- if (installSettings.contains(kInstallSettingsKey)) {
- QString installSettingsPath = installSettings.value(kInstallSettingsKey).toString();
- if (QDir::isRelativePath(installSettingsPath))
- installSettingsPath = applicationDirPath() + '/' + installSettingsPath;
- QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope, installSettingsPath);
- }
+ // Check if the default install settings contain a setting for the actual install settings.
+ // This can be an absolute path, or a path relative to applicationDirPath().
+ // The result is interpreted like -settingspath, but for SystemScope.
+ //
+ // Through the sdktool split that is upcoming, the new install settings might redirect
+ // yet a second time. So try this a few times.
+ // (Only the first time with QSettings::UserScope, to allow setting the install settings path
+ // in the user settings.)
+ QSettings::Scope scope = QSettings::UserScope;
+ int count = 0;
+ bool containsInstallSettingsKey = false;
+ do {
+ QSettings installSettings(QSettings::IniFormat, scope,
+ QLatin1String(Core::Constants::IDE_SETTINGSVARIANT_STR),
+ QLatin1String(Core::Constants::IDE_CASED_ID));
+ containsInstallSettingsKey = installSettings.contains(kInstallSettingsKey);
+ if (containsInstallSettingsKey) {
+ QString newInstallSettingsPath = installSettings.value(kInstallSettingsKey).toString();
+ if (QDir::isRelativePath(newInstallSettingsPath))
+ newInstallSettingsPath = applicationDirPath() + '/' + newInstallSettingsPath;
+ QSettings::setPath(QSettings::IniFormat, QSettings::SystemScope, newInstallSettingsPath);
+ }
+ scope = QSettings::SystemScope; // UserScope only the first time we check
+ ++count;
+ } while (containsInstallSettingsKey && count < 3);
}
static Utils::QtcSettings *createUserSettings()
diff --git a/src/plugins/mcusupport/mcusupportsdk.cpp b/src/plugins/mcusupport/mcusupportsdk.cpp
index b3f3a570cf..60e1e69f15 100644
--- a/src/plugins/mcusupport/mcusupportsdk.cpp
+++ b/src/plugins/mcusupport/mcusupportsdk.cpp
@@ -538,7 +538,7 @@ static McuAbstractTargetFactory::Ptr createFactory(bool isLegacy,
{"arm-greenhills",
McuPackagePtr{new McuPackage{settingsHandler,
{},
- toolchainFilePrefix / "arm-ghs.cmake",
+ toolchainFilePrefix / "ghs-arm.cmake",
{},
{},
Legacy::Constants::TOOLCHAIN_FILE_CMAKE_VARIABLE,
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
index 07205b5c73..1f665cb0b4 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
@@ -35,6 +35,25 @@ static Q_LOGGING_CATEGORY(assetsLibraryBenchmark, "qtc.assetsLibrary.setRoot", Q
namespace QmlDesigner {
+AssetsLibraryModel::AssetsLibraryModel(Utils::FileSystemWatcher *fileSystemWatcher, QObject *parent)
+ : QAbstractListModel(parent)
+ , m_fileSystemWatcher(fileSystemWatcher)
+{
+ // add role names
+ int role = 0;
+ const QMetaObject meta = AssetsLibraryDir::staticMetaObject;
+ for (int i = meta.propertyOffset(); i < meta.propertyCount(); ++i)
+ m_roleNames.insert(role++, meta.property(i).name());
+}
+
+void AssetsLibraryModel::setSearchText(const QString &searchText)
+{
+ if (m_searchText != searchText) {
+ m_searchText = searchText;
+ refresh();
+ }
+}
+
void AssetsLibraryModel::saveExpandedState(bool expanded, const QString &assetPath)
{
m_expandedStateHash.insert(assetPath, expanded);
@@ -186,66 +205,18 @@ QObject *AssetsLibraryModel::rootDir() const
return m_assetsDir;
}
-const QStringList &AssetsLibraryModel::supportedImageSuffixes()
-{
- static QStringList retList;
- if (retList.isEmpty()) {
- const QList<QByteArray> suffixes = QImageReader::supportedImageFormats();
- for (const QByteArray &suffix : suffixes)
- retList.append("*." + QString::fromUtf8(suffix));
- }
- return retList;
-}
-
-const QStringList &AssetsLibraryModel::supportedFragmentShaderSuffixes()
-{
- static const QStringList retList {"*.frag", "*.glsl", "*.glslf", "*.fsh"};
- return retList;
-}
-
-const QStringList &AssetsLibraryModel::supportedShaderSuffixes()
-{
- static const QStringList retList {"*.frag", "*.vert",
- "*.glsl", "*.glslv", "*.glslf",
- "*.vsh", "*.fsh"};
- return retList;
-}
-
-const QStringList &AssetsLibraryModel::supportedFontSuffixes()
-{
- static const QStringList retList {"*.ttf", "*.otf"};
- return retList;
-}
-
-const QStringList &AssetsLibraryModel::supportedAudioSuffixes()
-{
- static const QStringList retList {"*.wav", "*.mp3"};
- return retList;
-}
-
-const QStringList &AssetsLibraryModel::supportedVideoSuffixes()
-{
- static const QStringList retList {"*.mp4"};
- return retList;
-}
-
-const QStringList &AssetsLibraryModel::supportedTexture3DSuffixes()
+bool AssetsLibraryModel::isEmpty() const
{
- // These are file types only supported by 3D textures
- static QStringList retList {"*.hdr", "*.ktx"};
- return retList;
-}
+ return m_isEmpty;
+};
-AssetsLibraryModel::AssetsLibraryModel(Utils::FileSystemWatcher *fileSystemWatcher, QObject *parent)
- : QAbstractListModel(parent)
- , m_fileSystemWatcher(fileSystemWatcher)
+void AssetsLibraryModel::setIsEmpty(bool empty)
{
- // add role names
- int role = 0;
- const QMetaObject meta = AssetsLibraryDir::staticMetaObject;
- for (int i = meta.propertyOffset(); i < meta.propertyCount(); ++i)
- m_roleNames.insert(role++, meta.property(i).name());
-}
+ if (m_isEmpty != empty) {
+ m_isEmpty = empty;
+ emit isEmptyChanged();
+ }
+};
QVariant AssetsLibraryModel::data(const QModelIndex &index, int role) const
{
@@ -353,12 +324,54 @@ void AssetsLibraryModel::setRootPath(const QString &path)
qCInfo(assetsLibraryBenchmark) << "model reset:" << time.elapsed();
}
-void AssetsLibraryModel::setSearchText(const QString &searchText)
+const QStringList &AssetsLibraryModel::supportedImageSuffixes()
{
- if (m_searchText != searchText) {
- m_searchText = searchText;
- refresh();
+ static QStringList retList;
+ if (retList.isEmpty()) {
+ const QList<QByteArray> suffixes = QImageReader::supportedImageFormats();
+ for (const QByteArray &suffix : suffixes)
+ retList.append("*." + QString::fromUtf8(suffix));
}
+ return retList;
+}
+
+const QStringList &AssetsLibraryModel::supportedFragmentShaderSuffixes()
+{
+ static const QStringList retList {"*.frag", "*.glsl", "*.glslf", "*.fsh"};
+ return retList;
+}
+
+const QStringList &AssetsLibraryModel::supportedShaderSuffixes()
+{
+ static const QStringList retList {"*.frag", "*.vert",
+ "*.glsl", "*.glslv", "*.glslf",
+ "*.vsh", "*.fsh"};
+ return retList;
+}
+
+const QStringList &AssetsLibraryModel::supportedFontSuffixes()
+{
+ static const QStringList retList {"*.ttf", "*.otf"};
+ return retList;
+}
+
+const QStringList &AssetsLibraryModel::supportedAudioSuffixes()
+{
+ static const QStringList retList {"*.wav", "*.mp3"};
+ return retList;
+}
+
+const QStringList &AssetsLibraryModel::supportedVideoSuffixes()
+{
+ static const QStringList retList {"*.mp4"};
+ return retList;
+}
+
+const QStringList &AssetsLibraryModel::supportedTexture3DSuffixes()
+{
+ // These are file types only supported by 3D textures
+ static QStringList retList {"*.hdr", "*.ktx"};
+ return retList;
}
const QSet<QString> &AssetsLibraryModel::supportedSuffixes()
@@ -379,19 +392,6 @@ const QSet<QString> &AssetsLibraryModel::supportedSuffixes()
return allSuffixes;
}
-bool AssetsLibraryModel::isEmpty() const
-{
- return m_isEmpty;
-};
-
-void AssetsLibraryModel::setIsEmpty(bool empty)
-{
- if (m_isEmpty != empty) {
- m_isEmpty = empty;
- emit isEmptyChanged();
- }
-};
-
const QSet<QString> &AssetsLibraryModel::previewableSuffixes() const
{
static QSet<QString> previewableSuffixes;
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp
index 5dbb7102f4..e652fcd74f 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp
@@ -69,6 +69,8 @@ bool AssetsLibraryWidget::eventFilter(QObject *obj, QEvent *event)
m_assetsToDrag.clear();
}
}
+ } else if (event->type() == QMouseEvent::MouseButtonRelease) {
+ m_assetsToDrag.clear();
}
return QObject::eventFilter(obj, event);
diff --git a/src/plugins/qmldesigner/components/componentcore/theme.h b/src/plugins/qmldesigner/components/componentcore/theme.h
index e9b751e49d..eb922fb6d9 100644
--- a/src/plugins/qmldesigner/components/componentcore/theme.h
+++ b/src/plugins/qmldesigner/components/componentcore/theme.h
@@ -57,10 +57,8 @@ public:
centerHorizontal,
centerVertical,
closeCross,
- closeLink,
colorPopupClose,
columnsAndRows,
- copyLink,
copyStyle,
cornerA,
cornerB,
@@ -103,6 +101,7 @@ public:
gridView,
idAliasOff,
idAliasOn,
+ imported,
infinity,
keyframe,
linkTriangle,
@@ -116,7 +115,6 @@ public:
minus,
mirror,
newMaterial,
- openLink,
openMaterialBrowser,
orientation,
paddingEdge,
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
index c10799b6c5..b41a316513 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
@@ -14,6 +14,7 @@
#include "viewmanager.h"
#include <seekerslider.h>
#include <nodeinstanceview.h>
+#include <import.h>
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/command.h>
@@ -208,14 +209,21 @@ void Edit3DWidget::updateCreateSubMenu(const QStringList &keys,
void Edit3DWidget::onCreateAction()
{
// QAction *action = qobject_cast<QAction *>(sender());
- // if (!action)
+ // if (!action || !m_view || !m_view->model())
// return;
// m_view->executeInTransaction(__FUNCTION__, [&] {
- // int activeScene = m_view->rootModelNode().auxiliaryData("active3dScene@Internal").toInt();
+ // ItemLibraryEntry entry = m_nameToEntry.value(action->data().toString());
+ // Import import = Import::createLibraryImport(entry.requiredImport(),
+ // QString::number(entry.majorVersion())
+ // + QLatin1Char('.')
+ // + QString::number(entry.minorVersion()));
+ // if (!m_view->model()->hasImport(import))
+ // m_view->model()->changeImports({import}, {});
- // auto modelNode = QmlVisualNode::createQml3DNode(m_view, m_nameToEntry.value(action->data().toString()),
- // activeScene, m_contextMenuPos3d).modelNode();
+ // int activeScene = m_view->rootModelNode().auxiliaryData("active3dScene@Internal").toInt();
+ // auto modelNode = QmlVisualNode::createQml3DNode(m_view, entry,
+ // activeScene, m_contextMenuPos3d).modelNode();
// QTC_ASSERT(modelNode.isValid(), return);
// m_view->setSelectedModelNode(modelNode);
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
index cb955174af..dac6a0b8aa 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
@@ -273,8 +273,10 @@ void ItemLibraryWidget::delayedUpdateModel()
void ItemLibraryWidget::setModel(Model *model)
{
m_model = model;
- if (!model)
+ if (!model) {
+ m_itemToDrag = {};
return;
+ }
setItemLibraryInfo(model->metaInfo().itemLibraryInfo());
diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundleimporter.cpp b/src/plugins/qmldesigner/components/materialbrowser/bundleimporter.cpp
index 62d122d14c..2a31fa8885 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/bundleimporter.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/bundleimporter.cpp
@@ -97,9 +97,10 @@ QString BundleImporter::importComponent(const QString &qmlFile,
FilePath qmlSourceFile = bundleImportPath.resolvePath(FilePath::fromString(qmlFile));
const bool qmlFileExists = qmlSourceFile.exists();
const QString qmlType = qmlSourceFile.baseName();
- m_pendingTypes.append(QStringLiteral("%1.%2.%3")
- .arg(QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1),
- m_bundleId, qmlType));
+ const QString fullTypeName = QStringLiteral("%1.%2.%3")
+ .arg(QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1), m_bundleId, qmlType);
+ if (m_pendingTypes.contains(fullTypeName) && !m_pendingTypes[fullTypeName])
+ return QStringLiteral("Unable to import while unimporting the same type: '%1'").arg(fullTypeName);
if (!qmldirContent.contains(qmlFile)) {
qmldirContent.append(qmlType);
qmldirContent.append(" 1.0 ");
@@ -162,6 +163,7 @@ QString BundleImporter::importComponent(const QString &qmlFile,
m_importAddPending = true;
}
}
+ m_pendingTypes.insert(fullTypeName, true);
m_importTimerCount = 0;
m_importTimer.start();
@@ -175,8 +177,16 @@ void BundleImporter::handleImportTimer()
m_fullReset = false;
m_importAddPending = false;
m_importTimerCount = 0;
- m_pendingTypes.clear();
- emit importFinished({});
+
+ // Emit dummy finished signals for all pending types
+ const QStringList pendingTypes = m_pendingTypes.keys();
+ for (const QString &pendingType : pendingTypes) {
+ m_pendingTypes.remove(pendingType);
+ if (m_pendingTypes[pendingType])
+ emit importFinished({});
+ else
+ emit unimportFinished({});
+ }
};
auto doc = QmlDesignerPlugin::instance()->currentDesignDocument();
@@ -210,12 +220,17 @@ void BundleImporter::handleImportTimer()
}
// Detect when the code model has the new material(s) fully available
- const QStringList pendingTypes = m_pendingTypes;
+ const QStringList pendingTypes = m_pendingTypes.keys();
for (const QString &pendingType : pendingTypes) {
NodeMetaInfo metaInfo = model->metaInfo(pendingType.toUtf8());
- if (metaInfo.isValid() && !metaInfo.superClasses().empty()) {
- m_pendingTypes.removeAll(pendingType);
- emit importFinished(metaInfo);
+ const bool isImport = m_pendingTypes[pendingType];
+ const bool typeComplete = metaInfo.isValid() && !metaInfo.superClasses().empty();
+ if (isImport == typeComplete) {
+ m_pendingTypes.remove(pendingType);
+ if (isImport)
+ emit importFinished(metaInfo);
+ else
+ emit unimportFinished(metaInfo);
}
}
@@ -257,14 +272,14 @@ QString BundleImporter::unimportComponent(const QString &qmlFile)
{
FilePath bundleImportPath = resolveBundleImportPath();
if (bundleImportPath.isEmpty())
- return "Failed to resolve bundle import folder";
+ return QStringLiteral("Failed to resolve bundle import folder for: '%1'").arg(qmlFile);
if (!bundleImportPath.exists())
- return {};
+ return QStringLiteral("Unable to find bundle path: '%1'").arg(bundleImportPath.toString());
FilePath qmlFilePath = bundleImportPath.resolvePath(qmlFile);
if (!qmlFilePath.exists())
- return {};
+ return QStringLiteral("Unable to find specified file: '%1'").arg(qmlFilePath.toString());
QStringList removedFiles;
removedFiles.append(qmlFile);
@@ -272,9 +287,15 @@ QString BundleImporter::unimportComponent(const QString &qmlFile)
FilePath qmldirPath = bundleImportPath.resolvePath(QStringLiteral("qmldir"));
const std::optional<QByteArray> qmldirContent = qmldirPath.fileContents();
QByteArray newContent;
+
+ QString qmlType = qmlFilePath.baseName();
+ const QString fullTypeName = QStringLiteral("%1.%2.%3")
+ .arg(QLatin1String(Constants::COMPONENT_BUNDLES_FOLDER).mid(1), m_bundleId, qmlType);
+ if (m_pendingTypes.contains(fullTypeName) && m_pendingTypes[fullTypeName])
+ return QStringLiteral("Unable to unimport while importing the same type: '%1'").arg(fullTypeName);
+
if (qmldirContent) {
- QByteArray qmlType = qmlFilePath.baseName().toUtf8();
- int typeIndex = qmldirContent->indexOf(qmlType);
+ int typeIndex = qmldirContent->indexOf(qmlType.toUtf8());
if (typeIndex != -1) {
int newLineIndex = qmldirContent->indexOf('\n', typeIndex);
newContent = qmldirContent->left(typeIndex);
@@ -287,6 +308,8 @@ QString BundleImporter::unimportComponent(const QString &qmlFile)
}
}
+ m_pendingTypes.insert(fullTypeName, false);
+
QVariantHash assetRefMap = loadAssetRefMap(bundleImportPath);
bool writeAssetRefs = false;
const auto keys = assetRefMap.keys();
diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundleimporter.h b/src/plugins/qmldesigner/components/materialbrowser/bundleimporter.h
index b22d0edd59..64344915ce 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/bundleimporter.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/bundleimporter.h
@@ -51,18 +51,19 @@ public:
QString importComponent(const QString &qmlFile,
const QStringList &files);
QString unimportComponent(const QString &qmlFile);
+ Utils::FilePath resolveBundleImportPath();
signals:
// The metaInfo parameter will be invalid if an error was encountered during
// asynchronous part of the import. In this case all remaining pending imports have been
// terminated, and will not receive separate importFinished notifications.
void importFinished(const QmlDesigner::NodeMetaInfo &metaInfo);
+ void unimportFinished(const QmlDesigner::NodeMetaInfo &metaInfo);
private:
void handleImportTimer();
QVariantHash loadAssetRefMap(const Utils::FilePath &bundlePath);
void writeAssetRefMap(const Utils::FilePath &bundlePath, const QVariantHash &assetRefMap);
- Utils::FilePath resolveBundleImportPath();
Utils::FilePath m_bundleDir;
QString m_bundleId;
@@ -72,7 +73,7 @@ private:
int m_importTimerCount = 0;
bool m_importAddPending = false;
bool m_fullReset = false;
- QStringList m_pendingTypes;
+ QHash<QString, bool> m_pendingTypes; // <type, isImport>
};
} // namespace QmlDesigner::Internal
diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.cpp b/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.cpp
index b5bc19e785..6cee76475a 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.cpp
@@ -70,4 +70,20 @@ bool BundleMaterial::visible() const
return m_visible;
}
+bool BundleMaterial::setImported(bool imported)
+{
+ if (m_imported != imported) {
+ m_imported = imported;
+ emit materialImportedChanged();
+ return true;
+ }
+
+ return false;
+}
+
+bool BundleMaterial::imported() const
+{
+ return m_imported;
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.h b/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.h
index ae74a13d75..64d79aa65e 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/bundlematerial.h
@@ -40,6 +40,7 @@ class BundleMaterial : public QObject
Q_PROPERTY(QString bundleMaterialName MEMBER m_name CONSTANT)
Q_PROPERTY(QUrl bundleMaterialIcon MEMBER m_icon CONSTANT)
Q_PROPERTY(bool bundleMaterialVisible MEMBER m_visible NOTIFY materialVisibleChanged)
+ Q_PROPERTY(bool bundleMaterialImported READ imported WRITE setImported NOTIFY materialImportedChanged)
public:
BundleMaterial(QObject *parent,
@@ -57,8 +58,12 @@ public:
QStringList files() const;
bool visible() const;
+ bool setImported(bool imported);
+ bool imported() const;
+
signals:
void materialVisibleChanged();
+ void materialImportedChanged();
private:
QString m_name;
@@ -68,6 +73,7 @@ private:
QStringList m_files;
bool m_visible = true;
+ bool m_imported = false;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.cpp b/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.cpp
index 9a18ff7501..716fb57dbf 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.cpp
@@ -37,6 +37,16 @@ void BundleMaterialCategory::addBundleMaterial(BundleMaterial *bundleMat)
m_categoryMaterials.append(bundleMat);
}
+bool BundleMaterialCategory::updateImportedState(const QStringList &importedMats)
+{
+ bool changed = false;
+
+ for (BundleMaterial *mat : std::as_const(m_categoryMaterials))
+ changed |= mat->setImported(importedMats.contains(mat->qml().chopped(4)));
+
+ return changed;
+}
+
bool BundleMaterialCategory::filter(const QString &searchText)
{
bool visible = false;
diff --git a/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.h b/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.h
index 0a3a0f7c02..2336a03d01 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/bundlematerialcategory.h
@@ -42,6 +42,7 @@ public:
BundleMaterialCategory(QObject *parent, const QString &name);
void addBundleMaterial(BundleMaterial *bundleMat);
+ bool updateImportedState(const QStringList &importedMats);
bool filter(const QString &searchText);
QString name() const;
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.cpp
index 4e70008f1a..a43a23a1d1 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.cpp
@@ -122,7 +122,7 @@ void MaterialBrowserBundleModel::loadMaterialBundle()
m_matBundleExists = true;
- const QString bundleId = m_matBundleObj.value("id").toString();
+ QString bundleId = m_matBundleObj.value("id").toString();
const QJsonObject catsObj = m_matBundleObj.value("categories").toObject();
const QStringList categories = catsObj.keys();
@@ -160,8 +160,17 @@ void MaterialBrowserBundleModel::loadMaterialBundle()
m_importer = new Internal::BundleImporter(matBundleDir.path(), bundleId, sharedFiles);
connect(m_importer, &Internal::BundleImporter::importFinished, this, [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
+ m_importerRunning = false;
+ emit importerRunningChanged();
if (metaInfo.isValid())
- emit addBundleMaterialToProjectRequested(metaInfo);
+ emit bundleMaterialImported(metaInfo);
+ });
+
+ connect(m_importer, &Internal::BundleImporter::unimportFinished, this, [&](const QmlDesigner::NodeMetaInfo &metaInfo) {
+ Q_UNUSED(metaInfo)
+ m_importerRunning = false;
+ emit importerRunningChanged();
+ emit bundleMaterialUnimported(metaInfo);
});
}
@@ -193,6 +202,11 @@ void MaterialBrowserBundleModel::setHasMaterialRoot(bool b)
emit hasMaterialRootChanged();
}
+Internal::BundleImporter *MaterialBrowserBundleModel::bundleImporter() const
+{
+ return m_importer;
+}
+
void MaterialBrowserBundleModel::setSearchText(const QString &searchText)
{
QString lowerSearchText = searchText.toLower();
@@ -219,6 +233,16 @@ void MaterialBrowserBundleModel::setSearchText(const QString &searchText)
resetModel();
}
+void MaterialBrowserBundleModel::updateImportedState(const QStringList &importedMats)
+{
+ bool changed = false;
+ for (BundleMaterialCategory *cat : std::as_const(m_bundleCategories))
+ changed |= cat->updateImportedState(importedMats);
+
+ if (changed)
+ resetModel();
+}
+
void MaterialBrowserBundleModel::resetModel()
{
beginResetModel();
@@ -230,12 +254,30 @@ void MaterialBrowserBundleModel::applyToSelected(BundleMaterial *mat, bool add)
emit applyToSelectedTriggered(mat, add);
}
-void MaterialBrowserBundleModel::addMaterial(BundleMaterial *mat)
+void MaterialBrowserBundleModel::addToProject(BundleMaterial *mat)
{
QString err = m_importer->importComponent(mat->qml(), mat->files());
- if (!err.isEmpty())
+ if (err.isEmpty()) {
+ m_importerRunning = true;
+ emit importerRunningChanged();
+ } else {
qWarning() << __FUNCTION__ << err;
+ }
+}
+
+void MaterialBrowserBundleModel::removeFromProject(BundleMaterial *mat)
+{
+ emit bundleMaterialAboutToUnimport(mat->type());
+
+ QString err = m_importer->unimportComponent(mat->qml());
+
+ if (err.isEmpty()) {
+ m_importerRunning = true;
+ emit importerRunningChanged();
+ } else {
+ qWarning() << __FUNCTION__ << err;
+ }
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.h
index 60b48f1c9b..8197ebd78b 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserbundlemodel.h
@@ -50,6 +50,7 @@ class MaterialBrowserBundleModel : public QAbstractListModel
Q_PROPERTY(bool isEmpty MEMBER m_isEmpty NOTIFY isEmptyChanged)
Q_PROPERTY(bool hasQuick3DImport READ hasQuick3DImport WRITE setHasQuick3DImport NOTIFY hasQuick3DImportChanged)
Q_PROPERTY(bool hasMaterialRoot READ hasMaterialRoot WRITE setHasMaterialRoot NOTIFY hasMaterialRootChanged)
+ Q_PROPERTY(bool importerRunning MEMBER m_importerRunning NOTIFY importerRunningChanged)
public:
MaterialBrowserBundleModel(QObject *parent = nullptr);
@@ -59,6 +60,7 @@ public:
QHash<int, QByteArray> roleNames() const override;
void setSearchText(const QString &searchText);
+ void updateImportedState(const QStringList &importedMats);
bool hasQuick3DImport() const;
void setHasQuick3DImport(bool b);
@@ -66,10 +68,13 @@ public:
bool hasMaterialRoot() const;
void setHasMaterialRoot(bool b);
+ Internal::BundleImporter *bundleImporter() const;
+
void resetModel();
Q_INVOKABLE void applyToSelected(QmlDesigner::BundleMaterial *mat, bool add = false);
- Q_INVOKABLE void addMaterial(QmlDesigner::BundleMaterial *mat);
+ Q_INVOKABLE void addToProject(QmlDesigner::BundleMaterial *mat);
+ Q_INVOKABLE void removeFromProject(QmlDesigner::BundleMaterial *mat);
signals:
void isEmptyChanged();
@@ -77,7 +82,10 @@ signals:
void hasMaterialRootChanged();
void materialVisibleChanged();
void applyToSelectedTriggered(QmlDesigner::BundleMaterial *mat, bool add = false);
- void addBundleMaterialToProjectRequested(const QmlDesigner::NodeMetaInfo &metaInfo);
+ void bundleMaterialImported(const QmlDesigner::NodeMetaInfo &metaInfo);
+ void bundleMaterialAboutToUnimport(const QmlDesigner::TypeName &type);
+ void bundleMaterialUnimported(const QmlDesigner::NodeMetaInfo &metaInfo);
+ void importerRunningChanged();
private:
void loadMaterialBundle();
@@ -93,6 +101,7 @@ private:
bool m_hasMaterialRoot = false;
bool m_matBundleExists = false;
bool m_probeMatBundleDir = false;
+ bool m_importerRunning = false;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp
index c075a582e4..58c867782d 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.cpp
@@ -51,6 +51,9 @@ QVariant MaterialBrowserModel::data(const QModelIndex &index, int role) const
return matType;
}
+ if (roleName == "hasDynamicProperties")
+ return !m_materialList.at(index.row()).dynamicProperties().isEmpty();
+
return {};
}
@@ -121,7 +124,8 @@ QHash<int, QByteArray> MaterialBrowserModel::roleNames() const
{Qt::UserRole + 1, "materialName"},
{Qt::UserRole + 2, "materialInternalId"},
{Qt::UserRole + 3, "materialVisible"},
- {Qt::UserRole + 4, "materialType"}
+ {Qt::UserRole + 4, "materialType"},
+ {Qt::UserRole + 5, "hasDynamicProperties"}
};
return roles;
}
@@ -338,33 +342,47 @@ void MaterialBrowserModel::copyMaterialProperties(int idx, const QString &sectio
setCopiedMaterialType(matType);
m_allPropsCopied = section == "All";
+ bool dynamicPropsCopied = section == "Custom";
QmlObjectNode mat(m_copiedMaterial);
QSet<PropertyName> validProps;
+ QHash<PropertyName, TypeName> dynamicProps;
PropertyNameList copiedProps;
- // Base state properties are always valid
- const auto baseProps = m_copiedMaterial.propertyNames();
- for (const auto &baseProp : baseProps)
- validProps.insert(baseProp);
-
- if (!mat.isInBaseState()) {
- QmlPropertyChanges changes = mat.propertyChangeForCurrentState();
- if (changes.isValid()) {
- const QList<AbstractProperty> changedProps = changes.targetProperties();
- for (const auto &changedProp : changedProps)
- validProps.insert(changedProp.name());
+ if (dynamicPropsCopied || m_allPropsCopied) {
+ // Dynamic properties must always be set in base state
+ const QList<AbstractProperty> dynProps = m_copiedMaterial.dynamicProperties();
+ for (const auto &prop : dynProps) {
+ dynamicProps.insert(prop.name(), prop.dynamicTypeName());
+ validProps.insert(prop.name());
}
}
- if (mat.timelineIsActive()) {
- const QList<QmlTimelineKeyframeGroup> keyframeGroups
- = mat.currentTimeline().keyframeGroupsForTarget(m_copiedMaterial);
- for (const auto &kfg : keyframeGroups)
- validProps.insert(kfg.propertyName());
+ if (!dynamicPropsCopied) {
+ // Base state properties are always valid
+ const auto baseProps = m_copiedMaterial.propertyNames();
+ for (const auto &baseProp : baseProps)
+ validProps.insert(baseProp);
+
+ if (!mat.isInBaseState()) {
+ QmlPropertyChanges changes = mat.propertyChangeForCurrentState();
+ if (changes.isValid()) {
+ const QList<AbstractProperty> changedProps = changes.targetProperties();
+ for (const auto &changedProp : changedProps)
+ validProps.insert(changedProp.name());
+ }
+ }
+
+ if (mat.timelineIsActive()) {
+ const QList<QmlTimelineKeyframeGroup> keyframeGroups
+ = mat.currentTimeline().keyframeGroupsForTarget(m_copiedMaterial);
+ for (const auto &kfg : keyframeGroups)
+ validProps.insert(kfg.propertyName());
+ }
}
+ validProps.remove("objectName");
- if (m_allPropsCopied || m_propertyGroupsObj.empty()) {
+ if (m_allPropsCopied || dynamicPropsCopied || m_propertyGroupsObj.empty()) {
copiedProps = validProps.values();
} else {
QJsonObject propsSpecObj = m_propertyGroupsObj.value(m_copiedMaterialType).toObject();
@@ -389,8 +407,10 @@ void MaterialBrowserModel::copyMaterialProperties(int idx, const QString &sectio
PropertyCopyData data;
data.name = propName;
data.isValid = m_allPropsCopied || validProps.contains(propName);
- data.isBinding = mat.hasBindingProperty(propName);
if (data.isValid) {
+ if (dynamicProps.contains(propName))
+ data.dynamicTypeName = dynamicProps[propName];
+ data.isBinding = mat.hasBindingProperty(propName);
if (data.isBinding)
data.value = mat.expression(propName);
else
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h
index 8635c1f1b0..2e4a4fc5cb 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsermodel.h
@@ -75,6 +75,7 @@ public:
struct PropertyCopyData
{
PropertyName name;
+ TypeName dynamicTypeName;
QVariant value;
bool isBinding = false;
bool isValid = false;
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
index feb38e1cff..64b7f6ccd8 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
@@ -2,8 +2,10 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "materialbrowserview.h"
+
#include "bindingproperty.h"
#include "bundlematerial.h"
+#include "bundleimporter.h"
#include "materialbrowsermodel.h"
#include "materialbrowserwidget.h"
#include "materialbrowserbundlemodel.h"
@@ -18,6 +20,7 @@
#include <nodemetainfo.h>
#include <nodelistproperty.h>
#include <qmldesignerconstants.h>
+#include <utils/algorithm.h>
#include <QQuickItem>
#include <QRegularExpression>
@@ -81,13 +84,19 @@ WidgetInfo MaterialBrowserView::widgetInfo()
// remove current properties
PropertyNameList propNames;
if (mat.isInBaseState()) {
- propNames = material.propertyNames();
+ const QList<AbstractProperty> baseProps = material.properties();
+ for (const auto &baseProp : baseProps) {
+ if (!baseProp.isDynamic())
+ propNames.append(baseProp.name());
+ }
} else {
QmlPropertyChanges changes = mat.propertyChangeForCurrentState();
if (changes.isValid()) {
const QList<AbstractProperty> changedProps = changes.targetProperties();
- for (const auto &changedProp : changedProps)
- propNames.append(changedProp.name());
+ for (const auto &changedProp : changedProps) {
+ if (!changedProp.isDynamic())
+ propNames.append(changedProp.name());
+ }
}
}
for (const PropertyName &propName : std::as_const(propNames)) {
@@ -98,14 +107,29 @@ WidgetInfo MaterialBrowserView::widgetInfo()
// apply pasted properties
for (const QmlDesigner::MaterialBrowserModel::PropertyCopyData &propData : propDatas) {
- if (propData.name == "objectName")
- continue;
-
if (propData.isValid) {
- if (propData.isBinding)
+ const bool isDynamic = !propData.dynamicTypeName.isEmpty();
+ const bool isBaseState = currentState().isBaseState();
+ const bool hasProperty = mat.hasProperty(propData.name);
+ if (propData.isBinding) {
+ if (isDynamic && (!hasProperty || isBaseState)) {
+ mat.modelNode().bindingProperty(propData.name)
+ .setDynamicTypeNameAndExpression(
+ propData.dynamicTypeName, propData.value.toString());
+ continue;
+ }
mat.setBindingProperty(propData.name, propData.value.toString());
- else
+ } else {
+ const bool isRecording = mat.timelineIsActive()
+ && mat.currentTimeline().isRecording();
+ if (isDynamic && (!hasProperty || (isBaseState && !isRecording))) {
+ mat.modelNode().variantProperty(propData.name)
+ .setDynamicTypeNameAndValue(
+ propData.dynamicTypeName, propData.value);
+ continue;
+ }
mat.setVariantProperty(propData.name, propData.value);
+ }
} else {
mat.removeProperty(propData.name);
}
@@ -122,23 +146,38 @@ WidgetInfo MaterialBrowserView::widgetInfo()
connect(matBrowserBundleModel, &MaterialBrowserBundleModel::applyToSelectedTriggered, this,
[&] (BundleMaterial *bundleMat, bool add) {
- if (!m_selectedModel.isValid())
+ if (m_selectedModels.isEmpty())
return;
- m_bundleMaterialDropTarget = m_selectedModel;
+ m_bundleMaterialTargets = m_selectedModels;
m_bundleMaterialAddToSelected = add;
ModelNode defaultMat = getBundleMaterialDefaultInstance(bundleMat->type());
if (defaultMat.isValid())
applyBundleMaterialToDropTarget(defaultMat);
else
- m_widget->materialBrowserBundleModel()->addMaterial(bundleMat);
+ m_widget->materialBrowserBundleModel()->addToProject(bundleMat);
});
- connect(matBrowserBundleModel, &MaterialBrowserBundleModel::addBundleMaterialToProjectRequested, this,
+ connect(matBrowserBundleModel, &MaterialBrowserBundleModel::bundleMaterialImported, this,
[&] (const QmlDesigner::NodeMetaInfo &metaInfo) {
applyBundleMaterialToDropTarget({}, metaInfo);
+ updateBundleMaterialsImportedState();
+ });
+
+ connect(matBrowserBundleModel, &MaterialBrowserBundleModel::bundleMaterialAboutToUnimport, this,
+ [&] (const QmlDesigner::TypeName &type) {
+ // delete instances of the bundle material that is about to be unimported
+ executeInTransaction("MaterialBrowserView::widgetInfo", [&] {
+ Utils::reverseForeach(m_widget->materialBrowserModel()->materials(), [&](const ModelNode &mat) {
+ if (mat.isValid() && mat.type() == type)
+ QmlObjectNode(mat).destroy();
+ });
+ });
});
+
+ connect(matBrowserBundleModel, &MaterialBrowserBundleModel::bundleMaterialUnimported, this,
+ &MaterialBrowserView::updateBundleMaterialsImportedState);
}
return createWidgetInfo(m_widget.data(),
@@ -178,40 +217,42 @@ void MaterialBrowserView::applyBundleMaterialToDropTarget(const ModelNode &bundl
newMatNode = bundleMat;
}
- if (m_bundleMaterialDropTarget.isValid()
- && m_bundleMaterialDropTarget.metaInfo().isQtQuick3DModel()) {
- QmlObjectNode qmlObjNode(m_bundleMaterialDropTarget);
- if (m_bundleMaterialAddToSelected) {
- // TODO: unify this logic as it exist elsewhere also
- auto expToList = [](const QString &exp) {
- QString copy = exp;
- copy = copy.remove("[").remove("]");
-
- QStringList tmp = copy.split(',', Qt::SkipEmptyParts);
- for (QString &str : tmp)
- str = str.trimmed();
-
- return tmp;
- };
-
- auto listToExp = [](QStringList &stringList) {
- if (stringList.size() > 1)
- return QString("[" + stringList.join(",") + "]");
-
- if (stringList.size() == 1)
- return stringList.first();
-
- return QString();
- };
- QStringList matList = expToList(qmlObjNode.expression("materials"));
- matList.append(newMatNode.id());
- QString updatedExp = listToExp(matList);
- qmlObjNode.setBindingProperty("materials", updatedExp);
- } else {
- qmlObjNode.setBindingProperty("materials", newMatNode.id());
+ // TODO: unify this logic as it exist elsewhere also
+ auto expToList = [](const QString &exp) {
+ QString copy = exp;
+ copy = copy.remove("[").remove("]");
+
+ QStringList tmp = copy.split(',', Qt::SkipEmptyParts);
+ for (QString &str : tmp)
+ str = str.trimmed();
+
+ return tmp;
+ };
+
+ auto listToExp = [](QStringList &stringList) {
+ if (stringList.size() > 1)
+ return QString("[" + stringList.join(",") + "]");
+
+ if (stringList.size() == 1)
+ return stringList.first();
+
+ return QString();
+ };
+
+ for (const ModelNode &target : std::as_const(m_bundleMaterialTargets)) {
+ if (target.isValid() && target.metaInfo().isQtQuick3DModel()) {
+ QmlObjectNode qmlObjNode(target);
+ if (m_bundleMaterialAddToSelected) {
+ QStringList matList = expToList(qmlObjNode.expression("materials"));
+ matList.append(newMatNode.id());
+ QString updatedExp = listToExp(matList);
+ qmlObjNode.setBindingProperty("materials", updatedExp);
+ } else {
+ qmlObjNode.setBindingProperty("materials", newMatNode.id());
+ }
}
- m_bundleMaterialDropTarget = {};
+ m_bundleMaterialTargets = {};
m_bundleMaterialAddToSelected = false;
}
});
@@ -226,6 +267,7 @@ void MaterialBrowserView::modelAttached(Model *model)
rootModelNode().metaInfo().isQtQuick3DMaterial());
m_hasQuick3DImport = model->hasImport("QtQuick3D");
+ updateBundleMaterialsImportedState();
// Project load is already very busy and may even trigger puppet reset, so let's wait a moment
// before refreshing the model
@@ -274,24 +316,20 @@ void MaterialBrowserView::modelAboutToBeDetached(Model *model)
void MaterialBrowserView::selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
[[maybe_unused]] const QList<ModelNode> &lastSelectedNodeList)
{
- m_selectedModel = {};
-
- for (const ModelNode &node : selectedNodeList) {
- if (node.metaInfo().isQtQuick3DModel()) {
- m_selectedModel = node;
- break;
- }
- }
+ m_selectedModels = Utils::filtered(selectedNodeList, [](const ModelNode &node) {
+ return node.metaInfo().isQtQuick3DModel();
+ });
- m_widget->materialBrowserModel()->setHasModelSelection(m_selectedModel.isValid());
+ m_widget->materialBrowserModel()->setHasModelSelection(!m_selectedModels.isEmpty());
+ // the logic below selects the material of the first selected model if auto selection is on
if (!m_autoSelectModelMaterial)
return;
- if (selectedNodeList.size() > 1 || !m_selectedModel.isValid())
+ if (selectedNodeList.size() > 1 || m_selectedModels.isEmpty())
return;
- QmlObjectNode qmlObjNode(m_selectedModel);
+ QmlObjectNode qmlObjNode(m_selectedModels.at(0));
QString matExp = qmlObjNode.expression("materials");
if (matExp.isEmpty())
return;
@@ -385,6 +423,25 @@ void QmlDesigner::MaterialBrowserView::loadPropertyGroups()
m_propertyGroupsLoaded = m_widget->materialBrowserModel()->loadPropertyGroups(matPropsPath);
}
+void MaterialBrowserView::updateBundleMaterialsImportedState()
+{
+ using namespace Utils;
+
+ if (!m_widget->materialBrowserBundleModel()->bundleImporter())
+ return;
+
+ QStringList importedBundleMats;
+
+ FilePath materialBundlePath = m_widget->materialBrowserBundleModel()->bundleImporter()->resolveBundleImportPath();
+
+ if (materialBundlePath.exists()) {
+ importedBundleMats = transform(materialBundlePath.dirEntries({{"*.qml"}, QDir::Files}),
+ [](const FilePath &f) { return f.fileName().chopped(4); });
+ }
+
+ m_widget->materialBrowserBundleModel()->updateImportedState(importedBundleMats);
+}
+
ModelNode MaterialBrowserView::getBundleMaterialDefaultInstance(const TypeName &type)
{
const QList<ModelNode> materials = m_widget->materialBrowserModel()->materials();
@@ -442,13 +499,13 @@ void MaterialBrowserView::customNotification(const AbstractView *view,
} else if (identifier == "delete_selected_material") {
m_widget->materialBrowserModel()->deleteSelectedMaterial();
} else if (identifier == "drop_bundle_material") {
- m_bundleMaterialDropTarget = nodeList.first();
+ m_bundleMaterialTargets = nodeList;
ModelNode defaultMat = getBundleMaterialDefaultInstance(m_draggedBundleMaterial->type());
if (defaultMat.isValid())
applyBundleMaterialToDropTarget(defaultMat);
else
- m_widget->materialBrowserBundleModel()->addMaterial(m_draggedBundleMaterial);
+ m_widget->materialBrowserBundleModel()->addToProject(m_draggedBundleMaterial);
m_draggedBundleMaterial = nullptr;
}
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h
index 31b0310f4c..1d2322463b 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h
@@ -46,13 +46,15 @@ private:
void refreshModel(bool updateImages);
bool isMaterial(const ModelNode &node) const;
void loadPropertyGroups();
+ void updateBundleMaterialsImportedState();
void applyBundleMaterialToDropTarget(const ModelNode &bundleMat, const NodeMetaInfo &metaInfo = {});
ModelNode getBundleMaterialDefaultInstance(const TypeName &type);
QPointer<MaterialBrowserWidget> m_widget;
- ModelNode m_bundleMaterialDropTarget;
- ModelNode m_selectedModel; // first selected 3D model node
+ QList<ModelNode> m_bundleMaterialTargets;
+ QList<ModelNode> m_selectedModels; // selected 3D model nodes
BundleMaterial *m_draggedBundleMaterial = nullptr;
+
bool m_bundleMaterialAddToSelected = false;
bool m_hasQuick3DImport = false;
bool m_autoSelectModelMaterial = false; // TODO: wire this to some action
diff --git a/src/plugins/qmldesigner/designercore/include/modelnode.h b/src/plugins/qmldesigner/designercore/include/modelnode.h
index 2ab045716a..80a26a7b98 100644
--- a/src/plugins/qmldesigner/designercore/include/modelnode.h
+++ b/src/plugins/qmldesigner/designercore/include/modelnode.h
@@ -129,6 +129,7 @@ public:
QList<NodeListProperty> nodeListProperties() const;
QList<BindingProperty> bindingProperties() const;
QList<SignalHandlerProperty> signalProperties() const;
+ QList<AbstractProperty> dynamicProperties() const;
PropertyNameList propertyNames() const;
bool hasProperties() const;
diff --git a/src/plugins/qmldesigner/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/designercore/model/modelnode.cpp
index efdbdaad19..09a5d653b3 100644
--- a/src/plugins/qmldesigner/designercore/model/modelnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/modelnode.cpp
@@ -623,6 +623,18 @@ QList<SignalHandlerProperty> ModelNode::signalProperties() const
return propertyList;
}
+QList<AbstractProperty> ModelNode::dynamicProperties() const
+{
+ QList<AbstractProperty> propertyList;
+
+ const QList<AbstractProperty> abstractProperties = properties();
+ for (const AbstractProperty &abstractProperty : abstractProperties) {
+ if (abstractProperty.isDynamic())
+ propertyList.append(abstractProperty);
+ }
+ return propertyList;
+}
+
/*!
\brief removes a property from this node
\param name name of the property
diff --git a/src/plugins/qtsupport/qtoptionspage.cpp b/src/plugins/qtsupport/qtoptionspage.cpp
index 16d2a2c13a..f1cbc250b3 100644
--- a/src/plugins/qtsupport/qtoptionspage.cpp
+++ b/src/plugins/qtsupport/qtoptionspage.cpp
@@ -912,9 +912,9 @@ void QtOptionsPageWidget::apply()
&QtOptionsPageWidget::updateQtVersions);
}
-// TODO whenever we move the output of sdktool to a different location in the installer,
-// this needs to be adapted accordingly
const QStringList kSubdirsToCheck = {"",
+ "Tools/sdktool", // macOS
+ "Tools/sdktool/share/qtcreator", // Windows/Linux
"Qt Creator.app/Contents/Resources",
"Contents/Resources",
"Tools/QtCreator/share/qtcreator",
diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp
index 688d231ad7..692c4bec1a 100644
--- a/src/plugins/texteditor/texteditor.cpp
+++ b/src/plugins/texteditor/texteditor.cpp
@@ -5706,8 +5706,8 @@ void TextEditorWidget::mouseDoubleClickEvent(QMouseEvent *e)
}
}
- QTextCursor oldCursor = multiTextCursor().mainCursor();
- const int oldPosition = oldCursor.position();
+ QTextCursor eventCursor = cursorForPosition(QPoint(e->pos().x(), e->pos().y()));
+ const int eventDocumentPosition = eventCursor.position();
QPlainTextEdit::mouseDoubleClickEvent(e);
@@ -5715,19 +5715,19 @@ void TextEditorWidget::mouseDoubleClickEvent(QMouseEvent *e)
// event is triggered on a position that is inbetween two whitespaces this event selects the
// previous word or nothing if the whitespaces are at the block start. Replace this behavior
// with selecting the whitespaces starting from the previous word end to the next word.
- const QChar character = characterAt(oldPosition);
- const QChar prevCharacter = characterAt(oldPosition - 1);
+ const QChar character = characterAt(eventDocumentPosition);
+ const QChar prevCharacter = characterAt(eventDocumentPosition - 1);
if (character.isSpace() && prevCharacter.isSpace()) {
if (prevCharacter != QChar::ParagraphSeparator) {
- oldCursor.movePosition(QTextCursor::PreviousWord);
- oldCursor.movePosition(QTextCursor::EndOfWord);
+ eventCursor.movePosition(QTextCursor::PreviousWord);
+ eventCursor.movePosition(QTextCursor::EndOfWord);
} else if (character == QChar::ParagraphSeparator) {
return; // no special handling for empty lines
}
- oldCursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
+ eventCursor.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
MultiTextCursor cursor = multiTextCursor();
- cursor.replaceMainCursor(oldCursor);
+ cursor.replaceMainCursor(eventCursor);
setMultiTextCursor(cursor);
}
}
diff --git a/tests/system/suite_tools/tst_git_clone/test.py b/tests/system/suite_tools/tst_git_clone/test.py
index af2248b062..3a8678e52d 100644
--- a/tests/system/suite_tools/tst_git_clone/test.py
+++ b/tests/system/suite_tools/tst_git_clone/test.py
@@ -47,8 +47,8 @@ def verifyVersionControlView(targetDir, canceled):
"Searching for target directory in clone log")
test.verify(" ".join(["clone", "--progress", cloneUrl, cloneDir]) in vcsLog,
"Searching for git parameters in clone log")
- test.verify(canceled == (" terminated abnormally" in vcsLog),
- "Searching for result in clone log")
+ test.compare(canceled, " terminated abnormally" in vcsLog,
+ "Searching for result in clone log")
clickButton(waitForObject(":*Qt Creator.Clear_QToolButton"))
def verifyFiles(targetDir):
@@ -117,5 +117,5 @@ def main():
test.fail("The checked out project was not being opened.",
str(waitForObject(":Cannot Open Project_QTextEdit").plainText))
clickButton(waitForObject(":Cannot Open Project.OK_QPushButton"))
- verifyVersionControlView(targetDir, button != ":Git Repository Clone.Finish_QPushButton")
+ verifyVersionControlView(targetDir, button == "Cancel immediately")
invokeMenuItem("File", "Exit")