summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEike Ziller <eike.ziller@qt.io>2022-03-11 09:50:48 +0100
committerEike Ziller <eike.ziller@qt.io>2022-03-11 09:50:48 +0100
commitcd8c4ced811a8d022d3e244a482a4a3bbc513d83 (patch)
treee97b1cbe66c015b3f7b75ef265b25bf38ead9562
parenta863958aa4b27ab477a1926635accd681938adb7 (diff)
parent2829412e154935aea563862254ea5aa64941210f (diff)
downloadqt-creator-cd8c4ced811a8d022d3e244a482a4a3bbc513d83.tar.gz
Merge remote-tracking branch 'origin/7.0'
Conflicts: cmake/QtCreatorIDEBranding.cmake qbs/modules/qtc/qtc.qbs qtcreator_ide_branding.pri Change-Id: Ic02df53b880d0861d9d9ea0df3e0d381ae99f350
-rw-r--r--.github/workflows/build_cmake.yml83
-rw-r--r--dist/installer/mac/disclaim.entitlements8
-rw-r--r--doc/qtcreator/images/creator-qbs-project.pngbin13175 -> 0 bytes
-rw-r--r--doc/qtcreator/images/creator-uwp-kits.pngbin139327 -> 0 bytes
-rw-r--r--doc/qtcreator/images/qml-link-debugging-library.pngbin11659 -> 0 bytes
-rw-r--r--doc/qtcreator/images/qmldesigner-new-project.pngbin17167 -> 0 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-add-resource-wizard.pngbin18218 -> 13860 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-android-select-devices.pngbin39124 -> 0 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-autotools-buildrun.pngbin14287 -> 20223 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-autotools-buildsettings.pngbin11735 -> 21225 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-cmake-run-cmake.pngbin28948 -> 0 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-cmake-run-settings.pngbin10735 -> 0 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-deployment-steps-b2qt-58.pngbin56618 -> 0 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-edit-mode.pngbin72580 -> 0 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-git-commit-actions.pngbin13722 -> 0 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-language-client-inspector-memory-usage.pngbin10726 -> 0 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-locator-url-template.pngbin7598 -> 0 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-meson-build-settings.pngbin18693 -> 14743 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-meson-build-steps.pngbin9760 -> 4439 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-meson-clean-steps.pngbin9851 -> 4557 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-new-opengl-file.pngbin17947 -> 14351 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-new-project.pngbin0 -> 12918 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-new-qt-gui-application.pngbin18659 -> 13749 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-new-qt-quick-project-wizard.pngbin17426 -> 0 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-new-qt-quick-project.pngbin0 -> 12659 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-new-subproject.pngbin17167 -> 0 bytes
-rw-r--r--doc/qtcreator/images/qtcreator-pprunsettings.pngbin16858 -> 13198 bytes
-rw-r--r--doc/qtcreator/images/qtquick-debugging-settings.pngbin3740 -> 2517 bytes
-rw-r--r--doc/qtcreator/src/conan/creator-projects-conan.qdoc4
-rw-r--r--doc/qtcreator/src/editors/creator-code-syntax.qdoc2
-rw-r--r--doc/qtcreator/src/editors/creator-editors-options.qdoc18
-rw-r--r--doc/qtcreator/src/meson/creator-projects-meson-building.qdoc30
-rw-r--r--doc/qtcreator/src/meson/creator-projects-meson.qdoc3
-rw-r--r--doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc4
-rw-r--r--doc/qtcreator/src/projects/creator-only/creator-projects-settings-run-debug.qdocinc14
-rw-r--r--doc/qtcreator/src/qtquick/creator-only/qtquick-creating.qdoc2
-rw-r--r--doc/qtcreator/src/vcs/creator-vcs-git.qdoc2
-rw-r--r--doc/qtdesignstudio/images/icons/align-camera-on.pngbin0 -> 309 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/align-view-on.pngbin0 -> 321 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/particle-animation-off.pngbin0 -> 549 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/particle-animation-on.pngbin0 -> 316 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/particle-pause.pngbin0 -> 120 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/particle-play.pngbin0 -> 159 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/particle-restart.pngbin0 -> 302 bytes
-rw-r--r--doc/qtdesignstudio/images/icons/particles-seek.pngbin0 -> 311 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor-axis-helper.pngbin12011 -> 58091 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor-move.pngbin12265 -> 38487 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor-rotate.pngbin13843 -> 41596 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor-scale.pngbin12216 -> 38694 bytes
-rw-r--r--doc/qtdesignstudio/images/studio-3d-editor.pngbin12421 -> 41273 bytes
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc133
-rw-r--r--scripts/common.py29
-rw-r--r--share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h1
-rw-r--r--share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc3
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml6
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml126
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml3
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ParticleEmitterGizmo.qml127
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ParticleSystemGizmo.qml4
-rw-r--r--share/qtcreator/qml/qmlpuppet/mockfiles/qt6/RotateRing.qml1
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp62
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h9
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp112
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h2
-rw-r--r--share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.h2
-rw-r--r--share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml201
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/NewProjectDialog.qml121
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-basic.pngbin3891 -> 3642 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-basic@2x.pngbin9643 -> 5661 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-default.pngbin1617 -> 2222 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-default@2x.pngbin4165 -> 4150 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion.pngbin2436 -> 3371 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion@2x.pngbin8903 -> 5328 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine.pngbin3598 -> 3527 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine@2x.pngbin8809 -> 5090 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-macOs@2x.pngbin4165 -> 0 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-macos.pngbin1617 -> 2222 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-macos@2x.pngbin0 -> 4150 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark.pngbin4033 -> 3406 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark@2x.pngbin10919 -> 5410 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light.pngbin3780 -> 3588 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light@2x.pngbin9504 -> 5467 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark.pngbin3887 -> 3338 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark@2x.pngbin9579 -> 5417 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light.pngbin2486 -> 3461 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light@2x.pngbin9157 -> 5297 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system.pngbin3395 -> 3354 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system@2x.pngbin8527 -> 5172 bytes
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml183
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/DialogValues.qml52
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/NewProjectView.qml303
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/PopupDialog.qml66
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/PopupDialogButton.qml107
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/PopupDialogButtonBox.qml46
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml192
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/qmldir7
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExpressionTextField.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml19
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/VerticalScrollBar.qml31
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml2
-rw-r--r--share/qtcreator/themes/design-light.creatortheme2
-rw-r--r--share/qtcreator/themes/design.creatortheme4
-rw-r--r--src/libs/languageserverprotocol/lsptypes.h6
-rw-r--r--src/libs/utils/elfreader.h2
-rw-r--r--src/plugins/android/androidmanager.cpp2
-rw-r--r--src/plugins/android/androidmanifesteditorwidget.cpp9
-rw-r--r--src/plugins/android/androidmanifesteditorwidget.h2
-rw-r--r--src/plugins/android/avddialog.cpp8
-rw-r--r--src/plugins/android/avdmanageroutputparser.cpp2
-rw-r--r--src/plugins/clangcodemodel/clangdclient.cpp30
-rw-r--r--src/plugins/clangcodemodel/test/clangdtests.cpp13
-rw-r--r--src/plugins/clangcodemodel/test/data/completion/completion.pro2
-rw-r--r--src/plugins/clangcodemodel/test/data/find-usages/find-usages.pro1
-rw-r--r--src/plugins/clangcodemodel/test/data/follow-symbol/follow-symbol.pro1
-rw-r--r--src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp27
-rw-r--r--src/plugins/clangcodemodel/test/data/highlighting/highlighting.pro1
-rw-r--r--src/plugins/clangcodemodel/test/data/local-references/local-references.pro3
-rw-r--r--src/plugins/clangformat/clangformatutils.cpp17
-rw-r--r--src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp7
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketool.cpp4
-rw-r--r--src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp7
-rw-r--r--src/plugins/coreplugin/foldernavigationwidget.cpp7
-rw-r--r--src/plugins/debugger/debuggersourcepathmappingwidget.cpp3
-rw-r--r--src/plugins/help/helpplugin.cpp2
-rw-r--r--src/plugins/imageviewer/imageviewerfile.cpp13
-rw-r--r--src/plugins/languageclient/client.cpp5
-rw-r--r--src/plugins/languageclient/client.h2
-rw-r--r--src/plugins/languageclient/diagnosticmanager.cpp8
-rw-r--r--src/plugins/languageclient/diagnosticmanager.h5
-rw-r--r--src/plugins/marketplace/qtmarketplacewelcomepage.cpp5
-rw-r--r--src/plugins/mcusupport/mcupackage.cpp4
-rw-r--r--src/plugins/mcusupport/mcusupportversiondetection.cpp2
-rw-r--r--src/plugins/projectexplorer/buildconfiguration.cpp7
-rw-r--r--src/plugins/projectexplorer/customparser.cpp51
-rw-r--r--src/plugins/projectexplorer/kitmanager.cpp5
-rw-r--r--src/plugins/projectexplorer/projectwelcomepage.cpp62
-rw-r--r--src/plugins/projectexplorer/projectwelcomepage.h1
-rw-r--r--src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp9
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp70
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h4
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp19
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/crumblebar.cpp27
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h1
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dview.cpp39
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dview.h1
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp5
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecacheconnectionmanager.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp7
-rw-r--r--src/plugins/qmldesigner/designercore/model/modelnode.cpp4
-rw-r--r--src/plugins/qmldesigner/qmldesignerconstants.h1
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.cpp30
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.h1
-rw-r--r--src/plugins/qtsupport/gettingstartedwelcomepage.cpp5
-rw-r--r--src/plugins/studiowelcome/CMakeLists.txt1
-rw-r--r--src/plugins/studiowelcome/presetmodel.cpp152
-rw-r--r--src/plugins/studiowelcome/presetmodel.h116
-rw-r--r--src/plugins/studiowelcome/qdsnewdialog.cpp191
-rw-r--r--src/plugins/studiowelcome/qdsnewdialog.h29
-rw-r--r--src/plugins/studiowelcome/recentpresets.cpp86
-rw-r--r--src/plugins/studiowelcome/recentpresets.h58
-rw-r--r--src/plugins/studiowelcome/studiowelcome.qbs4
-rw-r--r--src/plugins/studiowelcome/studiowelcomeplugin.cpp2
-rw-r--r--src/plugins/studiowelcome/userpresets.cpp125
-rw-r--r--src/plugins/studiowelcome/userpresets.h91
-rw-r--r--src/plugins/studiowelcome/wizardfactories.cpp23
-rw-r--r--src/plugins/studiowelcome/wizardfactories.h2
-rw-r--r--src/plugins/studiowelcome/wizardhandler.cpp82
-rw-r--r--src/plugins/studiowelcome/wizardhandler.h14
m---------src/shared/qbs0
-rw-r--r--src/tools/disclaim/disclaim.qbs12
-rw-r--r--src/tools/sdktool/adddeviceoperation.cpp46
-rw-r--r--src/tools/sdktool/adddeviceoperation.h3
-rw-r--r--src/tools/tools.qbs1
-rw-r--r--tests/auto/qml/qmldesigner/wizard/CMakeLists.txt2
-rw-r--r--tests/auto/qml/qmldesigner/wizard/presetmodel-test.cpp260
-rw-r--r--tests/auto/qml/qmldesigner/wizard/recentpresets-test.cpp150
-rw-r--r--tests/auto/qml/qmldesigner/wizard/userpresets-test.cpp308
-rw-r--r--tests/auto/qml/qmldesigner/wizard/wizardfactories-test.cpp10
-rw-r--r--tests/auto/ssh/tst_ssh.cpp2
-rw-r--r--tests/system/shared/build_utils.py6
-rw-r--r--tests/system/suite_HELP/tst_HELP04/test.py14
-rw-r--r--tests/system/suite_SCOM/tst_SCOM04/test.py5
184 files changed, 3568 insertions, 910 deletions
diff --git a/.github/workflows/build_cmake.yml b/.github/workflows/build_cmake.yml
index 25e087fb25..f388524f11 100644
--- a/.github/workflows/build_cmake.yml
+++ b/.github/workflows/build_cmake.yml
@@ -8,12 +8,12 @@ on:
env:
QT_VERSION: 6.2.3
- CLANG_VERSION: 130
+ CLANG_VERSION: 140
ELFUTILS_VERSION: 0.175
CMAKE_VERSION: 3.21.1
NINJA_VERSION: 1.10.2
BUILD_TYPE: Release
- CCACHE_VERSION: 4.5
+ CCACHE_VERSION: 4.6
QT_MIRRORS: download.qt.io;mirrors.ocf.berkeley.edu/qt;ftp.fau.de/qtproject;mirror.bit.edu.cn/qtproject
jobs:
@@ -31,12 +31,14 @@ jobs:
environment_script: "C:/Program Files (x86)/Microsoft Visual Studio/2019/Enterprise/VC/Auxiliary/Build/vcvars64.bat",
is_msvc: true
}
-# - {
-# name: "Windows Latest MinGW", artifact: "Windows-MinGW",
-# os: windows-latest,
-# cc: "gcc", cxx: "g++",
-# is_msvc: false
-# }
+ - {
+ name: "Windows Latest MinGW", artifact: "Windows-MinGW",
+ os: windows-latest,
+ toolchain: "https://github.com/cristianadam/mingw-builds/releases/download/v11.2.0-rev1/x86_64-11.2.0-release-posix-seh-rt_v9-rev1.7z",
+ toolchain_path: "mingw64/bin",
+ cc: "gcc", cxx: "g++",
+ is_msvc: false
+ }
- {
name: "Ubuntu Latest GCC", artifact: "Linux",
os: ubuntu-latest,
@@ -111,6 +113,33 @@ jobs:
)
endif()
+ - name: Install system libs
+ shell: cmake -P {0}
+ run: |
+ if ("${{ runner.os }}" STREQUAL "Linux")
+ execute_process(
+ COMMAND sudo apt update
+ )
+ execute_process(
+ COMMAND sudo apt install libgl1-mesa-dev libvulkan-dev libxcb-xinput-dev libxcb-xinerama0-dev libxkbcommon-dev libxkbcommon-x11-dev
+ RESULT_VARIABLE result
+ )
+ if (NOT result EQUAL 0)
+ message(FATAL_ERROR "Failed to install dependencies")
+ endif()
+ endif()
+
+ if (NOT "x${{ matrix.config.toolchain }}" STREQUAL "x")
+ foreach(retry RANGE 10)
+ file(DOWNLOAD "${{ matrix.config.toolchain }}" ./toolchain.7z SHOW_PROGRESS)
+ file(SIZE ./toolchain.7z fileSize)
+ if (fileSize GREATER 0)
+ break()
+ endif()
+ endforeach()
+ execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ./toolchain.7z)
+ endif()
+
- name: Download Qt
id: qt
shell: cmake -P {0}
@@ -121,8 +150,8 @@ jobs:
if ("${{ runner.os }}" STREQUAL "Windows")
set(url_os "windows_x86")
if ("x${{ matrix.config.environment_script }}" STREQUAL "x")
- set(qt_package_arch_suffix "win64_mingw81")
- set(qt_dir_prefix "${qt_version}/mingw81_64")
+ set(qt_package_arch_suffix "win64_mingw")
+ set(qt_dir_prefix "${qt_version}/mingw_64")
set(qt_package_suffix "-Windows-Windows_10_21H2-Mingw-Windows-Windows_10_21H2-X86_64")
elseif ("${{ matrix.config.environment_script }}" MATCHES "vcvars64.bat")
set(qt_package_arch_suffix "win64_msvc2019_64")
@@ -218,7 +247,7 @@ jobs:
if ("x${{ matrix.config.environment_script }}" STREQUAL "x")
# deploy MinGW
foreach(file libwinpthread-1.dll libstdc++-6.dll libgcc_s_seh-1.dll)
- file(INSTALL "C:/ProgramData/chocolatey/lib/mingw/tools/install/mingw64/bin/${file}"
+ file(INSTALL "$ENV{GITHUB_WORKSPACE}/${{ matrix.config.toolchain_path }}/${file}"
DESTINATION "qt6/${qt_dir_prefix}/bin"
USE_SOURCE_PERMISSIONS)
endforeach()
@@ -434,22 +463,6 @@ jobs:
endforeach()
endforeach()
- - name: Install system libs
- shell: cmake -P {0}
- run: |
- if ("${{ runner.os }}" STREQUAL "Linux")
- execute_process(
- COMMAND sudo apt update
- )
- execute_process(
- COMMAND sudo apt install libgl1-mesa-dev libvulkan-dev libxcb-xinput-dev libxcb-xinerama0-dev libxkbcommon-dev libxkbcommon-x11-dev
- RESULT_VARIABLE result
- )
- if (NOT result EQUAL 0)
- message(FATAL_ERROR "Failed to install dependencies")
- endif()
- endif()
-
- name: Build
shell: cmake -P {0}
run: |
@@ -516,6 +529,14 @@ jobs:
unset(NO_DMG)
endif()
+ if (NOT "x${{ matrix.config.toolchain_path }}" STREQUAL "x")
+ set(path_separator ":")
+ if ("${{ runner.os }}" STREQUAL "Windows")
+ set(path_separator ";")
+ endif()
+ set(ENV{PATH} "$ENV{GITHUB_WORKSPACE}/${{ matrix.config.toolchain_path }}${path_separator}$ENV{PATH}")
+ endif()
+
execute_process(
COMMAND python
-u
@@ -673,10 +694,10 @@ jobs:
name: "Windows Latest MSVC", artifact: "Windows-MSVC",
os: ubuntu-latest
}
-# - {
-# name: "Windows Latest MinGW", artifact: "Windows-MinGW",
-# os: ubuntu-latest
-# }
+ - {
+ name: "Windows Latest MinGW", artifact: "Windows-MinGW",
+ os: ubuntu-latest
+ }
- {
name: "Ubuntu Latest GCC", artifact: "Linux",
os: ubuntu-latest
diff --git a/dist/installer/mac/disclaim.entitlements b/dist/installer/mac/disclaim.entitlements
new file mode 100644
index 0000000000..7760cac65c
--- /dev/null
+++ b/dist/installer/mac/disclaim.entitlements
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>com.apple.security.cs.allow-dyld-environment-variables</key>
+ <true/>
+</dict>
+</plist>
diff --git a/doc/qtcreator/images/creator-qbs-project.png b/doc/qtcreator/images/creator-qbs-project.png
deleted file mode 100644
index fe8d7b5ecd..0000000000
--- a/doc/qtcreator/images/creator-qbs-project.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/creator-uwp-kits.png b/doc/qtcreator/images/creator-uwp-kits.png
deleted file mode 100644
index 2c8c29560d..0000000000
--- a/doc/qtcreator/images/creator-uwp-kits.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/qml-link-debugging-library.png b/doc/qtcreator/images/qml-link-debugging-library.png
deleted file mode 100644
index 6a600c000d..0000000000
--- a/doc/qtcreator/images/qml-link-debugging-library.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/qmldesigner-new-project.png b/doc/qtcreator/images/qmldesigner-new-project.png
deleted file mode 100644
index 7bab02c38f..0000000000
--- a/doc/qtcreator/images/qmldesigner-new-project.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-add-resource-wizard.png b/doc/qtcreator/images/qtcreator-add-resource-wizard.png
index 3b1b8b045e..e76223f5b2 100644
--- a/doc/qtcreator/images/qtcreator-add-resource-wizard.png
+++ b/doc/qtcreator/images/qtcreator-add-resource-wizard.png
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-android-select-devices.png b/doc/qtcreator/images/qtcreator-android-select-devices.png
deleted file mode 100644
index 7c74766680..0000000000
--- a/doc/qtcreator/images/qtcreator-android-select-devices.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-autotools-buildrun.png b/doc/qtcreator/images/qtcreator-autotools-buildrun.png
index 5795b536b5..4901898234 100644
--- a/doc/qtcreator/images/qtcreator-autotools-buildrun.png
+++ b/doc/qtcreator/images/qtcreator-autotools-buildrun.png
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-autotools-buildsettings.png b/doc/qtcreator/images/qtcreator-autotools-buildsettings.png
index 879c0e8f5a..bd302a0b92 100644
--- a/doc/qtcreator/images/qtcreator-autotools-buildsettings.png
+++ b/doc/qtcreator/images/qtcreator-autotools-buildsettings.png
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-cmake-run-cmake.png b/doc/qtcreator/images/qtcreator-cmake-run-cmake.png
deleted file mode 100644
index c778ea4511..0000000000
--- a/doc/qtcreator/images/qtcreator-cmake-run-cmake.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-cmake-run-settings.png b/doc/qtcreator/images/qtcreator-cmake-run-settings.png
deleted file mode 100644
index 229bdae6dd..0000000000
--- a/doc/qtcreator/images/qtcreator-cmake-run-settings.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-deployment-steps-b2qt-58.png b/doc/qtcreator/images/qtcreator-deployment-steps-b2qt-58.png
deleted file mode 100644
index 8acc7c55c8..0000000000
--- a/doc/qtcreator/images/qtcreator-deployment-steps-b2qt-58.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-edit-mode.png b/doc/qtcreator/images/qtcreator-edit-mode.png
deleted file mode 100644
index a8781f1d5e..0000000000
--- a/doc/qtcreator/images/qtcreator-edit-mode.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-git-commit-actions.png b/doc/qtcreator/images/qtcreator-git-commit-actions.png
deleted file mode 100644
index 37295e48fc..0000000000
--- a/doc/qtcreator/images/qtcreator-git-commit-actions.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-language-client-inspector-memory-usage.png b/doc/qtcreator/images/qtcreator-language-client-inspector-memory-usage.png
deleted file mode 100644
index 92ab52d28b..0000000000
--- a/doc/qtcreator/images/qtcreator-language-client-inspector-memory-usage.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-locator-url-template.png b/doc/qtcreator/images/qtcreator-locator-url-template.png
deleted file mode 100644
index e0932c7be6..0000000000
--- a/doc/qtcreator/images/qtcreator-locator-url-template.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-meson-build-settings.png b/doc/qtcreator/images/qtcreator-meson-build-settings.png
index 6686555054..eee5c3d564 100644
--- a/doc/qtcreator/images/qtcreator-meson-build-settings.png
+++ b/doc/qtcreator/images/qtcreator-meson-build-settings.png
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-meson-build-steps.png b/doc/qtcreator/images/qtcreator-meson-build-steps.png
index 410d6ae059..73e7300a42 100644
--- a/doc/qtcreator/images/qtcreator-meson-build-steps.png
+++ b/doc/qtcreator/images/qtcreator-meson-build-steps.png
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-meson-clean-steps.png b/doc/qtcreator/images/qtcreator-meson-clean-steps.png
index c84aa1d217..f3e3dd2f66 100644
--- a/doc/qtcreator/images/qtcreator-meson-clean-steps.png
+++ b/doc/qtcreator/images/qtcreator-meson-clean-steps.png
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-new-opengl-file.png b/doc/qtcreator/images/qtcreator-new-opengl-file.png
index 529474b1e0..cad63fea84 100644
--- a/doc/qtcreator/images/qtcreator-new-opengl-file.png
+++ b/doc/qtcreator/images/qtcreator-new-opengl-file.png
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-new-project.png b/doc/qtcreator/images/qtcreator-new-project.png
new file mode 100644
index 0000000000..c1d2a37113
--- /dev/null
+++ b/doc/qtcreator/images/qtcreator-new-project.png
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-new-qt-gui-application.png b/doc/qtcreator/images/qtcreator-new-qt-gui-application.png
index 19d8e0c1eb..d2b3496c30 100644
--- a/doc/qtcreator/images/qtcreator-new-qt-gui-application.png
+++ b/doc/qtcreator/images/qtcreator-new-qt-gui-application.png
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-new-qt-quick-project-wizard.png b/doc/qtcreator/images/qtcreator-new-qt-quick-project-wizard.png
deleted file mode 100644
index d9d7509a8a..0000000000
--- a/doc/qtcreator/images/qtcreator-new-qt-quick-project-wizard.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-new-qt-quick-project.png b/doc/qtcreator/images/qtcreator-new-qt-quick-project.png
new file mode 100644
index 0000000000..ec773f7f5f
--- /dev/null
+++ b/doc/qtcreator/images/qtcreator-new-qt-quick-project.png
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-new-subproject.png b/doc/qtcreator/images/qtcreator-new-subproject.png
deleted file mode 100644
index 7bab02c38f..0000000000
--- a/doc/qtcreator/images/qtcreator-new-subproject.png
+++ /dev/null
Binary files differ
diff --git a/doc/qtcreator/images/qtcreator-pprunsettings.png b/doc/qtcreator/images/qtcreator-pprunsettings.png
index 4b53a44d9a..dab1d9e1cf 100644
--- a/doc/qtcreator/images/qtcreator-pprunsettings.png
+++ b/doc/qtcreator/images/qtcreator-pprunsettings.png
Binary files differ
diff --git a/doc/qtcreator/images/qtquick-debugging-settings.png b/doc/qtcreator/images/qtquick-debugging-settings.png
index 0b3d896ca1..c6b1f7bca2 100644
--- a/doc/qtcreator/images/qtquick-debugging-settings.png
+++ b/doc/qtcreator/images/qtquick-debugging-settings.png
Binary files differ
diff --git a/doc/qtcreator/src/conan/creator-projects-conan.qdoc b/doc/qtcreator/src/conan/creator-projects-conan.qdoc
index fc20640b86..f76eaac6a1 100644
--- a/doc/qtcreator/src/conan/creator-projects-conan.qdoc
+++ b/doc/qtcreator/src/conan/creator-projects-conan.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
@@ -52,7 +52,7 @@
To use Conan, install it by using the Qt installer or the tools provided by
your operating system. For example, on Windows, you can use the
- \c {choco install conan} or \{pip install conan} command.
+ \c {choco install conan} or \c {pip install conan} command.
To enable the experimental Conan plugin, select \uicontrol Help >
\uicontrol {About Plugins} > \uicontrol Utilities > \uicontrol Conan.
diff --git a/doc/qtcreator/src/editors/creator-code-syntax.qdoc b/doc/qtcreator/src/editors/creator-code-syntax.qdoc
index c320b19271..339b0f6f1b 100644
--- a/doc/qtcreator/src/editors/creator-code-syntax.qdoc
+++ b/doc/qtcreator/src/editors/creator-code-syntax.qdoc
@@ -97,6 +97,8 @@
between lines can be useful if there is usually not enough space to
display annotations next to the text.
+ \image qtcreator-options-text-editor-display.png "Text Editor Display options"
+
If you hide the annotations by deselecting the check box, you can move the
mouse pointer over an icon to view them.
diff --git a/doc/qtcreator/src/editors/creator-editors-options.qdoc b/doc/qtcreator/src/editors/creator-editors-options.qdoc
index d84ecc7f4d..a2e9d740b4 100644
--- a/doc/qtcreator/src/editors/creator-editors-options.qdoc
+++ b/doc/qtcreator/src/editors/creator-editors-options.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
@@ -40,12 +40,18 @@
\title Configuring the Editor
- \QC allows you to configure the text editor to suit your specific
- needs. To configure the editor, select \uicontrol Tools >
- \uicontrol Options > \uicontrol{Text Editor}.
+ You can configure the text editor to suit your specific needs by selecting
+ \uicontrol Tools > \uicontrol Options > \uicontrol{Text Editor}.
+
+ \image qtcreator-font-colors.png "Text Editor options"
+
+ The settings you specify apply globally to all projects.
+
+ To specify editor behavior for an open project, select \uicontrol Projects >
+ \uicontrol Editor.
+
+ \image qtcreator-editor-settings.png "Editor settings"
- These settings apply to all projects. To specify editor behavior for an open
- project, select \uicontrol Projects > \uicontrol Editor.
\if defined(qtcreator)
For more information, see \l{Specifying Editor Settings}.
\endif
diff --git a/doc/qtcreator/src/meson/creator-projects-meson-building.qdoc b/doc/qtcreator/src/meson/creator-projects-meson-building.qdoc
index 288630105f..b0f5ef2c7d 100644
--- a/doc/qtcreator/src/meson/creator-projects-meson-building.qdoc
+++ b/doc/qtcreator/src/meson/creator-projects-meson-building.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
@@ -31,19 +31,22 @@
\image qtcreator-meson-build-settings.png "Meson build settings"
- Settings are grouped by category by Meson. All items are user modifiable
- except \c backend which is forced to Ninja, \c {buildtype}, \c debug as well
- as \c optimization to ensure a good compatibility with \QC.
+ Meson builds projects in the directory specified in the
+ \uicontrol {Build directory} field.
- Each setting type has its own editor. To modif any setting, double-click it,
- either edit the field, or select your choice depending on the control. To
- apply changes, select \uicontrol {Apply configuration changes}. This will
- trigger a \c {meson configure} command if there were any configuration
- changes. If for any reason the build directory configuration is broken,
- select \uicontrol {Wipe project}. This should fix any build directory.
+ Build settings are grouped by category. You can modify all settings,
+ except \c backend, which is forced to Ninja, \c {buildtype}, \c debug,
+ and \c optimization to ensure compatibility with \QC.
- \note Any modified setting will remain in bold until \uicontrol
- {Apply configuration changes} is selected.
+ To modify a setting, double-click it. Modified settings are formatted in
+ bold until you select \uicontrol {Apply configuration changes} to apply
+ them. This triggers \c {meson configure}. If problems arise, select
+ \uicontrol {Wipe Project} to fix the build directory configuration.
+
+ Meson supports cross-compiling in addition to native building. \QC
+ generates a native build file for you. To use a custom native file or a
+ cross file instead, specify the file name in \uicontrol Parameters.
+ For example, \c {--cross-file cross_file.txt}.
For more information about using Meson, see \l{Setting Up Meson}.
@@ -56,8 +59,7 @@
\image qtcreator-meson-build-steps.png "Meson build steps"
- The build errors and warnings are parsed and displayed in the
- \uicontrol Issues output pane.
+ The build errors and warnings are parsed and displayed in \l Issues.
\section1 Meson Clean Steps
diff --git a/doc/qtcreator/src/meson/creator-projects-meson.qdoc b/doc/qtcreator/src/meson/creator-projects-meson.qdoc
index f7865ee225..664c444aa3 100644
--- a/doc/qtcreator/src/meson/creator-projects-meson.qdoc
+++ b/doc/qtcreator/src/meson/creator-projects-meson.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2020 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
@@ -99,7 +99,6 @@
The following features are not supported yet:
\list
- \li Cross compilation.
\li Showing header files in project tree.
\li Configuration change detection, for example when building triggers a
Meson configuration first.
diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc
index 24b30b4a4c..a3ad3bb15d 100644
--- a/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc
+++ b/doc/qtcreator/src/projects/creator-only/creator-projects-creating.qdoc
@@ -80,7 +80,7 @@
In the first step, you select a template for the project. You can filter
templates (1) to view only those that apply to a particular target platform.
- \image qtcreator-new-qt-quick-project-wizard.png
+ \image qtcreator-new-project.png
Next, you select a location for the project and specify settings for it.
@@ -326,7 +326,7 @@
\uicontrol {New Subproject}. Follow the steps in the
\uicontrol {New Subproject} wizard to create a subproject.
- \image qtcreator-new-subproject.png
+ \image qtcreator-new-qt-quick-project.png
To add an existing project as a subproject, select
\uicontrol {Add Existing Projects} in the context menu.
diff --git a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-run-debug.qdocinc b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-run-debug.qdocinc
index ce5b73d07e..f8c1b3bfd2 100644
--- a/doc/qtcreator/src/projects/creator-only/creator-projects-settings-run-debug.qdocinc
+++ b/doc/qtcreator/src/projects/creator-only/creator-projects-settings-run-debug.qdocinc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Creator documentation.
@@ -38,6 +38,18 @@
execute any JavaScript functions. Therefore, you must make sure that the
port is properly protected by a firewall.
+ Optionally, in \uicontrol {Additional startup commands}, you can enter
+ additional settings for debugging C++:
+
+ \list
+ \li \l{Adding Custom Debugging Helpers}{Custom debugging helpers}
+ \li \l{Specifying GDB Settings}{GDB commands} to execute after GDB
+ has started, but before the debugged program is started or
+ attached, and before the debugging helpers are initialized
+ \endlist
+
+ However, you can usually leave this field empty.
+
For more information about debugging, see \l{Debugging}.
//! [run settings debugger]
diff --git a/doc/qtcreator/src/qtquick/creator-only/qtquick-creating.qdoc b/doc/qtcreator/src/qtquick/creator-only/qtquick-creating.qdoc
index c3f4d9d1bb..7adfe57020 100644
--- a/doc/qtcreator/src/qtquick/creator-only/qtquick-creating.qdoc
+++ b/doc/qtcreator/src/qtquick/creator-only/qtquick-creating.qdoc
@@ -36,7 +36,7 @@
\title Creating Qt Quick Projects
- \image qmldesigner-new-project.png "New Project dialog"
+ \image qtcreator-new-qt-quick-project.png "New Project dialog"
The following table lists the wizard templates for creating a new
Qt Quick project from scratch.
diff --git a/doc/qtcreator/src/vcs/creator-vcs-git.qdoc b/doc/qtcreator/src/vcs/creator-vcs-git.qdoc
index 4f3842dd8c..2f6236113b 100644
--- a/doc/qtcreator/src/vcs/creator-vcs-git.qdoc
+++ b/doc/qtcreator/src/vcs/creator-vcs-git.qdoc
@@ -299,7 +299,7 @@
\uicontrol {Include Old Entries} and \uicontrol {Include Tags}.
To add a tag to a change in the change log, select \uicontrol Branches >
- \uicontrol Log. Select the change, and then select > \uicontrol {Add Tag
+ \uicontrol Log. Select the change, and then select \uicontrol {Add Tag
for Change} in the context menu.
If you checked out a specific commit, the list of branches displays a
diff --git a/doc/qtdesignstudio/images/icons/align-camera-on.png b/doc/qtdesignstudio/images/icons/align-camera-on.png
new file mode 100644
index 0000000000..382a2ac6b3
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/align-camera-on.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/align-view-on.png b/doc/qtdesignstudio/images/icons/align-view-on.png
new file mode 100644
index 0000000000..3617416f6f
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/align-view-on.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/particle-animation-off.png b/doc/qtdesignstudio/images/icons/particle-animation-off.png
new file mode 100644
index 0000000000..e3cd945edb
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/particle-animation-off.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/particle-animation-on.png b/doc/qtdesignstudio/images/icons/particle-animation-on.png
new file mode 100644
index 0000000000..d240b34c2a
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/particle-animation-on.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/particle-pause.png b/doc/qtdesignstudio/images/icons/particle-pause.png
new file mode 100644
index 0000000000..442a77211f
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/particle-pause.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/particle-play.png b/doc/qtdesignstudio/images/icons/particle-play.png
new file mode 100644
index 0000000000..cc04c94897
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/particle-play.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/particle-restart.png b/doc/qtdesignstudio/images/icons/particle-restart.png
new file mode 100644
index 0000000000..dc1c06bd49
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/particle-restart.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/icons/particles-seek.png b/doc/qtdesignstudio/images/icons/particles-seek.png
new file mode 100644
index 0000000000..c6c76fe4ca
--- /dev/null
+++ b/doc/qtdesignstudio/images/icons/particles-seek.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor-axis-helper.png b/doc/qtdesignstudio/images/studio-3d-editor-axis-helper.png
index 0e0f690881..788b498991 100644
--- a/doc/qtdesignstudio/images/studio-3d-editor-axis-helper.png
+++ b/doc/qtdesignstudio/images/studio-3d-editor-axis-helper.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor-move.png b/doc/qtdesignstudio/images/studio-3d-editor-move.png
index 6cc885655d..1e8be3f865 100644
--- a/doc/qtdesignstudio/images/studio-3d-editor-move.png
+++ b/doc/qtdesignstudio/images/studio-3d-editor-move.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor-rotate.png b/doc/qtdesignstudio/images/studio-3d-editor-rotate.png
index e53f38f942..b6c4ce167a 100644
--- a/doc/qtdesignstudio/images/studio-3d-editor-rotate.png
+++ b/doc/qtdesignstudio/images/studio-3d-editor-rotate.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor-scale.png b/doc/qtdesignstudio/images/studio-3d-editor-scale.png
index 7902d02103..19d4258275 100644
--- a/doc/qtdesignstudio/images/studio-3d-editor-scale.png
+++ b/doc/qtdesignstudio/images/studio-3d-editor-scale.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/studio-3d-editor.png b/doc/qtdesignstudio/images/studio-3d-editor.png
index 7ac86341d4..a62a6deb76 100644
--- a/doc/qtdesignstudio/images/studio-3d-editor.png
+++ b/doc/qtdesignstudio/images/studio-3d-editor.png
Binary files differ
diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc
index ea415a20cc..7b147fe684 100644
--- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc
+++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-editor.qdoc
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2021 The Qt Company Ltd.
+** Copyright (C) 2022 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Studio documentation.
@@ -26,7 +26,7 @@
/*!
\previouspage qtquick-form-editor.html
\page studio-3d-editor.html
- \nextpage quick-library.html
+ \nextpage quick-components-view.html
\title 3D Editor
@@ -64,11 +64,11 @@
affect only the local transformations of the component or whether they
transform with respect to the global space.
- Additional helpful features when editing 3D scenes are the \e {edit light},
- which is a quick way to light the scene, and the grid that helps you to
- navigate in 3D space. Select the \inlineimage grid_on.png
- (\uicontrol {Toggle Grid Visibility}) or press \key G to show or hide the
- grid.
+ Another helpful feature when editing 3D scenes is the \e {edit light},
+ which is a quick way to light the scene.
+
+ Additionally, you can toggle the visibility of the grid, selection boxes,
+ icon gizmos, and camera frustums in the 3D scene.
To refresh the contents of \uicontrol {3D Editor}, press \key P or
select the \inlineimage icons/reset.png
@@ -97,7 +97,7 @@
\li To pan, press \key Alt (or \key Option on \macos) and use the
middle mouse button to click and drag anywhere in the rendered
view to slide the view around.
- \note At the moment it is not possible to pan using Magic Mouse.
+ \note It is not possible to pan using Magic Mouse.
\li To orbit, press \key Alt and click and drag anywhere in the rendered
view to rotate the view.
\li To zoom, use the mouse wheel or press \key Alt and right-click
@@ -109,7 +109,7 @@
select \inlineimage fit_selected.png
(\uicontrol {Fit Selected}) or press \key F.
- The world axis helper (1) shows the direction of the world axes in view.
+ The world axis helper (1) shows the direction of the world axes in the view.
To point the camera at the currently selected component in the direction of
an axis, click the axis. Clicking the dot at the end of the axis will point
the camera at the opposite direction of the axis. If no component is
@@ -179,6 +179,7 @@
{keyboard shortcuts} applicable to your operating system, for example,
\key Ctrl+C and \key Ctrl+V on Windows to copy-paste components.
+ \target moving components 3d editor
\section1 Moving Components
\image studio-3d-editor-move.png "3D Editor in move mode"
@@ -233,6 +234,76 @@
gray handle at the center of the component.
\endlist
+ \section1 Aligning Views and Cameras
+
+ To align a camera to the \uicontrol {3D Editor} view:
+ \list 1
+ \li Select a camera in \uicontrol {3D Editor} or \uicontrol {Navigator}.
+ \li In \uicontrol {3D Editor},
+ select \inlineimage icons/align-camera-on.png
+ .
+ \endlist
+
+ This moves and rotates the camera so that the camera shows the same view
+ as the current view in \uicontrol {3D Editor}.
+
+ To align the \uicontrol {3D Editor} view to a camera:
+ \list 1
+ \li Select a camera in \uicontrol {3D Editor} or \uicontrol {Navigator}.
+ \li In \uicontrol {3D Editor},
+ select \inlineimage icons/align-view-on.png
+ .
+ \endlist
+
+ This copies the position as well as x and y rotation values from the
+ camera and applies them to \uicontrol {3D Editor}.
+
+ \section1 Toggling Visibility
+
+ To toggle the visibility of objects in \uicontrol {3D Editor}, select
+ \inlineimage icons/visibilityon.png
+ in the toolbar. This opens a menu with the following options:
+
+ \table
+ \row
+ \li Show Grid
+ \li Toggles the visibility of the helper grid.
+ \row
+ \li Show Selection Boxes
+ \li Toggles the visibility of selection boxes for selected 3D objects.
+ \row
+ \li Show Icon Gizmos
+ \li Toggles the visibility of icon gizmos for object such as cameras,
+ lights, and particle systems.
+ \row
+ \li Always Show Camera Frustums
+ \li Toggles between always showing the camera frustum and showing it
+ only for cameras selected in \uicontrol {3D Editor}.
+ \endtable
+
+ \section1 Particle Editor
+
+ The particle editor tools help you preview your particle systems in
+ \uicontrol {3D Editor}. You can select one particle system to preview at a
+ time.
+
+ To preview a particle system in \uicontrol{3D Editor}:
+
+ \list 1
+ \li Select a particle system in \uicontrol Navigator or
+ \uicontrol {3D Editor}.
+ \li In the \uicontrol {3D Editor}, select
+ \inlineimage icons/particle-animation-on.png
+ to activate particle animation. Now you can see the particle animation in
+ \uicontrol{3D Editor}.
+ \endlist
+
+ You can pause the particle animation by selecting
+ \inlineimage icons/particle-animation-on.png
+ . When the animation is paused, you can use
+ \inlineimage icons/particles-seek.png
+ to manually seek forward or backward in the particle animation.
+
\section1 Summary of the 3D Editor Toolbar Buttons
The \uicontrol {3D Editor} toolbar contains the following buttons:
@@ -254,7 +325,7 @@
\inlineimage move_on.png
\li Activate the Move Tool
\li \key W
- \li \l{Moving Components}
+ \li \l{moving components 3d editor}{Moving Components}
\row
\li \inlineimage rotate_off.png
\inlineimage rotate_on.png
@@ -291,17 +362,47 @@
\li \key U
\li \l{Using Edit Light}
\row
- \li \inlineimage grid_off.png
- \inlineimage grid_on.png
- \li Toggle Grid Visibility
- \li \key G
+ \li \inlineimage icons/align-camera-on.png
+ \li Align Selected Cameras to View
+ \li
+ \li\l{Aligning Views and Cameras}
+ \row
+ \li \inlineimage icons/align-view-on.png
+ \li Align View to Selected Camera
+ \li
+ \li \l{Aligning Views and Cameras}
+ \row
+ \li \inlineimage icons/visibilityon.png
+ \li Visibility Toggles
\li
+ \li \l{Toggling Visibility}
+ \row
+ \li \inlineimage icons/particles-seek.png
+ \li Seek Particle System Time
+ \li
+ \li \l{Particle Editor}
+ \row
+ \li \inlineimage icons/particle-animation-on.png
+ \inlineimage icons/particle-animation-off.png
+ \li Toggle Particle Animation
+ \li \key V
+ \li \l{Particle Editor}
+ \row
+ \li \inlineimage icons/particle-play.png
+ \inlineimage icons/particle-pause.png
+ \li Play/Pause Particles
+ \li \key ,
+ \li \l{Particle Editor}
+ \row
+ \li \inlineimage icons/particle-restart.png
+ \li Restart Particles
+ \li \key /
+ \li \l{Particle Editor}
\row
\li \inlineimage icons/reset.png
\li Reset View
- \li \key R
+ \li \key P
\li
\endtable
-
*/
diff --git a/scripts/common.py b/scripts/common.py
index a04beb27ef..6851b000e4 100644
--- a/scripts/common.py
+++ b/scripts/common.py
@@ -229,6 +229,16 @@ def codesign_call():
codesign_call.extend(signing_flags.split())
return codesign_call
+def codesign_executable(path):
+ codesign = codesign_call()
+ if not codesign:
+ return
+ entitlements_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'dist',
+ 'installer', 'mac', os.path.basename(path) + '.entitlements')
+ if os.path.exists(entitlements_path):
+ codesign.extend(['--entitlements', entitlements_path])
+ subprocess.check_call(codesign + [path])
+
def os_walk(path, filter, function):
for r, _, fs in os.walk(path):
for f in fs:
@@ -237,20 +247,21 @@ def os_walk(path, filter, function):
function(ff)
def conditional_sign_recursive(path, filter):
- codesign = codesign_call()
- if is_mac_platform() and codesign:
- os_walk(path, filter, lambda fp: subprocess.check_call(codesign + [fp]))
+ if is_mac_platform():
+ os_walk(path, filter, lambda fp: codesign_executable(fp))
def codesign(app_path):
+ codesign = codesign_call()
+ if not codesign or not is_mac_platform():
+ return
# sign all executables in Resources
conditional_sign_recursive(os.path.join(app_path, 'Contents', 'Resources'),
lambda ff: os.access(ff, os.X_OK))
# sign all libraries in Imports
conditional_sign_recursive(os.path.join(app_path, 'Contents', 'Imports'),
lambda ff: ff.endswith('.dylib'))
- codesign = codesign_call()
- if is_mac_platform() and codesign:
- entitlements_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'dist',
- 'installer', 'mac', 'entitlements.plist')
- # sign the whole bundle
- subprocess.check_call(codesign + ['--deep', app_path, '--entitlements', entitlements_path])
+
+ # sign the whole bundle
+ entitlements_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..', 'dist',
+ 'installer', 'mac', 'entitlements.plist')
+ subprocess.check_call(codesign + ['--deep', app_path, '--entitlements', entitlements_path])
diff --git a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h
index cb23b2c9ad..cb34c253f9 100644
--- a/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h
+++ b/share/qtcreator/qml/qmlpuppet/commands/view3dactioncommand.h
@@ -50,6 +50,7 @@ public:
ShowSelectionBox,
ShowIconGizmo,
ShowCameraFrustum,
+ ShowParticleEmitter,
Edit3DParticleModeToggle,
ParticlesPlay,
ParticlesRestart,
diff --git a/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc b/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc
index 065f9e32cf..9831bec4be 100644
--- a/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc
+++ b/share/qtcreator/qml/qmlpuppet/editor3d_qt6.qrc
@@ -35,7 +35,6 @@
<file>mockfiles/qt6/LightGizmo.qml</file>
<file>mockfiles/qt6/LightIconGizmo.qml</file>
<file>mockfiles/qt6/LightModel.qml</file>
- <file>mockfiles/qt6/ParticleSystemGizmo.qml</file>
<file>mockfiles/qt6/Line3D.qml</file>
<file>mockfiles/qt6/MaterialNodeView.qml</file>
<file>mockfiles/qt6/ModelNode2DImageView.qml</file>
@@ -44,6 +43,8 @@
<file>mockfiles/qt6/MoveGizmo.qml</file>
<file>mockfiles/qt6/NodeNodeView.qml</file>
<file>mockfiles/qt6/Overlay2D.qml</file>
+ <file>mockfiles/qt6/ParticleSystemGizmo.qml</file>
+ <file>mockfiles/qt6/ParticleEmitterGizmo.qml</file>
<file>mockfiles/qt6/PlanarDraggable.qml</file>
<file>mockfiles/qt6/PlanarMoveHandle.qml</file>
<file>mockfiles/qt6/PlanarScaleHandle.qml</file>
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml
index 0b15f19067..904a062a62 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt5/EditView3D.qml
@@ -385,14 +385,12 @@ Item {
lightIconGizmos[slotFound].targetNode = obj;
lightIconGizmos[slotFound].locked = _generalHelper.isLocked(obj);
lightIconGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
- _generalHelper.registerGizmoTarget(obj);
return;
}
// No free gizmos available, create a new one
var gizmoComponent = Qt.createComponent("LightIconGizmo.qml");
if (gizmoComponent.status === Component.Ready) {
- _generalHelper.registerGizmoTarget(obj);
var gizmo = gizmoComponent.createObject(overlayView,
{"view3D": overlayView, "targetNode": obj,
"selectedNodes": selectedNodes, "scene": scene,
@@ -426,7 +424,6 @@ Item {
cameraGizmos[slotFound].targetNode = obj;
cameraGizmos[slotFound].locked = _generalHelper.isLocked(obj);
cameraGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
- _generalHelper.registerGizmoTarget(obj);
return;
}
@@ -434,7 +431,6 @@ Item {
var gizmoComponent = Qt.createComponent("CameraGizmo.qml");
var frustumComponent = Qt.createComponent("CameraFrustum.qml");
if (gizmoComponent.status === Component.Ready && frustumComponent.status === Component.Ready) {
- _generalHelper.registerGizmoTarget(obj);
var geometryName = _generalHelper.generateUniqueName("CameraGeometry");
var frustum = frustumComponent.createObject(
overlayScene,
@@ -463,7 +459,6 @@ Item {
if (lightIconGizmos[i].targetNode === obj) {
lightIconGizmos[i].scene = null;
lightIconGizmos[i].targetNode = null;
- _generalHelper.unregisterGizmoTarget(obj);
return;
}
}
@@ -475,7 +470,6 @@ Item {
if (cameraGizmos[i].targetNode === obj) {
cameraGizmos[i].scene = null;
cameraGizmos[i].targetNode = null;
- _generalHelper.unregisterGizmoTarget(obj);
return;
}
}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml
index eb7d50d2e4..25297f8fc6 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/EditView3D.qml
@@ -42,6 +42,7 @@ Item {
property bool showSelectionBox: true
property bool showIconGizmo: true
property bool showCameraFrustum: false
+ property bool showParticleEmitter: false
property bool usePerspective: true
property bool globalOrientation: false
property alias contentItem: contentItem
@@ -58,9 +59,10 @@ Item {
property var lightIconGizmos: []
property var cameraGizmos: []
property var particleSystemIconGizmos: []
+ property var particleEmitterGizmos: []
property var selectionBoxes: []
property rect viewPortRect: Qt.rect(0, 0, 1000, 1000)
-
+ property Node activeParticleSystem: null
property bool shuttingDown: false
property real fps: 0
@@ -70,15 +72,16 @@ Item {
signal changeObjectProperty(var objects, var propNames)
signal notifyActiveSceneChange()
- onUsePerspectiveChanged: _generalHelper.storeToolState(sceneId, "usePerspective", usePerspective)
- onShowEditLightChanged: _generalHelper.storeToolState(sceneId, "showEditLight", showEditLight)
- onGlobalOrientationChanged: _generalHelper.storeToolState(sceneId, "globalOrientation", globalOrientation)
- onShowGridChanged: _generalHelper.storeToolState(sceneId, "showGrid", showGrid);
- onShowSelectionBoxChanged: _generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox);
- onShowIconGizmoChanged: _generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo);
- onShowCameraFrustumChanged: _generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum);
- onSelectionModeChanged: _generalHelper.storeToolState(sceneId, "selectionMode", selectionMode);
- onTransformModeChanged: _generalHelper.storeToolState(sceneId, "transformMode", transformMode);
+ onUsePerspectiveChanged: _generalHelper.storeToolState(sceneId, "usePerspective", usePerspective)
+ onShowEditLightChanged: _generalHelper.storeToolState(sceneId, "showEditLight", showEditLight)
+ onGlobalOrientationChanged: _generalHelper.storeToolState(sceneId, "globalOrientation", globalOrientation)
+ onShowGridChanged: _generalHelper.storeToolState(sceneId, "showGrid", showGrid);
+ onShowSelectionBoxChanged: _generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox);
+ onShowIconGizmoChanged: _generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo);
+ onShowCameraFrustumChanged: _generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum);
+ onShowParticleEmitterChanged: _generalHelper.storeToolState(sceneId, "showParticleEmitter", showParticleEmitter);
+ onSelectionModeChanged: _generalHelper.storeToolState(sceneId, "selectionMode", selectionMode);
+ onTransformModeChanged: _generalHelper.storeToolState(sceneId, "transformMode", transformMode);
onActiveSceneChanged: updateActiveScene()
@@ -232,6 +235,11 @@ Item {
else if (resetToDefault)
showCameraFrustum = false;
+ if ("showParticleEmitter" in toolStates)
+ showParticleEmitter = toolStates.showParticleEmitter;
+ else if (resetToDefault)
+ showParticleEmitter = false;
+
if ("usePerspective" in toolStates)
usePerspective = toolStates.usePerspective;
else if (resetToDefault)
@@ -265,6 +273,7 @@ Item {
_generalHelper.storeToolState(sceneId, "showSelectionBox", showSelectionBox)
_generalHelper.storeToolState(sceneId, "showIconGizmo", showIconGizmo)
_generalHelper.storeToolState(sceneId, "showCameraFrustum", showCameraFrustum)
+ _generalHelper.storeToolState(sceneId, "showParticleEmitter", showParticleEmitter)
_generalHelper.storeToolState(sceneId, "usePerspective", usePerspective)
_generalHelper.storeToolState(sceneId, "globalOrientation", globalOrientation)
_generalHelper.storeToolState(sceneId, "selectionMode", selectionMode);
@@ -376,14 +385,12 @@ Item {
lightIconGizmos[slotFound].targetNode = obj;
lightIconGizmos[slotFound].locked = _generalHelper.isLocked(obj);
lightIconGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
- _generalHelper.registerGizmoTarget(obj);
return;
}
// No free gizmos available, create a new one
var gizmoComponent = Qt.createComponent("LightIconGizmo.qml");
if (gizmoComponent.status === Component.Ready) {
- _generalHelper.registerGizmoTarget(obj);
var gizmo = gizmoComponent.createObject(overlayView,
{"view3D": overlayView, "targetNode": obj,
"selectedNodes": selectedNodes, "scene": scene,
@@ -417,7 +424,6 @@ Item {
cameraGizmos[slotFound].targetNode = obj;
cameraGizmos[slotFound].locked = _generalHelper.isLocked(obj);
cameraGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
- _generalHelper.registerGizmoTarget(obj);
return;
}
@@ -425,7 +431,6 @@ Item {
var gizmoComponent = Qt.createComponent("CameraGizmo.qml");
var frustumComponent = Qt.createComponent("CameraFrustum.qml");
if (gizmoComponent.status === Component.Ready && frustumComponent.status === Component.Ready) {
- _generalHelper.registerGizmoTarget(obj);
var geometryName = _generalHelper.generateUniqueName("CameraGeometry");
var frustum = frustumComponent.createObject(
overlayScene,
@@ -466,26 +471,66 @@ Item {
particleSystemIconGizmos[slotFound].targetNode = obj;
particleSystemIconGizmos[slotFound].locked = _generalHelper.isLocked(obj);
particleSystemIconGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
- _generalHelper.registerGizmoTarget(obj);
return;
}
// No free gizmos available, create a new one
var gizmoComponent = Qt.createComponent("ParticleSystemGizmo.qml");
if (gizmoComponent.status === Component.Ready) {
- _generalHelper.registerGizmoTarget(obj);
var gizmo = gizmoComponent.createObject(overlayView,
{"view3D": overlayView, "targetNode": obj,
"selectedNodes": selectedNodes, "scene": scene,
"activeScene": activeScene,
"locked": _generalHelper.isLocked(obj),
"hidden": _generalHelper.isHidden(obj),
- "globalShow": showIconGizmo});
+ "globalShow": showIconGizmo,
+ "activeParticleSystem": activeParticleSystem});
particleSystemIconGizmos[particleSystemIconGizmos.length] = gizmo;
gizmo.clicked.connect(handleObjectClicked);
gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
gizmo.activeScene = Qt.binding(function() {return activeScene;});
gizmo.globalShow = Qt.binding(function() {return showIconGizmo;});
+ gizmo.activeParticleSystem = Qt.binding(function() {return activeParticleSystem;});
+ }
+ }
+
+ function addParticleEmitterGizmo(scene, obj)
+ {
+ // Insert into first available gizmo if we don't already have gizmo for this object
+ var slotFound = -1;
+ for (var i = 0; i < particleEmitterGizmos.length; ++i) {
+ if (!particleEmitterGizmos[i].targetNode) {
+ slotFound = i;
+ } else if (particleEmitterGizmos[i].targetNode === obj) {
+ particleEmitterGizmos[i].scene = scene;
+ return;
+ }
+ }
+
+ if (slotFound !== -1) {
+ particleEmitterGizmos[slotFound].scene = scene;
+ particleEmitterGizmos[slotFound].targetNode = obj;
+ particleEmitterGizmos[slotFound].hidden = _generalHelper.isHidden(obj);
+ particleEmitterGizmos[slotFound].systemHidden = _generalHelper.isHidden(obj.system);
+ return;
+ }
+
+ // No free gizmos available, create a new one
+ var gizmoComponent = Qt.createComponent("ParticleEmitterGizmo.qml");
+ if (gizmoComponent.status === Component.Ready) {
+ var gizmo = gizmoComponent.createObject(
+ overlayScene,
+ {"targetNode": obj, "selectedNodes": selectedNodes,
+ "activeParticleSystem": activeParticleSystem, "scene": scene,
+ "activeScene": activeScene, "hidden": _generalHelper.isHidden(obj),
+ "systemHidden": _generalHelper.isHidden(obj.system),
+ "globalShow": showParticleEmitter});
+
+ particleEmitterGizmos[particleEmitterGizmos.length] = gizmo;
+ gizmo.selectedNodes = Qt.binding(function() {return selectedNodes;});
+ gizmo.activeParticleSystem = Qt.binding(function() {return activeParticleSystem;});
+ gizmo.globalShow = Qt.binding(function() {return showParticleEmitter;});
+ gizmo.activeScene = Qt.binding(function() {return activeScene;});
}
}
@@ -495,7 +540,6 @@ Item {
if (lightIconGizmos[i].targetNode === obj) {
lightIconGizmos[i].scene = null;
lightIconGizmos[i].targetNode = null;
- _generalHelper.unregisterGizmoTarget(obj);
return;
}
}
@@ -507,7 +551,6 @@ Item {
if (cameraGizmos[i].targetNode === obj) {
cameraGizmos[i].scene = null;
cameraGizmos[i].targetNode = null;
- _generalHelper.unregisterGizmoTarget(obj);
return;
}
}
@@ -519,7 +562,17 @@ Item {
if (particleSystemIconGizmos[i].targetNode === obj) {
particleSystemIconGizmos[i].scene = null;
particleSystemIconGizmos[i].targetNode = null;
- _generalHelper.unregisterGizmoTarget(obj);
+ return;
+ }
+ }
+ }
+
+ function releaseParticleEmitterGizmo(obj)
+ {
+ for (var i = 0; i < particleEmitterGizmos.length; ++i) {
+ if (particleEmitterGizmos[i].targetNode === obj) {
+ particleEmitterGizmos[i].scene = null;
+ particleEmitterGizmos[i].targetNode = null;
return;
}
}
@@ -555,6 +608,16 @@ Item {
}
}
+ function updateParticleEmitterGizmoScene(scene, obj)
+ {
+ for (var i = 0; i < particleEmitterGizmos.length; ++i) {
+ if (particleEmitterGizmos[i].targetNode === obj) {
+ particleEmitterGizmos[i].scene = scene;
+ return;
+ }
+ }
+ }
+
Component.onCompleted: {
createEditView();
selectObjects([]);
@@ -588,7 +651,6 @@ Item {
return;
}
}
-
}
function onHiddenStateChanged(node)
{
@@ -610,6 +672,15 @@ Item {
return;
}
}
+ for (var i = 0; i < particleEmitterGizmos.length; ++i) {
+ if (particleEmitterGizmos[i].targetNode === node) {
+ particleEmitterGizmos[i].hidden = _generalHelper.isHidden(node);
+ return;
+ } else if (particleEmitterGizmos[i].targetNode && particleEmitterGizmos[i].targetNode.system === node) {
+ particleEmitterGizmos[i].systemHidden = _generalHelper.isHidden(node);
+ return;
+ }
+ }
}
}
@@ -810,9 +881,16 @@ Item {
onPressed: (mouse)=> {
if (viewRoot.editView) {
- var pickResult = _generalHelper.pickViewAt(viewRoot.editView, mouse.x, mouse.y);
- handleObjectClicked(_generalHelper.resolvePick(pickResult.objectHit),
- mouse.modifiers & Qt.ControlModifier);
+ // First pick overlay to check for hits there
+ var pickResult = _generalHelper.pickViewAt(overlayView, mouse.x, mouse.y);
+ var resolvedResult = _generalHelper.resolvePick(pickResult.objectHit);
+ if (!resolvedResult) {
+ // No hits from overlay view, pick the main scene
+ pickResult = _generalHelper.pickViewAt(viewRoot.editView, mouse.x, mouse.y);
+ resolvedResult = _generalHelper.resolvePick(pickResult.objectHit);
+ }
+
+ handleObjectClicked(resolvedResult, mouse.modifiers & Qt.ControlModifier);
if (pickResult.objectHit) {
if (transformMode === EditView3D.TransformMode.Move)
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml
index 7752693d55..2b78dd04aa 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/IconGizmo.qml
@@ -47,6 +47,7 @@ Item {
property bool locked: false
property bool globalShow: true
property bool canBeVisible: activeScene === scene && !hidden && (targetNode ? targetNode.visible : false)
+ property real iconOpacity: selected ? 0.2 : 1
property alias iconSource: iconImage.source
@@ -76,7 +77,7 @@ Item {
border.color: "#7777ff"
border.width: !iconGizmo.locked && iconGizmo.highlightOnHover && iconGizmo.hasMouse ? 2 : 0
radius: 5
- opacity: iconGizmo.selected ? 0.2 : 1
+ opacity: iconGizmo.iconOpacity
Image {
id: iconImage
fillMode: Image.Pad
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ParticleEmitterGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ParticleEmitterGizmo.qml
new file mode 100644
index 0000000000..a06a38a202
--- /dev/null
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ParticleEmitterGizmo.qml
@@ -0,0 +1,127 @@
+/****************************************************************************
+**
+** 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 QtQuick3D
+import QtQuick3D.Particles3D
+
+Node {
+ id: root
+
+ property Node targetNode: null
+ property var selectedNodes: []
+ property Node activeParticleSystem: null
+ property Node scene: null
+ property Node activeScene: null
+ property bool hidden: false
+ property bool systemHidden: false
+ property Node shapeModel: null
+ property bool globalShow: false
+ property bool canBeVisible: activeScene === scene && targetNode && !hidden && !systemHidden
+ property bool partOfActiveSystem: root.targetNode && root.targetNode.system === activeParticleSystem
+
+ opacity: 0.15
+
+ readonly property bool selected: selectedNodes.includes(targetNode)
+
+ visible: canBeVisible && (globalShow || selected)
+
+ position: targetNode ? targetNode.scenePosition : Qt.vector3d(0, 0, 0)
+ rotation: targetNode ? targetNode.sceneRotation : Qt.quaternion(1, 0, 0, 0)
+ scale: targetNode ? targetNode.sceneScale : Qt.vector3d(1, 1, 1)
+
+ function basicShape()
+ {
+ if (targetNode && targetNode.shape && targetNode.shape instanceof ParticleShape3D) {
+ if (targetNode.shape.type === ParticleShape3D.Cube)
+ return "#Cube";
+ else if (targetNode.shape.type === ParticleShape3D.Cylinder)
+ return "#Cylinder";
+ }
+ return "#Sphere";
+ }
+
+ function updateShape()
+ {
+ if (shapeModel)
+ shapeModel.destroy();
+
+ if (!targetNode)
+ return;
+
+ if (targetNode.shape instanceof ParticleModelShape3D) {
+ shapeModel = _generalHelper.createParticleEmitterGizmoModel(targetNode, defaultMaterial);
+ shapeModel.parent = root;
+ }
+ }
+
+ Component.onCompleted: {
+ updateShape();
+ }
+
+ Connections {
+ target: targetNode
+ function onSystemChanged() { systemHidden = _generalHelper.isHidden(system); }
+ }
+
+ Connections {
+ target: targetNode
+ function onShapeChanged() { updateShape(); }
+ }
+
+ Connections {
+ target: targetNode.shape instanceof ParticleModelShape3D ? targetNode.shape
+ :null
+ function onDelegateChanged() { updateShape(); }
+ }
+
+ Connections {
+ target: targetNode.shape instanceof ParticleModelShape3D ? targetNode.shape.delegate
+ : null
+ function onSourceChanged() { updateShape(); }
+ }
+
+ Model {
+ readonly property Node _pickTarget: root.targetNode
+ materials: [defaultMaterial]
+ source: basicShape()
+ scale: root.targetNode && root.targetNode.shape && targetNode.shape instanceof ParticleShape3D
+ ? root.targetNode.shape.extents.times(0.02) // default extent is 50
+ : autoScale.getScale(Qt.vector3d(0.1, 0.1, 0.1))
+ visible: !shapeModel
+ }
+
+ AutoScaleHelper {
+ id: autoScale
+ view3D: overlayView
+ }
+
+ DefaultMaterial {
+ id: defaultMaterial
+ diffuseColor: root.selected ? "#FF0000" : partOfActiveSystem ? "#FFFF00" : "#AAAAAA"
+ lighting: DefaultMaterial.NoLighting
+ cullMode: Material.NoCulling
+ }
+}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ParticleSystemGizmo.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ParticleSystemGizmo.qml
index de591fcd21..3d498ce335 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ParticleSystemGizmo.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/ParticleSystemGizmo.qml
@@ -28,5 +28,9 @@ import QtQuick3D 6.0
IconGizmo {
id: particleSystemGizmo
+
+ property Node activeParticleSystem: null
+
iconSource: "qrc:///qtquickplugin/mockfiles/images/editor_particlesystem.png"
+ iconOpacity: selected || activeParticleSystem == targetNode ? 0.2 : 1
}
diff --git a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/RotateRing.qml b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/RotateRing.qml
index 8003839a89..79d31f4594 100644
--- a/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/RotateRing.qml
+++ b/share/qtcreator/qml/qmlpuppet/mockfiles/qt6/RotateRing.qml
@@ -54,6 +54,7 @@ Model {
Model {
id: pickModel
+ readonly property bool _edit3dLocked: true // Make this non-pickable in main picking handling
objectName: "PickModel for " + rotateRing.objectName
source: "../meshes/ringselect.mesh"
pickable: true
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
index 9d7d4b05ce..66cd2d80b8 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.cpp
@@ -46,6 +46,12 @@
#include <QtQuick/qquickitem.h>
#include <QtCore/qmath.h>
+#ifdef QUICK3D_PARTICLES_MODULE
+#include <QtQuick3DParticles/private/qquick3dparticlemodelshape_p.h>
+#include <QtQuick3DParticles/private/qquick3dparticleemitter_p.h>
+#include <QtQuick3DParticles/private/qquick3dparticletrailemitter_p.h>
+#endif
+
#include <limits>
namespace QmlDesigner {
@@ -404,22 +410,6 @@ QQuick3DNode *GeneralHelper::resolvePick(QQuick3DNode *pickNode)
return pickNode;
}
-void GeneralHelper::registerGizmoTarget(QQuick3DNode *node)
-{
- if (!m_gizmoTargets.contains(node)) {
- m_gizmoTargets.insert(node);
- node->installEventFilter(this);
- }
-}
-
-void GeneralHelper::unregisterGizmoTarget(QQuick3DNode *node)
-{
- if (m_gizmoTargets.contains(node)) {
- m_gizmoTargets.remove(node);
- node->removeEventFilter(this);
- }
-}
-
bool GeneralHelper::isLocked(QQuick3DNode *node) const
{
if (node) {
@@ -460,6 +450,31 @@ bool GeneralHelper::isPickable(QQuick3DNode *node) const
return true;
}
+// Emitter gizmo model creation is done in C++ as creating dynamic properties and
+// assigning materials to dynamically created models is lot simpler in C++
+QQuick3DNode *GeneralHelper::createParticleEmitterGizmoModel(QQuick3DNode *emitter,
+ QQuick3DMaterial *material) const
+{
+#ifdef QUICK3D_PARTICLES_MODULE
+ auto e = qobject_cast<QQuick3DParticleEmitter *>(emitter);
+ if (!e || qobject_cast<QQuick3DParticleTrailEmitter *>(e) || !material)
+ return nullptr;
+
+ auto shape = qobject_cast<QQuick3DParticleModelShape *>(e->shape());
+ if (shape && shape->delegate()) {
+ if (auto model = qobject_cast<QQuick3DModel *>(
+ shape->delegate()->create(shape->delegate()->creationContext()))) {
+ QQmlEngine::setObjectOwnership(model, QQmlEngine::JavaScriptOwnership);
+ model->setProperty("_pickTarget", QVariant::fromValue(emitter));
+ QQmlListReference matRef(model, "materials");
+ matRef.append(material);
+ return model;
+ }
+ }
+#endif
+ return nullptr;
+}
+
void GeneralHelper::storeToolState(const QString &sceneId, const QString &tool, const QVariant &state,
int delay)
{
@@ -713,21 +728,6 @@ bool GeneralHelper::isRotationBlocked(QQuick3DNode *node) const
return m_rotationBlockedNodes.contains(node);
}
-bool GeneralHelper::eventFilter(QObject *obj, QEvent *event)
-{
- if (event->type() == QEvent::DynamicPropertyChange) {
- auto node = qobject_cast<QQuick3DNode *>(obj);
- if (m_gizmoTargets.contains(node)) {
- auto de = static_cast<QDynamicPropertyChangeEvent *>(event);
- if (de->propertyName() == "_edit3dLocked")
- emit lockedStateChanged(node);
- else if (de->propertyName() == "_edit3dHidden")
- emit hiddenStateChanged(node);
- }
- }
- return QObject::eventFilter(obj, event);
-}
-
void GeneralHelper::handlePendingToolStateUpdate()
{
m_toolStateUpdateTimer.stop();
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
index 46e6019dd5..ac67172ab3 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/editor3d/generalhelper.h
@@ -41,6 +41,7 @@ QT_BEGIN_NAMESPACE
class QQuick3DCamera;
class QQuick3DNode;
class QQuick3DViewport;
+class QQuick3DMaterial;
class QQuickItem;
QT_END_NAMESPACE
@@ -84,11 +85,11 @@ public:
Q_INVOKABLE QQuick3DPickResult pickViewAt(QQuick3DViewport *view, float posX, float posY);
Q_INVOKABLE QQuick3DNode *resolvePick(QQuick3DNode *pickNode);
- Q_INVOKABLE void registerGizmoTarget(QQuick3DNode *node);
- Q_INVOKABLE void unregisterGizmoTarget(QQuick3DNode *node);
Q_INVOKABLE bool isLocked(QQuick3DNode *node) const;
Q_INVOKABLE bool isHidden(QQuick3DNode *node) const;
Q_INVOKABLE bool isPickable(QQuick3DNode *node) const;
+ Q_INVOKABLE QQuick3DNode *createParticleEmitterGizmoModel(QQuick3DNode *emitter,
+ QQuick3DMaterial *material) const;
Q_INVOKABLE void storeToolState(const QString &sceneId, const QString &tool,
const QVariant &state, int delayEmit = 0);
@@ -123,9 +124,6 @@ signals:
void lockedStateChanged(QQuick3DNode *node);
void rotationBlocksChanged();
-protected:
- bool eventFilter(QObject *obj, QEvent *event) final;
-
private:
void handlePendingToolStateUpdate();
QVector3D pivotScenePosition(QQuick3DNode *node) const;
@@ -136,7 +134,6 @@ private:
QTimer m_toolStateUpdateTimer;
QHash<QString, QVariantMap> m_toolStates;
QHash<QString, QVariantMap> m_toolStatesPending;
- QSet<QQuick3DNode *> m_gizmoTargets;
QSet<QQuick3DNode *> m_rotationBlockedNodes;
struct MultiSelData {
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
index e2bd56562d..9656e0e5e8 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
@@ -113,6 +113,7 @@
#include <QtQuick3DParticles/private/qquick3dparticle_p.h>
#include <QtQuick3DParticles/private/qquick3dparticleaffector_p.h>
#include <QtQuick3DParticles/private/qquick3dparticleemitter_p.h>
+#include <QtQuick3DParticles/private/qquick3dparticletrailemitter_p.h>
#endif
#ifdef IMPORT_QUICK3D_ASSETS
@@ -427,16 +428,25 @@ void Qt5InformationNodeInstanceServer::resetParticleSystem()
void Qt5InformationNodeInstanceServer::handleParticleSystemSelected(QQuick3DParticleSystem* targetParticleSystem)
{
- if (!m_particleAnimationDriver || targetParticleSystem == m_targetParticleSystem)
+ if (targetParticleSystem == m_targetParticleSystem)
return;
- m_particleAnimationDriver->reset();
// stop the previously selected from animating
resetParticleSystem();
m_targetParticleSystem = targetParticleSystem;
+ if (m_editView3DData.rootItem) {
+ QQmlProperty systemProperty(m_editView3DData.rootItem, "activeParticleSystem", context());
+ systemProperty.write(objectToVariant(m_targetParticleSystem));
+ }
+
+ if (!m_particleAnimationDriver)
+ return;
+
+ // Ensure clean slate for newly selected system
resetParticleSystem();
+
#if QT_VERSION >= QT_VERSION_CHECK(6, 2, 2)
QObject::disconnect(m_particleAnimationConnection);
m_particleAnimationConnection = connect(m_particleAnimationDriver, &AnimationDriver::advanced, [this] () {
@@ -507,9 +517,17 @@ static QQuick3DParticleSystem *parentParticleSystem(QObject *selectedObject)
return nullptr;
}
-void Qt5InformationNodeInstanceServer::handleParticleSystemDeselected(QObject *selectedObject)
+void Qt5InformationNodeInstanceServer::handleParticleSystemDeselected()
{
+ resetParticleSystem();
+
m_targetParticleSystem = nullptr;
+
+ if (m_editView3DData.rootItem) {
+ QQmlProperty systemProperty(m_editView3DData.rootItem, "activeParticleSystem", context());
+ systemProperty.write(objectToVariant(nullptr));
+ }
+
const auto anim = animations();
int i = 0;
for (auto a : anim) {
@@ -526,7 +544,7 @@ void Qt5InformationNodeInstanceServer::handleParticleSystemDeselected(QObject *s
void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &objs)
{
#ifdef QUICK3D_PARTICLES_MODULE
- resetParticleSystem();
+ bool skipSystemDeselect = m_targetParticleSystem == nullptr;
#endif
QList<ServerNodeInstance> instanceList;
const QVariantList varObjs = objs.value<QVariantList>();
@@ -535,8 +553,20 @@ void Qt5InformationNodeInstanceServer::handleSelectionChanged(const QVariant &ob
if (obj) {
ServerNodeInstance instance = instanceForObject(obj);
instanceList << instance;
+#ifdef QUICK3D_PARTICLES_MODULE
+ if (!skipSystemDeselect) {
+ auto particleSystem = parentParticleSystem(instance.internalObject());
+ skipSystemDeselect = particleSystem == m_targetParticleSystem;
+ }
+#endif
}
}
+
+#ifdef QUICK3D_PARTICLES_MODULE
+ if (m_targetParticleSystem && !skipSystemDeselect)
+ handleParticleSystemDeselected();
+#endif
+
selectInstances(instanceList);
// Hold selection changes reflected back from designer for a bit
m_selectionChangeTimer.start(500);
@@ -745,6 +775,10 @@ void Qt5InformationNodeInstanceServer::handleNode3DDestroyed(QObject *obj)
} else if (qobject_cast<QQuick3DParticleSystem *>(obj)) {
QMetaObject::invokeMethod(m_editView3DData.rootItem, "releaseParticleSystemGizmo",
Q_ARG(QVariant, objectToVariant(obj)));
+ } else if (qobject_cast<QQuick3DParticleEmitter *>(obj)
+ && !qobject_cast<QQuick3DParticleTrailEmitter *>(obj)) {
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "releaseParticleEmitterGizmo",
+ Q_ARG(QVariant, objectToVariant(obj)));
#endif
}
removeNode3D(obj);
@@ -853,6 +887,11 @@ void Qt5InformationNodeInstanceServer::resolveSceneRoots()
QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateParticleSystemGizmoScene",
Q_ARG(QVariant, objectToVariant(newRoot)),
Q_ARG(QVariant, objectToVariant(node)));
+ } else if (qobject_cast<QQuick3DParticleEmitter *>(node)
+ && !qobject_cast<QQuick3DParticleTrailEmitter *>(node)) {
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "updateParticleEmitterGizmoScene",
+ Q_ARG(QVariant, objectToVariant(newRoot)),
+ Q_ARG(QVariant, objectToVariant(node)));
#endif
}
}
@@ -1415,15 +1454,19 @@ void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos(
QHash<QObject *, QObjectList> cameras;
QHash<QObject *, QObjectList> lights;
QHash<QObject *, QObjectList> particleSystems;
+ QHash<QObject *, QObjectList> particleEmitters;
for (const ServerNodeInstance &instance : instanceList) {
- if (instance.isSubclassOf("QQuick3DCamera"))
+ if (instance.isSubclassOf("QQuick3DCamera")) {
cameras[find3DSceneRoot(instance)] << instance.internalObject();
- else if (instance.isSubclassOf("QQuick3DAbstractLight"))
+ } else if (instance.isSubclassOf("QQuick3DAbstractLight")) {
lights[find3DSceneRoot(instance)] << instance.internalObject();
- else if (instance.isSubclassOf("QQuick3DParticleSystem"))
+ } else if (instance.isSubclassOf("QQuick3DParticleSystem")) {
particleSystems[find3DSceneRoot(instance)] << instance.internalObject();
-
+ } else if (instance.isSubclassOf("QQuick3DParticleEmitter")
+ && !instance.isSubclassOf("QQuick3DParticleTrailEmitter")) {
+ particleEmitters[find3DSceneRoot(instance)] << instance.internalObject();
+ }
}
auto cameraIt = cameras.constBegin();
@@ -1456,6 +1499,17 @@ void Qt5InformationNodeInstanceServer::createCameraAndLightGizmos(
}
++particleIt;
}
+
+ auto emitterIt = particleEmitters.constBegin();
+ while (emitterIt != particleEmitters.constEnd()) {
+ const auto emitterObjs = emitterIt.value();
+ for (auto &obj : emitterObjs) {
+ QMetaObject::invokeMethod(m_editView3DData.rootItem, "addParticleEmitterGizmo",
+ Q_ARG(QVariant, objectToVariant(emitterIt.key())),
+ Q_ARG(QVariant, objectToVariant(obj)));
+ }
+ ++emitterIt;
+ }
}
void Qt5InformationNodeInstanceServer::add3DViewPorts(const QList<ServerNodeInstance> &instanceList)
@@ -1924,6 +1978,9 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
QVariantList selectedObjs;
QObject *firstSceneRoot = nullptr;
ServerNodeInstance firstInstance;
+#ifdef QUICK3D_PARTICLES_MODULE
+ QList<QQuick3DParticleSystem *> selectedParticleSystems;
+#endif
for (qint32 id : instanceIds) {
if (hasInstanceForId(id)) {
ServerNodeInstance instance = instanceForId(id);
@@ -1937,17 +1994,12 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
object = instance.internalObject();
#ifdef QUICK3D_PARTICLES_MODULE
- auto particlesystem = qobject_cast<QQuick3DParticleSystem *>(instance.internalObject());
- if (particlesystem) {
- handleParticleSystemSelected(particlesystem);
- } else {
- particlesystem = parentParticleSystem(instance.internalObject());
- if (particlesystem) {
- if (particlesystem != m_targetParticleSystem)
- handleParticleSystemSelected(particlesystem);
- } else {
- handleParticleSystemDeselected(instance.internalObject());
- }
+ if (selectedParticleSystems.size() <= 1) {
+ auto particleSystem = qobject_cast<QQuick3DParticleSystem *>(instance.internalObject());
+ if (!particleSystem)
+ particleSystem = parentParticleSystem(instance.internalObject());
+ if (particleSystem && !selectedParticleSystems.contains(particleSystem))
+ selectedParticleSystems.append(particleSystem);
}
#endif
auto isSelectableAsRoot = [&]() -> bool {
@@ -1957,6 +2009,8 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
|| qobject_cast<QQuick3DAbstractLight *>(object)
#ifdef QUICK3D_PARTICLES_MODULE
|| qobject_cast<QQuick3DParticleSystem *>(object)
+ || qobject_cast<QQuick3DParticleEmitter *>(object)
+
#endif
) {
return true;
@@ -1978,6 +2032,14 @@ void Qt5InformationNodeInstanceServer::changeSelection(const ChangeSelectionComm
}
}
+#ifdef QUICK3D_PARTICLES_MODULE
+ // We only support exactly one active particle systems at a time
+ if (selectedParticleSystems.size() == 1)
+ handleParticleSystemSelected(selectedParticleSystems[0]);
+ else
+ handleParticleSystemDeselected();
+#endif
+
if (firstSceneRoot && m_active3DScene != firstSceneRoot) {
m_active3DScene = firstSceneRoot;
m_active3DView = findView3DForInstance(firstInstance);
@@ -2105,6 +2167,9 @@ void Qt5InformationNodeInstanceServer::view3DAction(const View3DActionCommand &c
updatedState.insert("showCameraFrustum", command.isEnabled());
break;
#ifdef QUICK3D_PARTICLES_MODULE
+ case View3DActionCommand::ShowParticleEmitter:
+ updatedState.insert("showParticleEmitter", command.isEnabled());
+ break;
case View3DActionCommand::ParticlesPlay:
m_particleAnimationPlaying = command.isEnabled();
updatedState.insert("particlePlay", command.isEnabled());
@@ -2220,8 +2285,12 @@ void Qt5InformationNodeInstanceServer::handleInstanceLocked(const ServerNodeInst
QObject *obj = instance.internalObject();
auto node = qobject_cast<QQuick3DNode *>(obj);
- if (node)
+ if (node) {
node->setProperty("_edit3dLocked", edit3dLocked);
+ auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
+ if (helper)
+ emit helper->lockedStateChanged(node);
+ }
const auto children = obj->children();
for (auto child : children) {
if (hasInstanceForObject(child)) {
@@ -2276,6 +2345,9 @@ void Qt5InformationNodeInstanceServer::handleInstanceHidden(const ServerNodeInst
// as changes in the node tree (reparenting, adding new nodes) can make the previously set
// hide status based on ancestor unreliable.
node->setProperty("_edit3dHidden", edit3dHidden);
+ auto helper = qobject_cast<QmlDesigner::Internal::GeneralHelper *>(m_3dHelper);
+ if (helper)
+ emit helper->hiddenStateChanged(node);
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 1)
if (auto model = qobject_cast<QQuick3DModel *>(node))
model->setPickable(!edit3dHidden); // allow 3D objects to receive mouse clicks
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
index 2f6331e8dd..8f08dec389 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5informationnodeinstanceserver.h
@@ -151,7 +151,7 @@ private:
#ifdef QUICK3D_PARTICLES_MODULE
void handleParticleSystemSelected(QQuick3DParticleSystem* targetParticleSystem);
void resetParticleSystem();
- void handleParticleSystemDeselected(QObject *selectedObject);
+ void handleParticleSystemDeselected();
#endif
RenderViewData m_editView3DData;
diff --git a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.h b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.h
index 6c97658466..799d27054d 100644
--- a/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.h
+++ b/share/qtcreator/qml/qmlpuppet/qml2puppet/instances/qt5previewnodeinstanceserver.h
@@ -49,7 +49,7 @@ protected:
private:
ServerNodeInstance m_currentState;
- QSize m_previewSize{160, 160};
+ QSize m_previewSize{320, 320};
};
} // namespace QmlDesigner
diff --git a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml
index ad4ec007cc..5ac4d0fc6e 100644
--- a/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml
+++ b/share/qtcreator/qmldesigner/itemLibraryQmlSources/Assets.qml
@@ -32,45 +32,67 @@ import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
Item {
- id: rootItem
+ id: root
property var selectedAssets: ({})
property int allExpandedState: 0
property string contextFilePath: ""
property var contextDir: undefined
property bool isDirContextMenu: false
+ property var dropExtFiles: [] // array of supported externally dropped files
function clearSearchFilter()
{
searchBox.text = "";
}
- DropArea {
- id: dropArea
+ function updateDropExtFiles(drag)
+ {
+ root.dropExtFiles = []
+ for (const u of drag.urls) {
+ var url = u.toString();
+ if (url.startsWith("file:///")) // remove file scheme (happens on Windows)
+ url = url.substr(8)
+
+ var ext = url.slice(url.lastIndexOf('.') + 1).toLowerCase()
+ if (rootView.supportedDropSuffixes().includes('*.' + ext))
+ root.dropExtFiles.push(url)
+ }
- property var files // list of supported dropped files
+ drag.accepted = root.dropExtFiles.length > 0
+ }
- enabled: true
- anchors.fill: parent
+ DropArea { // handles external drop on empty area of the view (goes to root folder)
+ id: dropArea
+ y: assetsView.y + assetsView.contentHeight + 5
+ width: parent.width
+ height: parent.height - y
onEntered: (drag)=> {
- files = []
- for (var i = 0; i < drag.urls.length; ++i) {
- var url = drag.urls[i].toString();
- if (url.startsWith("file:///")) // remove file scheme (happens on Windows)
- url = url.substr(8)
- var ext = url.slice(url.lastIndexOf('.') + 1).toLowerCase()
- if (rootView.supportedDropSuffixes().includes('*.' + ext))
- files.push(url)
- }
-
- if (files.length === 0)
- drag.accepted = false;
+ root.updateDropExtFiles(drag)
}
onDropped: {
- if (files.length > 0)
- rootView.handleFilesDrop(files)
+ rootView.handleExtFilesDrop(root.dropExtFiles, assetsModel.rootDir().dirPath)
+ }
+
+ Canvas { // marker for the drop area
+ id: dropCanvas
+ anchors.fill: parent
+ visible: dropArea.containsDrag
+
+ onWidthChanged: dropCanvas.requestPaint()
+ onHeightChanged: dropCanvas.requestPaint()
+
+ onPaint: {
+ var ctx = getContext("2d")
+ ctx.reset()
+ ctx.strokeStyle = StudioTheme.Values.themeInteraction
+ ctx.lineWidth = 2
+ ctx.setLineDash([4, 4])
+ ctx.rect(5, 5, dropCanvas.width - 10, dropCanvas.height - 10)
+ ctx.stroke()
+ }
}
}
@@ -79,9 +101,9 @@ Item {
acceptedButtons: Qt.RightButton
onClicked: {
if (!assetsModel.isEmpty) {
- contextFilePath = ""
- contextDir = assetsModel.rootDir()
- isDirContextMenu = false
+ root.contextFilePath = ""
+ root.contextDir = assetsModel.rootDir()
+ root.isDirContextMenu = false
contextMenu.popup()
}
}
@@ -91,8 +113,8 @@ Item {
function handleViewFocusOut()
{
contextMenu.close()
- selectedAssets = {}
- selectedAssetsChanged()
+ root.selectedAssets = {}
+ root.selectedAssetsChanged()
}
StudioControls.Menu {
@@ -100,42 +122,50 @@ Item {
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: allExpandedState !== 1
- visible: isDirContextMenu
+ enabled: root.allExpandedState !== 1
+ visible: root.isDirContextMenu
height: visible ? implicitHeight : 0
onTriggered: assetsModel.toggleExpandAll(true)
}
StudioControls.MenuItem {
text: qsTr("Collapse All")
- enabled: allExpandedState !== 2
- visible: isDirContextMenu
+ enabled: root.allExpandedState !== 2
+ visible: root.isDirContextMenu
height: visible ? implicitHeight : 0
onTriggered: assetsModel.toggleExpandAll(false)
}
StudioControls.MenuSeparator {
- visible: isDirContextMenu
+ visible: root.isDirContextMenu
height: visible ? StudioTheme.Values.border : 0
}
StudioControls.MenuItem {
+ id: deleteFileItem
text: qsTr("Delete File")
- visible: contextFilePath
- height: visible ? implicitHeight : 0
- onTriggered: assetsModel.deleteFile(contextFilePath)
+ visible: root.contextFilePath
+ height: deleteFileItem.visible ? deleteFileItem.implicitHeight : 0
+ onTriggered: {
+ assetsModel.deleteFiles(Object.keys(root.selectedAssets).filter(p => root.selectedAssets[p]))
+ }
}
StudioControls.MenuSeparator {
- visible: contextFilePath
+ visible: root.contextFilePath
height: visible ? StudioTheme.Values.border : 0
}
StudioControls.MenuItem {
text: qsTr("Rename Folder")
- visible: isDirContextMenu
+ visible: root.isDirContextMenu
height: visible ? implicitHeight : 0
onTriggered: renameFolderDialog.open()
}
@@ -147,14 +177,14 @@ Item {
StudioControls.MenuItem {
text: qsTr("Delete Folder")
- visible: isDirContextMenu
+ visible: root.isDirContextMenu
height: visible ? implicitHeight : 0
onTriggered: {
- var dirEmpty = !(contextDir.dirsModel && contextDir.dirsModel.rowCount() > 0)
- && !(contextDir.filesModel && contextDir.filesModel.rowCount() > 0);
+ var dirEmpty = !(root.contextDir.dirsModel && root.contextDir.dirsModel.rowCount() > 0)
+ && !(root.contextDir.filesModel && root.contextDir.filesModel.rowCount() > 0);
if (dirEmpty)
- assetsModel.deleteFolder(contextDir.dirPath)
+ assetsModel.deleteFolder(root.contextDir.dirPath)
else
confirmDeleteFolderDialog.open()
}
@@ -235,7 +265,7 @@ Item {
text: qsTr("Rename")
enabled: folderRename.text !== ""
onClicked: {
- var success = assetsModel.renameFolder(contextDir.dirPath, folderRename.text)
+ var success = assetsModel.renameFolder(root.contextDir.dirPath, folderRename.text)
if (success)
renameFolderDialog.accept()
@@ -251,7 +281,7 @@ Item {
}
onOpened: {
- folderRename.text = contextDir.dirName
+ folderRename.text = root.contextDir.dirName
folderRename.selectAll()
folderRename.forceActiveFocus()
renameFolderDialog.renameError = false
@@ -309,7 +339,7 @@ Item {
text: qsTr("Create")
enabled: folderName.text !== ""
onClicked: {
- assetsModel.addNewFolder(contextDir.dirPath + '/' + folderName.text)
+ assetsModel.addNewFolder(root.contextDir.dirPath + '/' + folderName.text)
newFolderDialog.accept()
}
}
@@ -345,7 +375,7 @@ Item {
id: folderNotEmpty
text: qsTr("Folder \"%1\" is not empty. Delete it anyway?")
- .arg(contextDir ? contextDir.dirName : "")
+ .arg(root.contextDir ? root.contextDir.dirName : "")
color: StudioTheme.Values.themeTextColor
wrapMode: Text.WordWrap
width: confirmDeleteFolderDialog.width
@@ -373,7 +403,7 @@ Item {
text: qsTr("Delete")
onClicked: {
- assetsModel.deleteFolder(contextDir.dirPath)
+ assetsModel.deleteFolder(root.contextDir.dirPath)
confirmDeleteFolderDialog.accept()
}
}
@@ -433,7 +463,7 @@ Item {
spacing: 20
x: 20
- width: rootItem.width - 2 * x
+ width: root.width - 2 * x
anchors.verticalCenter: parent.verticalCenter
Text {
@@ -492,6 +522,8 @@ Item {
id: dirSection
Section {
+ id: section
+
width: assetsView.width -
(assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0) - 5
caption: dirName
@@ -506,16 +538,31 @@ Item {
visible: dirVisible
expandOnClick: false
useDefaulContextMenu: false
+ dropEnabled: true
onToggleExpand: {
dirExpanded = !dirExpanded
}
+ onDropEnter: (drag)=> {
+ root.updateDropExtFiles(drag)
+ section.highlight = drag.accepted
+ }
+
+ onDropExit: {
+ section.highlight = false
+ }
+
+ onDrop: {
+ section.highlight = false
+ rootView.handleExtFilesDrop(root.dropExtFiles, dirPath)
+ }
+
onShowContextMenu: {
- contextFilePath = ""
- contextDir = model
- isDirContextMenu = true
- allExpandedState = assetsModel.getAllExpandedState()
+ root.contextFilePath = ""
+ root.contextDir = model
+ root.isDirContextMenu = true
+ root.allExpandedState = assetsModel.getAllExpandedState()
contextMenu.popup()
}
@@ -544,9 +591,9 @@ Item {
anchors.fill: parent
acceptedButtons: Qt.RightButton
onClicked: {
- contextFilePath = ""
- contextDir = model
- isDirContextMenu = true
+ root.contextFilePath = ""
+ root.contextDir = model
+ root.isDirContextMenu = true
contextMenu.popup()
}
}
@@ -562,9 +609,10 @@ Item {
width: assetsView.width -
(assetsView.verticalScrollBarVisible ? assetsView.verticalThickness : 0)
height: img.height
- color: selectedAssets[filePath] ? StudioTheme.Values.themeInteraction
- : (mouseArea.containsMouse ? StudioTheme.Values.themeSectionHeadBackground
- : "transparent")
+ color: root.selectedAssets[filePath]
+ ? StudioTheme.Values.themeInteraction
+ : (mouseArea.containsMouse ? StudioTheme.Values.themeSectionHeadBackground
+ : "transparent")
Row {
spacing: 5
@@ -601,28 +649,31 @@ Item {
onPositionChanged: tooltipBackend.reposition()
onPressed: (mouse)=> {
forceActiveFocus()
+ var ctrlDown = mouse.modifiers & Qt.ControlModifier
if (mouse.button === Qt.LeftButton) {
- var ctrlDown = mouse.modifiers & Qt.ControlModifier
- if (!selectedAssets[filePath] && !ctrlDown)
- selectedAssets = {}
- currFileSelected = ctrlDown ? !selectedAssets[filePath] : true
- selectedAssets[filePath] = currFileSelected
- selectedAssetsChanged()
-
- var selectedAssetsArr = []
- for (var assetPath in selectedAssets) {
- if (selectedAssets[assetPath])
- selectedAssetsArr.push(assetPath)
+ 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))
}
-
- if (currFileSelected)
- rootView.startDragAsset(selectedAssetsArr, mapToGlobal(mouse.x, mouse.y))
} else {
- contextFilePath = filePath
- contextDir = model.fileDir
+ 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
tooltipBackend.hideTooltip()
- isDirContextMenu = false
contextMenu.popup()
}
}
@@ -630,9 +681,9 @@ Item {
onReleased: (mouse)=> {
if (mouse.button === Qt.LeftButton) {
if (!(mouse.modifiers & Qt.ControlModifier))
- selectedAssets = {}
- selectedAssets[filePath] = currFileSelected
- selectedAssetsChanged()
+ root.selectedAssets = {}
+ root.selectedAssets[filePath] = currFileSelected
+ root.selectedAssetsChanged()
}
}
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/NewProjectDialog.qml b/share/qtcreator/qmldesigner/newprojectdialog/NewProjectDialog.qml
index 9176af9e34..4cc82bc79c 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/NewProjectDialog.qml
+++ b/share/qtcreator/qmldesigner/newprojectdialog/NewProjectDialog.qml
@@ -32,6 +32,7 @@ import StudioTheme as StudioTheme
import StudioControls as SC
import NewProjectDialog
+import BackendApi
Item {
id: rootDialog
@@ -161,17 +162,43 @@ Item {
readonly property int animDur: 500
id: tabBar
x: 10 // left padding
- width: parent.width - 64 // right padding
- height: DialogValues.projectViewHeaderHeight
+ width: parent.width - 20 // right padding
+ height: DialogValues.presetViewHeaderHeight
color: DialogValues.lightPaneColor
+ function selectTab(tabIndex, selectLast = false) {
+ var item = repeater.itemAt(tabIndex)
+ tabBarRow.currIndex = tabIndex
+
+ presetView.selectLast = selectLast
+ BackendApi.presetModel.setPage(tabIndex) // NOTE: it resets preset model
+ }
+
+ Connections {
+ target: BackendApi
+
+ function onUserPresetSaved() {
+ var customTabIndex = repeater.count - 1
+ tabBar.selectTab(customTabIndex, true)
+ }
+
+ function onLastUserPresetRemoved() {
+ tabBar.selectTab(0, false)
+ }
+ }
+
Row {
id: tabBarRow
spacing: 20
property int currIndex: 0
+ readonly property string currentTabName:
+ repeater.count > 0 && repeater.itemAt(currIndex)
+ ? repeater.itemAt(currIndex).text
+ : ''
Repeater {
- model: categoryModel
+ id: repeater
+ model: BackendApi.categoryModel
Text {
text: name
font.weight: Font.DemiBold
@@ -184,13 +211,7 @@ Item {
MouseArea {
anchors.fill: parent
onClicked: {
- tabBarRow.currIndex = index
- presetModel.setPage(index)
- projectView.currentIndex = 0
- projectView.currentIndexChanged()
-
- strip.x = parent.x
- strip.width = parent.width
+ tabBar.selectTab(index)
}
}
@@ -199,8 +220,19 @@ Item {
} // tabBarRow
Rectangle {
+ function computeX() {
+ var item = tabBarRow.children[tabBarRow.currIndex] ?? tabBarRow.children[0]
+ return item.x;
+ }
+
+ function computeWidth() {
+ var item = tabBarRow.children[tabBarRow.currIndex] ?? tabBarRow.children[0]
+ return item.width;
+ }
+
id: strip
- width: tabBarRow.children[0].width
+ x: computeX()
+ width: computeWidth()
height: 5
radius: 2
color: DialogValues.textColorInteraction
@@ -209,35 +241,40 @@ Item {
Behavior on x { SmoothedAnimation { duration: tabBar.animDur } }
Behavior on width { SmoothedAnimation { duration: strip.width === 0 ? 0 : tabBar.animDur } } // do not animate initial width
}
-
- Connections {
- target: rootDialog
- function onWidthChanged() {
- if (rootDialog.width < 1200) { // 1200 = the width threshold
- tabBar.width = tabBar.parent.width - 20
- projectView.width = projectView.parent.width - 20
- } else {
- tabBar.width = tabBar.parent.width - 64
- projectView.width = projectView.parent.width - 64
- }
- }
- }
} // Rectangle
- NewProjectView {
- id: projectView
+ Rectangle {
+ id: presetViewFrame
x: 10 // left padding
- width: parent.width - 64 // right padding
- height: DialogValues.projectViewHeight
- loader: projectDetailsLoader
-
- Connections {
- target: rootDialog
- function onHeightChanged() {
- if (rootDialog.height < 700) { // 700 = minimum height big dialog
- projectView.height = DialogValues.projectViewHeight / 2
- } else {
- projectView.height = DialogValues.projectViewHeight
+ width: parent.width - 20 // right padding
+ height: DialogValues.presetViewHeight
+ color: DialogValues.darkPaneColor
+
+ Item {
+ anchors.fill: parent
+ anchors.margins: DialogValues.gridMargins
+
+ NewProjectView {
+ id: presetView
+ anchors.fill: parent
+
+ loader: projectDetailsLoader
+ currentTabName: tabBarRow.currentTabName
+
+ Connections {
+ target: rootDialog
+ function onHeightChanged() {
+ if (rootDialog.height < 720) { // 720 = minimum height big dialog
+ DialogValues.presetViewHeight =
+ DialogValues.presetItemHeight
+ + 2 * DialogValues.gridMargins
+ } else {
+ DialogValues.presetViewHeight =
+ DialogValues.presetItemHeight * 2
+ + DialogValues.gridSpacing
+ + 2 * DialogValues.gridMargins
+ }
+ }
}
}
}
@@ -247,12 +284,12 @@ Item {
Text {
id: descriptionText
- text: dialogBox.projectDescription
+ text: BackendApi.projectDescription
font.pixelSize: DialogValues.defaultPixelSize
lineHeight: DialogValues.defaultLineHeight
lineHeightMode: Text.FixedHeight
leftPadding: 14
- width: projectView.width
+ width: presetViewFrame.width
color: DialogValues.textColor
wrapMode: Text.WordWrap
maximumLineCount: 4
@@ -298,7 +335,7 @@ Item {
iconFont: StudioTheme.Constants.font
onClicked: {
- dialogBox.reject();
+ BackendApi.reject();
}
}
@@ -310,11 +347,11 @@ Item {
visible: true
buttonIcon: qsTr("Create")
iconSize: DialogValues.defaultPixelSize
- enabled: dialogBox.fieldsValid
+ enabled: BackendApi.fieldsValid
iconFont: StudioTheme.Constants.font
onClicked: {
- dialogBox.accept();
+ BackendApi.accept();
}
}
} // RowLayout
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic.png
index 389a4eab87..d139d6e026 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic@2x.png
index 3636791da1..03f87cc4b7 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic@2x.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-basic@2x.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-default.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-default.png
index 6c50e4e1fa..ceb573b339 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-default.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-default.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-default@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-default@2x.png
index 09ea1ce94d..dd86707377 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-default@2x.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-default@2x.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion.png
index 745828c1f7..d196646855 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion@2x.png
index c2232f3a75..6bdb9952a4 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion@2x.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-fusion@2x.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine.png
index 40c96993a0..76612e8a8e 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine@2x.png
index c4ef9b7854..34c41c3587 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine@2x.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-imagine@2x.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-macOs@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-macOs@2x.png
deleted file mode 100644
index 09ea1ce94d..0000000000
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-macOs@2x.png
+++ /dev/null
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-macos.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-macos.png
index 6c50e4e1fa..ceb573b339 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-macos.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-macos.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-macos@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-macos@2x.png
new file mode 100644
index 0000000000..dd86707377
--- /dev/null
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-macos@2x.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark.png
index 515f5e0b8e..cf7891232a 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark@2x.png
index 1967a363dc..b353dfa6d9 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark@2x.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_dark@2x.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light.png
index d41b3c5ff8..e826ad0081 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light@2x.png
index 03c1ae6603..2d3c7c53b6 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light@2x.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-material_light@2x.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark.png
index 339342bd91..9a9988e91d 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark@2x.png
index 2ec60f0453..bd778aaa07 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark@2x.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_dark@2x.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light.png
index 7b457bae8f..169581e05d 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light@2x.png
index 22e200c0d7..80239a95a8 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light@2x.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_light@2x.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system.png
index 65fbae504f..08872abd22 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system@2x.png b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system@2x.png
index 5d05168537..5b06ca2987 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system@2x.png
+++ b/share/qtcreator/qmldesigner/newprojectdialog/image/style-universal_system@2x.png
Binary files differ
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml
index d5c37651dc..b348a6da35 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml
+++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml
@@ -31,16 +31,13 @@ import QtQuick.Layouts
import StudioControls as SC
import StudioTheme as StudioTheme
+import BackendApi
+
Item {
width: DialogValues.detailsPaneWidth
- Component.onCompleted: {
- dialogBox.detailsLoaded = true;
- }
-
- Component.onDestruction: {
- dialogBox.detailsLoaded = false;
- }
+ Component.onCompleted: BackendApi.detailsLoaded = true
+ Component.onDestruction: BackendApi.detailsLoaded = false
Rectangle {
color: DialogValues.darkPaneColor
@@ -53,13 +50,13 @@ Item {
Column {
anchors.fill: parent
- spacing: DialogValues.defaultPadding
+ spacing: 5
Text {
id: detailsHeading
text: qsTr("Details")
height: DialogValues.paneTitleTextHeight
- width: parent.width;
+ width: parent.width
font.weight: Font.DemiBold
font.pixelSize: DialogValues.paneTitlePixelSize
lineHeight: DialogValues.paneTitleLineHeight
@@ -71,39 +68,36 @@ Item {
Flickable {
width: parent.width
height: parent.height - detailsHeading.height - DialogValues.defaultPadding
-
+ - savePresetButton.height
contentWidth: parent.width
contentHeight: scrollContent.height
boundsBehavior: Flickable.StopAtBounds
clip: true
- ScrollBar.vertical: SC.VerticalScrollBar {
- }
+ ScrollBar.vertical: SC.VerticalScrollBar {}
Column {
id: scrollContent
width: parent.width - DialogValues.detailsPanePadding
- height: DialogValues.detailsScrollableContentHeight
spacing: DialogValues.defaultPadding
SC.TextField {
id: projectNameTextField
actionIndicatorVisible: false
translationIndicatorVisible: false
- text: dialogBox.projectName
+ text: BackendApi.projectName
width: parent.width
color: DialogValues.textColor
selectByMouse: true
+ font.pixelSize: DialogValues.defaultPixelSize
onEditingFinished: {
text = text.charAt(0).toUpperCase() + text.slice(1)
}
-
- font.pixelSize: DialogValues.defaultPixelSize
}
Binding {
- target: dialogBox
+ target: BackendApi
property: "projectName"
value: projectNameTextField.text
}
@@ -118,14 +112,14 @@ Item {
id: projectLocationTextField
actionIndicatorVisible: false
translationIndicatorVisible: false
- text: dialogBox.projectLocation
+ text: BackendApi.projectLocation
color: DialogValues.textColor
selectByMouse: true
font.pixelSize: DialogValues.defaultPixelSize
}
Binding {
- target: dialogBox
+ target: BackendApi
property: "projectLocation"
value: projectLocationTextField.text
}
@@ -138,7 +132,7 @@ Item {
iconFont: StudioTheme.Constants.font
onClicked: {
- var newLocation = dialogBox.chooseProjectLocation()
+ var newLocation = BackendApi.chooseProjectLocation()
if (newLocation)
projectLocationTextField.text = newLocation
}
@@ -159,7 +153,7 @@ Item {
Text {
id: statusMessage
- text: dialogBox.statusMessage
+ text: BackendApi.statusMessage
font.pixelSize: DialogValues.defaultPixelSize
lineHeight: DialogValues.defaultLineHeight
lineHeightMode: Text.FixedHeight
@@ -172,7 +166,7 @@ Item {
states: [
State {
name: "warning"
- when: dialogBox.statusType === "warning"
+ when: BackendApi.statusType === "warning"
PropertyChanges {
target: statusMessage
color: DialogValues.textWarning
@@ -185,7 +179,7 @@ Item {
State {
name: "error"
- when: dialogBox.statusType === "error"
+ when: BackendApi.statusType === "error"
PropertyChanges {
target: statusMessage
color: DialogValues.textError
@@ -208,7 +202,7 @@ Item {
}
Binding {
- target: dialogBox
+ target: BackendApi
property: "saveAsDefaultLocation"
value: defaultLocationCheckbox.checked
}
@@ -219,25 +213,25 @@ Item {
id: screenSizeComboBox
actionIndicatorVisible: false
currentIndex: -1
- model: screenSizeModel
+ model: BackendApi.screenSizeModel
textRole: "display"
width: parent.width
font.pixelSize: DialogValues.defaultPixelSize
onActivated: (index) => {
- dialogBox.setScreenSizeIndex(index);
+ BackendApi.setScreenSizeIndex(index);
- var size = screenSizeModel.screenSizes(index);
+ var size = BackendApi.screenSizeModel.screenSizes(index);
widthField.realValue = size.width;
heightField.realValue = size.height;
}
Connections {
- target: screenSizeModel
+ target: BackendApi.screenSizeModel
function onModelReset() {
var newIndex = screenSizeComboBox.currentIndex > -1
? screenSizeComboBox.currentIndex
- : dialogBox.screenSizeIndex()
+ : BackendApi.screenSizeIndex()
screenSizeComboBox.currentIndex = newIndex
screenSizeComboBox.activated(newIndex)
@@ -248,10 +242,8 @@ Item {
GridLayout { // orientation + width + height
width: parent.width
height: 85
-
columns: 4
rows: 2
-
columnSpacing: 10
rowSpacing: 10
@@ -295,10 +287,7 @@ Item {
font.pixelSize: DialogValues.defaultPixelSize
onRealValueChanged: {
- var height = heightField.realValue
- var width = realValue
-
- if (width >= height)
+ if (widthField.realValue >= heightField.realValue)
orientationButton.setHorizontal()
else
orientationButton.setVertical()
@@ -306,7 +295,7 @@ Item {
} // Width Text Field
Binding {
- target: dialogBox
+ target: BackendApi
property: "customWidth"
value: widthField.realValue
}
@@ -323,10 +312,7 @@ Item {
font.pixelSize: DialogValues.defaultPixelSize
onRealValueChanged: {
- var height = realValue
- var width = widthField.realValue
-
- if (width >= height)
+ if (widthField.realValue >= heightField.realValue)
orientationButton.setHorizontal()
else
orientationButton.setVertical()
@@ -334,7 +320,7 @@ Item {
} // Height Text Field
Binding {
- target: dialogBox
+ target: BackendApi
property: "customHeight"
value: heightField.realValue
}
@@ -345,7 +331,6 @@ Item {
id: orientationButton
implicitWidth: 100
implicitHeight: 50
-
checked: false
hoverEnabled: false
background: Rectangle {
@@ -384,19 +369,22 @@ Item {
onClicked: {
if (widthField.realValue && heightField.realValue) {
- [widthField.realValue, heightField.realValue] = [heightField.realValue, widthField.realValue];
- checked = !checked
+ [widthField.realValue, heightField.realValue] = [heightField.realValue, widthField.realValue]
+ orientationButton.checked = !orientationButton.checked
+
+ if (widthField.realValue === heightField.realValue)
+ orientationButton.checked ? setVertical() : setHorizontal()
}
}
function setHorizontal() {
- checked = false
+ orientationButton.checked = false
horizontalBar.color = DialogValues.textColorInteraction
verticalBar.color = "white"
}
function setVertical() {
- checked = true
+ orientationButton.checked = true
horizontalBar.color = "white"
verticalBar.color = DialogValues.textColorInteraction
}
@@ -404,23 +392,27 @@ Item {
} // GridLayout: orientation + width + height
- Rectangle { width: parent.width; height: 1; color: DialogValues.dividerlineColor }
+ Rectangle {
+ width: parent.width
+ height: 1
+ color: DialogValues.dividerlineColor
+ }
SC.CheckBox {
id: useQtVirtualKeyboard
actionIndicatorVisible: false
text: qsTr("Use Qt Virtual Keyboard")
font.pixelSize: DialogValues.defaultPixelSize
- checked: dialogBox.useVirtualKeyboard
- visible: dialogBox.haveVirtualKeyboard
+ checked: BackendApi.useVirtualKeyboard
+ visible: BackendApi.haveVirtualKeyboard
}
RowLayout { // Target Qt Version
width: parent.width
- visible: dialogBox.haveTargetQtVersion
+ visible: BackendApi.haveTargetQtVersion
Text {
- text: "Target Qt Version:"
+ text: qsTr("Target Qt Version:")
font.pixelSize: DialogValues.defaultPixelSize
lineHeight: DialogValues.defaultLineHeight
lineHeightMode: Text.FixedHeight
@@ -432,33 +424,98 @@ Item {
actionIndicatorVisible: false
implicitWidth: 70
Layout.alignment: Qt.AlignRight
- currentIndex: 1
+ currentIndex: BackendApi.targetQtVersionIndex
font.pixelSize: DialogValues.defaultPixelSize
model: ListModel {
- ListElement {
- name: "Qt 5"
- }
- ListElement {
- name: "Qt 6"
- }
+ ListElement { name: "Qt 5" }
+ ListElement { name: "Qt 6" }
}
onActivated: (index) => {
- dialogBox.setTargetQtVersion(index)
+ BackendApi.targetQtVersionIndex = index
}
} // Target Qt Version ComboBox
+
+ Binding {
+ target: BackendApi
+ property: "targetQtVersionIndex"
+ value: qtVersionComboBox.currentIndex
+ }
+
} // RowLayout
Binding {
- target: dialogBox
+ target: BackendApi
property: "useVirtualKeyboard"
value: useQtVirtualKeyboard.checked
}
} // ScrollContent Column
} // ScrollView
-
} // Column
+
+ SC.AbstractButton {
+ id: savePresetButton
+ width: StudioTheme.Values.singleControlColumnWidth
+ buttonIcon: qsTr("Save Custom Preset")
+ iconFont: StudioTheme.Constants.font
+ iconSize: DialogValues.defaultPixelSize
+ anchors.bottom: parent.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ onClicked: savePresetDialog.open()
+ }
+
+ PopupDialog {
+ id: savePresetDialog
+ title: qsTr("Save Preset")
+ standardButtons: Dialog.Save | Dialog.Cancel
+ modal: true
+ closePolicy: Popup.CloseOnEscape
+ anchors.centerIn: parent
+ width: DialogValues.popupDialogWidth
+
+ onAccepted: BackendApi.savePresetDialogAccept()
+
+ onOpened: {
+ presetNameTextField.selectAll()
+ presetNameTextField.forceActiveFocus()
+ }
+
+ ColumnLayout {
+ width: parent.width
+ spacing: 10
+
+ Text {
+ text: qsTr("Preset name")
+ font.pixelSize: DialogValues.defaultPixelSize
+ color: DialogValues.textColor
+ }
+
+ SC.TextField {
+ id: presetNameTextField
+ actionIndicatorVisible: false
+ translationIndicatorVisible: false
+ text: qsTr("MyPreset")
+ color: DialogValues.textColor
+ font.pixelSize: DialogValues.defaultPixelSize
+ Layout.fillWidth: true
+ maximumLength: 30
+ validator: RegularExpressionValidator { regularExpression: /\w[\w ]*/ }
+
+ onEditingFinished: {
+ presetNameTextField.text = text.trim()
+ presetNameTextField.text = text.replace(/\s+/g, " ")
+ }
+ }
+
+ Binding {
+ target: BackendApi
+ property: "presetName"
+ value: presetNameTextField.text
+ }
+ }
+ }
} // Item
- }
-}
+ } // Rectangle
+} // root Item
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/DialogValues.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/DialogValues.qml
index ae26727e07..d85093738d 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/DialogValues.qml
+++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/DialogValues.qml
@@ -29,39 +29,57 @@ import QtQml
import StudioTheme as StudioTheme
QtObject {
+ id: root
+
readonly property int dialogWidth: 1522
readonly property int dialogHeight: 940
- readonly property int projectViewMinimumWidth: 600
- readonly property int projectViewMinimumHeight: projectViewHeight
- readonly property int dialogContentHeight: projectViewHeight + 300 // i.e. dialog without header and footer
- readonly property int loadedPanesWidth: detailsPaneWidth + stylesPaneWidth
- readonly property int detailsPaneWidth: 330 + detailsPanePadding * 2
+ readonly property int presetViewMinimumWidth: 600
+ readonly property int presetViewMinimumHeight: root.gridCellHeight
+ readonly property int dialogContentHeight: root.presetViewHeight + 300 // i.e. dialog without header and footer
+ readonly property int loadedPanesWidth: root.detailsPaneWidth + root.stylesPaneWidth
+ readonly property int detailsPaneWidth: 330 + root.detailsPanePadding * 2
readonly property int dialogTitleTextHeight: 85
readonly property int paneTitleTextHeight: 47
readonly property int logoWidth: 85
readonly property int logoHeight: 85
- /* detailsScrollableContentHeight - the full height that may need to be scrolled to be fully
- visible, if the dialog box is too small. */
- readonly property int detailsScrollableContentHeight: 428
- readonly property int stylesPaneWidth: styleImageWidth + stylesPanePadding * 2 + styleImageBorderWidth * 2 // i.e. 240px
+ readonly property int stylesPaneWidth: root.styleImageWidth + root.stylesPanePadding * 2
+ + root.styleImageBorderWidth * 2 // i.e. 240px
readonly property int detailsPanePadding: 18
readonly property int stylesPanePadding: 18
readonly property int defaultPadding: 18
readonly property int dialogLeftPadding: 35
+ readonly property int styleListItemHeight: root.styleImageHeight + root.styleTextHeight
+ + 2 * root.styleImageBorderWidth
+ + root.styleListItemBottomMargin
+ + root.styleListItemSpacing
+ readonly property int styleListItemBottomMargin: 10
+ readonly property int styleListItemSpacing: 4
readonly property int styleImageWidth: 200
+ readonly property int styleImageHeight: 262
readonly property int styleImageBorderWidth: 2
+ readonly property int styleTextHeight: 18
+
readonly property int footerHeight: 73
- readonly property int projectItemWidth: 90
- readonly property int projectItemHeight: 144
- readonly property int projectViewHeight: projectItemHeight * 2
- readonly property int projectViewHeaderHeight: 38
+ readonly property int presetItemWidth: 136
+ readonly property int presetItemHeight: 110
+ property int presetViewHeight: root.presetItemHeight * 2 + root.gridSpacing + root.gridMargins * 2
+ readonly property int presetViewHeaderHeight: 38
+
+ readonly property int gridMargins: 20
+ readonly property int gridCellWidth: root.presetItemWidth + root.gridSpacing
+ readonly property int gridCellHeight: root.presetItemHeight + root.gridSpacing
+ readonly property int gridSpacing: 2
readonly property int dialogButtonWidth: 100
- readonly property int loadedPanesHeight: dialogContentHeight
- readonly property int detailsPaneHeight: dialogContentHeight
+ // This is for internal popup dialogs
+ readonly property int popupDialogWidth: 270
+ readonly property int popupDialogPadding: 12
+
+ readonly property int loadedPanesHeight: root.dialogContentHeight
+ readonly property int detailsPaneHeight: root.dialogContentHeight
readonly property string darkPaneColor: StudioTheme.Values.themeBackgroundColorNormal
readonly property string lightPaneColor: StudioTheme.Values.themeBackgroundColorAlternate
@@ -71,6 +89,8 @@ QtObject {
readonly property string dividerlineColor: StudioTheme.Values.themeTextColorDisabled
readonly property string textError: StudioTheme.Values.themeError
readonly property string textWarning: StudioTheme.Values.themeWarning
+ readonly property string presetItemBackgroundHover: StudioTheme.Values.themeControlBackgroundGlobalHover
+ readonly property string presetItemBackgroundHoverInteraction: StudioTheme.Values.themeControlBackgroundInteraction
readonly property real defaultPixelSize: 14
readonly property real defaultLineHeight: 21
@@ -91,6 +111,6 @@ QtObject {
item and spacing after it). So we have to subtract 2 x layout spacing before setting
our own, narrower, spacing.
*/
- return -layoutSpacing -layoutSpacing + value
+ return -layoutSpacing - layoutSpacing + value
}
}
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/NewProjectView.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/NewProjectView.qml
index e011057892..e8bb58cfa7 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/NewProjectView.qml
+++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/NewProjectView.qml
@@ -28,111 +28,252 @@ import QtQuick.Controls
import QtQuick
import QtQuick.Layouts
+import StudioControls as SC
import StudioTheme as StudioTheme
-GridView {
- id: projectView
+import BackendApi
+
+ScrollView {
+ id: scrollView
required property Item loader
+ required property string currentTabName
- cellWidth: DialogValues.projectItemWidth
- cellHeight: DialogValues.projectItemHeight
- clip: true
+ property string backgroundHoverColor: DialogValues.presetItemBackgroundHover
- boundsBehavior: Flickable.StopAtBounds
+ // selectLast: if true, it will select last item in the model after a model reset.
+ property bool selectLast: false
- children: [
- Rectangle {
- color: DialogValues.darkPaneColor
- anchors.fill: parent
- z: -1
- }
- ]
+ ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
+ ScrollBar.vertical: SC.VerticalScrollBar {
+ parent: scrollView
+ x: scrollView.width + (DialogValues.gridMargins
+ - StudioTheme.Values.scrollBarThickness) * 0.5
+ y: scrollView.topPadding
+ height: scrollView.availableHeight
+ }
- model: presetModel
+ contentWidth: gridView.contentItem.childrenRect.width
+ contentHeight: gridView.contentItem.childrenRect.height
- // called by onModelReset and when user clicks on an item, or when the header item is changed.
- onCurrentIndexChanged: {
- dialogBox.selectedPreset = projectView.currentIndex
- var source = dialogBox.currentPresetQmlPath()
- loader.source = source
- }
+ GridView {
+ id: gridView
- Connections {
- target: presetModel
+ clip: true
+ anchors.fill: parent
+ cellWidth: DialogValues.gridCellWidth
+ cellHeight: DialogValues.gridCellHeight
+ rightMargin: -DialogValues.gridSpacing
+ bottomMargin: -DialogValues.gridSpacing
+ boundsBehavior: Flickable.StopAtBounds
+ model: BackendApi.presetModel
- // called when data is set (setWizardFactories)
- function onModelReset() {
- currentIndex = 0
- currentIndexChanged()
+ // called by onModelReset and when user clicks on an item, or when the header item is changed.
+ onCurrentIndexChanged: {
+ BackendApi.selectedPreset = gridView.currentIndex
+ var source = BackendApi.currentPresetQmlPath()
+ scrollView.loader.source = source
}
- }
- delegate: ItemDelegate {
- id: delegate
+ Connections {
+ target: BackendApi.presetModel
- width: DialogValues.projectItemWidth
- height: DialogValues.projectItemHeight
- background: null
+ // called when data is set (setWizardFactories)
+ function onModelReset() {
+ if (scrollView.selectLast) {
+ gridView.currentIndex = BackendApi.presetModel.rowCount() - 1
+ scrollView.selectLast = false
+ } else {
+ gridView.currentIndex = 0
+ }
- function fontIconCode(index) {
- var code = presetModel.fontIconCode(index)
- return code ? code : StudioTheme.Constants.wizardsUnknown
+ // This will load Details.qml and Styles.qml by setting "source" on the Loader.
+ gridView.currentIndexChanged()
+ }
}
- Column {
- width: parent.width
- height: parent.height
+ delegate: ItemDelegate {
+ id: delegate
- Label {
- id: projectTypeIcon
- text: fontIconCode(index)
- color: DialogValues.textColor
+ property bool hover: delegate.hovered || removeMouseArea.containsMouse
+
+ width: DialogValues.presetItemWidth
+ height: DialogValues.presetItemHeight
+
+ onClicked: delegate.GridView.view.currentIndex = index
+
+ background: Rectangle {
+ id: delegateBackground
width: parent.width
- height: DialogValues.projectItemHeight / 2
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignBottom
- renderType: Text.NativeRendering
- font.pixelSize: 65
- font.family: StudioTheme.Constants.iconFont.family
+ height: parent.height
+ color: delegate.hover ? scrollView.backgroundHoverColor : "transparent"
+ border.color: delegate.hover ? presetName.color : "transparent"
+ }
+
+ function fontIconCode(index) {
+ var code = BackendApi.presetModel.fontIconCode(index)
+ return code ? code : StudioTheme.Constants.wizardsUnknown
}
+ contentItem: Item {
+ anchors.fill: parent
+
+ ColumnLayout {
+ spacing: 0
+ anchors.top: parent.top
+ anchors.topMargin: -1
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ Label {
+ id: presetIcon
+ text: delegate.fontIconCode(index)
+ color: DialogValues.textColor
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignBottom
+ renderType: Text.NativeRendering
+ font.pixelSize: 65
+ font.family: StudioTheme.Constants.iconFont.family
+ Layout.alignment: Qt.AlignHCenter
+ } // Preset type icon Label
+
+ Text {
+ id: presetName
+ color: DialogValues.textColor
+ text: name
+ font.pixelSize: DialogValues.defaultPixelSize
+ lineHeight: DialogValues.defaultLineHeight
+ lineHeightMode: Text.FixedHeight
+ width: DialogValues.presetItemWidth - 16
+ elide: Text.ElideRight
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignTop
+ Layout.alignment: Qt.AlignHCenter
+ Layout.preferredWidth: presetName.width
+ Layout.minimumWidth: presetName.width
+ Layout.maximumWidth: presetName.width
+
+ ToolTip {
+ id: toolTip
+ y: -toolTip.height
+ visible: delegate.hovered && presetName.truncated
+ text: name
+ delay: 1000
+ height: 20
+
+ background: Rectangle {
+ color: StudioTheme.Values.themeToolTipBackground
+ border.color: StudioTheme.Values.themeToolTipOutline
+ border.width: StudioTheme.Values.border
+ }
+
+ contentItem: Text {
+ color: StudioTheme.Values.themeToolTipText
+ text: toolTip.text
+ font.pixelSize: DialogValues.defaultPixelSize
+ verticalAlignment: Text.AlignVCenter
+ }
+ }
+ }
+
+ Text {
+ id: presetResolution
+ color: DialogValues.textColor
+ text: resolution
+ font.pixelSize: DialogValues.defaultPixelSize
+ lineHeight: DialogValues.defaultLineHeight
+ lineHeightMode: Text.FixedHeight
+ wrapMode: Text.Wrap
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignTop
+ Layout.alignment: Qt.AlignHCenter
+ }
+
+ } // ColumnLayout
+
+ Item {
+ id: removePresetButton
+ width: 20
+ height: 20
+ anchors.top: parent.top
+ anchors.right: parent.right
+ anchors.margins: 4
+ visible: isUserPreset === true
+ && delegate.hover
+ && scrollView.currentTabName !== BackendApi.recentsTabName()
+
+ Text {
+ anchors.fill: parent
+ text: StudioTheme.Constants.closeCross
+ color: DialogValues.textColor
+ horizontalAlignment: Qt.AlignHCenter
+ verticalAlignment: Qt.AlignVCenter
+ font.family: StudioTheme.Constants.iconFont.family
+ font.pixelSize: StudioTheme.Values.myIconFontSize
+ }
+
+ MouseArea {
+ id: removeMouseArea
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: removeMouseArea.containsMouse ? Qt.PointingHandCursor
+ : Qt.ArrowCursor
+
+ onClicked: {
+ removePresetDialog.presetName = presetName.text
+ removePresetDialog.open()
+ }
+ }
+ } // Delete preset button Item
+ } // Item
+
+ states: [
+ State {
+ name: "current"
+ when: delegate.GridView.isCurrentItem
+
+ PropertyChanges {
+ target: presetName
+ color: DialogValues.textColorInteraction
+ }
+ PropertyChanges {
+ target: presetResolution
+ color: DialogValues.textColorInteraction
+ }
+ PropertyChanges {
+ target: presetIcon
+ color: DialogValues.textColorInteraction
+ }
+ PropertyChanges {
+ target: scrollView
+ backgroundHoverColor: DialogValues.presetItemBackgroundHoverInteraction
+ }
+ } // State
+ ]
+ } // ItemDelegate
+
+ PopupDialog {
+ id: removePresetDialog
+
+ property string presetName
+
+ title: qsTr("Delete Custom Preset")
+ standardButtons: Dialog.Yes | Dialog.No
+ modal: true
+ closePolicy: Popup.CloseOnEscape
+ anchors.centerIn: parent
+ width: DialogValues.popupDialogWidth
+
+ onAccepted: BackendApi.removeCurrentPreset()
+
Text {
- id: projectTypeLabel
+ text: qsTr("Are you sure you want to delete \"" + removePresetDialog.presetName + "\" ?")
color: DialogValues.textColor
-
- text: name
font.pixelSize: DialogValues.defaultPixelSize
- lineHeight: DialogValues.defaultLineHeight
- lineHeightMode: Text.FixedHeight
- width: parent.width
- height: DialogValues.projectItemHeight / 2
- wrapMode: Text.Wrap
- horizontalAlignment: Text.AlignHCenter
- verticalAlignment: Text.AlignTop
- }
- } // Column
+ wrapMode: Text.WordWrap
- MouseArea {
- anchors.fill: parent
- onClicked: {
- delegate.GridView.view.currentIndex = index
+ width: DialogValues.popupDialogWidth - 2 * DialogValues.popupDialogPadding
}
- }
-
- states: [
- State {
- when: delegate.GridView.isCurrentItem
- PropertyChanges {
- target: projectTypeLabel
- color: DialogValues.textColorInteraction
- }
- PropertyChanges {
- target: projectTypeIcon
- color: DialogValues.textColorInteraction
- }
- } // State
- ]
- } // ItemDelegate
-} // GridView
+ } // Dialog
+ } // GridView
+} // ScrollView
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/PopupDialog.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/PopupDialog.qml
new file mode 100644
index 0000000000..2c6b308461
--- /dev/null
+++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/PopupDialog.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** 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 StudioTheme as StudioTheme
+
+import BackendApi
+
+Dialog {
+ id: root
+ padding: DialogValues.popupDialogPadding
+
+ background: Rectangle {
+ color: DialogValues.darkPaneColor
+ border.color: StudioTheme.Values.themeInteraction
+ border.width: StudioTheme.Values.border
+ }
+
+ header: Label {
+ text: root.title
+ visible: root.title
+ elide: Label.ElideRight
+ font.bold: true
+ font.pixelSize: DialogValues.defaultPixelSize
+ padding: DialogValues.popupDialogPadding
+ color: DialogValues.textColor
+ horizontalAlignment: Text.AlignHCenter
+
+ background: Rectangle {
+ x: 1
+ y: 1
+ width: parent.width - 2
+ height: parent.height - 1
+ color: DialogValues.darkPaneColor
+ }
+ }
+
+ footer: PopupDialogButtonBox {
+ visible: count > 0
+ }
+}
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/PopupDialogButton.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/PopupDialogButton.qml
new file mode 100644
index 0000000000..ee64eb9078
--- /dev/null
+++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/PopupDialogButton.qml
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** 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 StudioTheme as StudioTheme
+
+Button {
+ id: root
+
+ implicitWidth: Math.max(
+ background ? background.implicitWidth : 0,
+ textItem.implicitWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(
+ background ? background.implicitHeight : 0,
+ textItem.implicitHeight + topPadding + bottomPadding)
+ leftPadding: 4
+ rightPadding: 4
+
+ background: Rectangle {
+ id: background
+ implicitWidth: 80
+ implicitHeight: StudioTheme.Values.height
+ color: StudioTheme.Values.themeControlBackground
+ border.color: StudioTheme.Values.themeControlOutline
+ anchors.fill: parent
+ }
+
+ contentItem: Text {
+ id: textItem
+ text: root.text
+ font.family: StudioTheme.Constants.font.family
+ font.pixelSize: DialogValues.defaultPixelSize
+ color: StudioTheme.Values.themeTextColor
+ horizontalAlignment: Text.AlignHCenter
+ verticalAlignment: Text.AlignVCenter
+ renderType: Text.QtRendering
+ anchors.fill: parent
+ }
+
+ states: [
+ State {
+ name: "default"
+ when: !root.hovered && !root.checked && !root.pressed
+
+ PropertyChanges {
+ target: background
+ color: StudioTheme.Values.themeControlBackground
+ border.color: StudioTheme.Values.themeControlOutline
+ }
+ PropertyChanges {
+ target: textItem
+ color: StudioTheme.Values.themeTextColor
+ }
+ },
+ State {
+ name: "hover"
+ when: root.hovered && !root.checked && !root.pressed
+
+ PropertyChanges {
+ target: background
+ color: StudioTheme.Values.themeControlBackgroundHover
+ border.color: StudioTheme.Values.themeControlOutline
+ }
+ PropertyChanges {
+ target: textItem
+ color: StudioTheme.Values.themeTextColor
+ }
+ },
+ State {
+ name: "press"
+ when: root.hovered && root.pressed
+
+ PropertyChanges {
+ target: background
+ color: StudioTheme.Values.themeInteraction
+ border.color: StudioTheme.Values.themeInteraction
+ }
+ PropertyChanges {
+ target: textItem
+ color: StudioTheme.Values.themeIconColor
+ }
+ }
+ ]
+}
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/PopupDialogButtonBox.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/PopupDialogButtonBox.qml
new file mode 100644
index 0000000000..d4d867f862
--- /dev/null
+++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/PopupDialogButtonBox.qml
@@ -0,0 +1,46 @@
+/****************************************************************************
+**
+** 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
+
+DialogButtonBox {
+ id: root
+ padding: DialogValues.popupDialogPadding
+ alignment: Qt.AlignRight | Qt.AlignBottom
+
+ background: Rectangle {
+ implicitHeight: 40
+ x: 1
+ y: 1
+ width: parent.width - 2
+ height: parent.height - 2
+ color: DialogValues.darkPaneColor
+ }
+
+ delegate: PopupDialogButton {
+ width: root.count === 1 ? root.availableWidth / 2 : undefined
+ }
+}
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml
index e6955bb21b..72be983e33 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml
+++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Styles.qml
@@ -23,20 +23,21 @@
**
****************************************************************************/
+import QtQuick
import QtQuick.Window
import QtQuick.Controls
-
-import QtQuick
import QtQuick.Layouts
import StudioControls as SC
import StudioTheme as StudioTheme
+import BackendApi
+
Item {
width: DialogValues.stylesPaneWidth
Component.onCompleted: {
- dialogBox.stylesLoaded = true;
+ BackendApi.stylesLoaded = true
/*
* TODO: roleNames is called before the backend model (in the proxy class StyleModel) is
@@ -47,7 +48,7 @@ Item {
}
Component.onDestruction: {
- dialogBox.stylesLoaded = false;
+ BackendApi.stylesLoaded = false
}
Rectangle {
@@ -57,116 +58,120 @@ Item {
Item {
x: DialogValues.stylesPanePadding
- width: parent.width - DialogValues.stylesPanePadding * 2 + styleScrollBar.width
+ width: parent.width - DialogValues.stylesPanePadding * 2
height: parent.height
- ColumnLayout {
- anchors.fill: parent
- spacing: 5
-
- Text {
- id: styleTitleText
- text: qsTr("Style")
- Layout.minimumHeight: DialogValues.paneTitleTextHeight
- font.weight: Font.DemiBold
- font.pixelSize: DialogValues.paneTitlePixelSize
- lineHeight: DialogValues.paneTitleLineHeight
- lineHeightMode: Text.FixedHeight
- color: DialogValues.textColor
- verticalAlignment: Qt.AlignVCenter
-
- function refresh() {
- text = qsTr("Style") + " (" + styleModel.rowCount() + ")"
- }
+ Text {
+ id: styleTitleText
+ text: qsTr("Style")
+ height: DialogValues.paneTitleTextHeight
+ width: parent.width
+ font.weight: Font.DemiBold
+ font.pixelSize: DialogValues.paneTitlePixelSize
+ lineHeight: DialogValues.paneTitleLineHeight
+ lineHeightMode: Text.FixedHeight
+ color: DialogValues.textColor
+ verticalAlignment: Qt.AlignVCenter
+ anchors.top: parent.top
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ function refresh() {
+ styleTitleText.text = qsTr("Style") + " (" + BackendApi.styleModel.rowCount() + ")"
+ }
+ }
+
+ SC.ComboBox { // Style Filter ComboBox
+ id: styleComboBox
+ actionIndicatorVisible: false
+ currentIndex: 0
+ textRole: "text"
+ valueRole: "value"
+ font.pixelSize: DialogValues.defaultPixelSize
+ width: parent.width
+
+ anchors.top: styleTitleText.bottom
+ anchors.topMargin: 5
+
+ model: ListModel {
+ ListElement { text: qsTr("All"); value: "all" }
+ ListElement { text: qsTr("Light"); value: "light" }
+ ListElement { text: qsTr("Dark"); value: "dark" }
}
- SC.ComboBox { // Style Filter ComboBox
- actionIndicatorVisible: false
- currentIndex: 0
- textRole: "text"
- valueRole: "value"
- font.pixelSize: DialogValues.defaultPixelSize
-
- model: ListModel {
- ListElement { text: qsTr("All"); value: "all" }
- ListElement { text: qsTr("Light"); value: "light" }
- ListElement { text: qsTr("Dark"); value: "dark" }
- }
-
- implicitWidth: parent.width
-
- onActivated: (index) => {
- styleModel.filter(currentValue.toLowerCase());
- styleTitleText.refresh();
- }
- } // Style Filter ComboBox
-
- Item { implicitWidth: 1; implicitHeight: 9 }
+ onActivated: (index) => {
+ BackendApi.styleModel.filter(currentValue.toLowerCase())
+ styleTitleText.refresh()
+ }
+ } // Style Filter ComboBox
+
+ ScrollView {
+ id: scrollView
+
+ anchors.top: styleComboBox.bottom
+ anchors.topMargin: 11
+ anchors.bottom: parent.bottom
+ anchors.bottomMargin: DialogValues.stylesPanePadding
+ width: parent.width
+
+ ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
+ ScrollBar.vertical: SC.VerticalScrollBar {
+ id: styleScrollBar
+ x: stylesList.width + (DialogValues.stylesPanePadding
+ - StudioTheme.Values.scrollBarThickness) * 0.5
+ }
ListView {
id: stylesList
- Layout.fillWidth: true
- Layout.fillHeight: true
- clip: true
- model: styleModel
-
- MouseArea {
- id: listViewMouseArea
- anchors.fill: parent
- hoverEnabled: true
- propagateComposedEvents: true
- }
-
+ anchors.fill: parent
focus: true
+ clip: true
+ model: BackendApi.styleModel
boundsBehavior: Flickable.StopAtBounds
-
highlightFollowsCurrentItem: false
-
- ScrollBar.vertical: SC.VerticalScrollBar {
- id: styleScrollBar
- property int extraPadding: 0
- bottomInset: extraPadding
- bottomPadding: bottomInset + 16
- viewMouseArea: listViewMouseArea
- } // ScrollBar
+ bottomMargin: -DialogValues.styleListItemBottomMargin
onCurrentIndexChanged: {
- if (styleModel.rowCount() > 0)
- dialogBox.styleIndex = stylesList.currentIndex;
+ if (BackendApi.styleModel.rowCount() > 0)
+ BackendApi.styleIndex = stylesList.currentIndex
}
delegate: ItemDelegate {
id: delegateId
- height: styleImage.height + DialogValues.styleImageBorderWidth + styleText.height + extraPadding.height + 1
- width: stylesList.width - styleScrollBar.width
+ width: stylesList.width
+ height: DialogValues.styleListItemHeight
- Component.onCompleted: {
- styleScrollBar.extraPadding = styleText.height + extraPadding.height
- }
+ onClicked: stylesList.currentIndex = index
- Rectangle {
+ background: Rectangle {
anchors.fill: parent
color: DialogValues.lightPaneColor
+ }
+
+ contentItem: Item {
+ anchors.fill: parent
Column {
- spacing: 0
anchors.fill: parent
+ spacing: DialogValues.styleListItemSpacing
Rectangle {
- border.color: index == stylesList.currentIndex ? DialogValues.textColorInteraction : "transparent"
- border.width: index == stylesList.currentIndex ? DialogValues.styleImageBorderWidth : 0
+ width: DialogValues.styleImageWidth
+ + 2 * DialogValues.styleImageBorderWidth
+ height: DialogValues.styleImageHeight
+ + 2 * DialogValues.styleImageBorderWidth
+ border.color: index === stylesList.currentIndex ? DialogValues.textColorInteraction : "transparent"
+ border.width: index === stylesList.currentIndex ? DialogValues.styleImageBorderWidth : 0
color: "transparent"
- width: parent.width
- height: parent.height - styleText.height - extraPadding.height
Image {
id: styleImage
- asynchronous: false
- source: "image://newprojectdialog_library/" + styleModel.iconId(model.index)
- width: 200
- height: 262
x: DialogValues.styleImageBorderWidth
y: DialogValues.styleImageBorderWidth
+ width: DialogValues.styleImageWidth
+ height: DialogValues.styleImageHeight
+ asynchronous: false
+ source: "image://newprojectdialog_library/" + BackendApi.styleModel.iconId(model.index)
}
} // Rectangle
@@ -175,35 +180,26 @@ Item {
text: model.display
font.pixelSize: DialogValues.defaultPixelSize
lineHeight: DialogValues.defaultLineHeight
- height: 18
+ height: DialogValues.styleTextHeight
lineHeightMode: Text.FixedHeight
horizontalAlignment: Text.AlignHCenter
width: parent.width
color: DialogValues.textColor
}
-
- Item { id: extraPadding; width: 1; height: 10 }
} // Column
- } // Rectangle
-
- MouseArea {
- anchors.fill: parent
- onClicked: {
- stylesList.currentIndex = index
- }
}
}
Connections {
- target: styleModel
+ target: BackendApi.styleModel
function onModelReset() {
- stylesList.currentIndex = dialogBox.styleIndex;
- stylesList.currentIndexChanged();
- styleTitleText.refresh();
+ stylesList.currentIndex = BackendApi.styleIndex
+ stylesList.currentIndexChanged()
+ styleTitleText.refresh()
}
}
} // ListView
- } // ColumnLayout
+ } // ScrollView
} // Parent Item
} // Rectangle
}
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/qmldir b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/qmldir
index d7c1562164..996b9ec356 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/qmldir
+++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/qmldir
@@ -1,4 +1,7 @@
-singleton DialogValues 1.0 DialogValues.qml
+PopupDialog 1.0 PopupDialog.qml
+PopupDialogButton 1.0 PopupDialogButton.qml
+PopupDialogButtonBox 1.0 PopupDialogButtonBox.qml
Details 1.0 Details.qml
-Styles 1.0 Styles.qml
+singleton DialogValues 1.0 DialogValues.qml
NewProjectView 1.0 NewProjectView.qml
+Styles 1.0 Styles.qml
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExpressionTextField.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExpressionTextField.qml
index 87e9a7e3c0..7828e9b427 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExpressionTextField.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ExpressionTextField.qml
@@ -140,7 +140,7 @@ StudioControls.TextField {
+ 2 : 0)
height: StudioTheme.Values.height - 2 * StudioTheme.Values.border
color: StudioTheme.Values.themeInteraction
- y: listView.currentItem.y
+ y: listView.currentItem?.y ?? 0
}
highlightFollowsCurrentItem: false
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
index 3f8a331189..143ec349d0 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
@@ -54,6 +54,8 @@ Item {
property bool expandOnClick: true // if false, toggleExpand signal will be emitted instead
property bool addTopPadding: true
property bool addBottomPadding: true
+ property bool dropEnabled: false
+ property bool highlight: false
property bool useDefaulContextMenu: true
@@ -72,9 +74,22 @@ Item {
function onExpandAll() { section.expanded = true }
}
+ signal drop(var drag)
+ signal dropEnter(var drag)
+ signal dropExit()
signal showContextMenu()
signal toggleExpand()
+ DropArea {
+ id: dropArea
+
+ enabled: section.dropEnabled
+ anchors.fill: parent
+
+ onEntered: (drag)=> section.dropEnter(drag)
+ onDropped: (drag)=> section.drop(drag)
+ onExited: section.dropExit()
+ }
Rectangle {
id: header
@@ -82,7 +97,9 @@ Item {
visible: !section.hideHeader
anchors.left: parent.left
anchors.right: parent.right
- color: Qt.lighter(StudioTheme.Values.themeSectionHeadBackground, 1.0 + (0.2 * section.level))
+ color: section.highlight ? StudioTheme.Values.themeInteraction
+ : Qt.lighter(StudioTheme.Values.themeSectionHeadBackground, 1.0
+ + (0.2 * section.level))
Item {
StudioControls.Menu {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/VerticalScrollBar.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/VerticalScrollBar.qml
index 4b34413095..b0e6f82bc1 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/VerticalScrollBar.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/VerticalScrollBar.qml
@@ -35,37 +35,26 @@ ScrollBar {
implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
implicitContentHeight + topPadding + bottomPadding)
- property bool scrollBarVisible: parent.childrenRect.height > parent.height
- // viewMouseArea: if set, the scrollbar will be visible only on hover over the view containing
- // the mouse area item.
- property MouseArea viewMouseArea: null
-
- minimumSize: orientation == Qt.Horizontal ? height / width : width / height
+ property bool scrollBarVisible: parent.contentHeight > scrollBar.height
+ minimumSize: scrollBar.width / scrollBar.height
orientation: Qt.Vertical
- policy: computePolicy()
- x: parent.width - width
- y: 0
+ policy: scrollBar.scrollBarVisible ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
+
height: parent.availableHeight
- (parent.bothVisible ? parent.horizontalThickness : 0)
- padding: 0
+ padding: scrollBar.active ? StudioTheme.Values.scrollBarActivePadding
+ : StudioTheme.Values.scrollBarInactivePadding
background: Rectangle {
+ implicitWidth: StudioTheme.Values.scrollBarThickness
+ implicitHeight: StudioTheme.Values.scrollBarThickness
color: StudioTheme.Values.themeScrollBarTrack
}
contentItem: Rectangle {
- implicitWidth: StudioTheme.Values.scrollBarThickness
+ implicitWidth: StudioTheme.Values.scrollBarThickness - 2 * scrollBar.padding
+ implicitHeight: StudioTheme.Values.scrollBarThickness - 2 * scrollBar.padding
color: StudioTheme.Values.themeScrollBarHandle
}
-
- function computePolicy() {
- if (!scrollBar.scrollBarVisible)
- return ScrollBar.AlwaysOff;
-
- if (scrollBar.viewMouseArea)
- return scrollBar.viewMouseArea.containsMouse ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
- else
- return ScrollBar.AlwaysOn;
- }
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml
index 29d0edb14d..f63aa36ab1 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioTheme/Values.qml
@@ -89,6 +89,8 @@ QtObject {
property real typeLabelVerticalShift: Math.round(6 * values.scaleFactor)
property real scrollBarThickness: 10
+ property real scrollBarActivePadding: 1
+ property real scrollBarInactivePadding: 2
property real toolTipHeight: 25
property int toolTipDelay: 1000
diff --git a/share/qtcreator/themes/design-light.creatortheme b/share/qtcreator/themes/design-light.creatortheme
index 0490ffa8ca..b5e54f2a34 100644
--- a/share/qtcreator/themes/design-light.creatortheme
+++ b/share/qtcreator/themes/design-light.creatortheme
@@ -374,7 +374,7 @@ QmlDesigner_ScrollBarHandleColor=ff8b8e8f
PaletteWindow=selectedBackground
PaletteWindowText=text
PaletteBase=normalBackground
-PaletteAlternateBase=alternateBackground
+PaletteAlternateBase=normalBackground
PaletteButton=selectedBackground
PaletteBrightText=selectedBackgroundText
PaletteText=text
diff --git a/share/qtcreator/themes/design.creatortheme b/share/qtcreator/themes/design.creatortheme
index 3dcfb3e1d0..613d89de6b 100644
--- a/share/qtcreator/themes/design.creatortheme
+++ b/share/qtcreator/themes/design.creatortheme
@@ -430,8 +430,8 @@ PaletteBase=normalBackground
-;can't see where this is used.
-PaletteAlternateBase=alternateBackground
+;can't see where this is used. ;Used in plugin dialog
+PaletteAlternateBase=normalBackground
;PaletteAlternateBase=ffd3299a
diff --git a/src/libs/languageserverprotocol/lsptypes.h b/src/libs/languageserverprotocol/lsptypes.h
index dbec3b96de..5dd3f58604 100644
--- a/src/libs/languageserverprotocol/lsptypes.h
+++ b/src/libs/languageserverprotocol/lsptypes.h
@@ -142,6 +142,12 @@ public:
{ return JsonObject::contains(startKey) && JsonObject::contains(endKey); }
};
+inline bool operator==(const Range &r1, const Range &r2)
+{
+ return r1.contains(r2) && r2.contains(r1);
+}
+inline bool operator!=(const Range &r1, const Range &r2) { return !(r1 == r2); }
+
class LANGUAGESERVERPROTOCOL_EXPORT Location : public JsonObject
{
public:
diff --git a/src/libs/utils/elfreader.h b/src/libs/utils/elfreader.h
index 052703f7c0..2f52938b6f 100644
--- a/src/libs/utils/elfreader.h
+++ b/src/libs/utils/elfreader.h
@@ -146,7 +146,7 @@ public:
ElfType elftype;
ElfMachine elfmachine;
ElfClass elfclass;
- quint64 entryPoint;
+ quint64 entryPoint = 0;
QByteArray debugLink;
QByteArray buildId;
DebugSymbolsType symbolsType = UnknownSymbols;
diff --git a/src/plugins/android/androidmanager.cpp b/src/plugins/android/androidmanager.cpp
index e909752f78..0ac99f89c9 100644
--- a/src/plugins/android/androidmanager.cpp
+++ b/src/plugins/android/androidmanager.cpp
@@ -517,6 +517,8 @@ QString AndroidManager::androidNameForApiLevel(int x)
return QLatin1String("Android 12");
case 32:
return QLatin1String("Android 12L");
+ case 33:
+ return QLatin1String("Android 13");
default:
return tr("Unknown Android version. API Level: %1").arg(x);
}
diff --git a/src/plugins/android/androidmanifesteditorwidget.cpp b/src/plugins/android/androidmanifesteditorwidget.cpp
index 90da79c08f..5886877815 100644
--- a/src/plugins/android/androidmanifesteditorwidget.cpp
+++ b/src/plugins/android/androidmanifesteditorwidget.cpp
@@ -1229,8 +1229,15 @@ static void addServiceArgumentsAndLibName(const AndroidServiceData &service, QXm
writeMetadataElement("android.app.lib_name", "android:value", "-- %%INSERT_APP_LIB_NAME%% --", writer);
}
-static void addServiceMetadata(QXmlStreamWriter &writer)
+void AndroidManifestEditorWidget::addServiceMetadata(QXmlStreamWriter &writer)
{
+ // The values below are no longer needed in Qt 6.2+, don't add them
+ const Target *target = androidTarget(m_textEditorWidget->textDocument()->filePath());
+ if (target) {
+ const QtSupport::QtVersion *qt = QtSupport::QtKitAspect::qtVersion(target->kit());
+ if (qt && qt->qtVersion() >= QtSupport::QtVersionNumber(6, 2))
+ return;
+ }
writeMetadataElement("android.app.qt_sources_resource_id", "android:resource", "@array/qt_sources", writer);
writeMetadataElement("android.app.repository", "android:value", "default", writer);
writeMetadataElement("android.app.qt_libs_resource_id", "android:resource", "@array/qt_libs", writer);
diff --git a/src/plugins/android/androidmanifesteditorwidget.h b/src/plugins/android/androidmanifesteditorwidget.h
index 1dd134b08c..6a99a321a7 100644
--- a/src/plugins/android/androidmanifesteditorwidget.h
+++ b/src/plugins/android/androidmanifesteditorwidget.h
@@ -160,6 +160,8 @@ private:
QGroupBox *createApplicationGroupBox(QWidget *parent);
QGroupBox *createAdvancedGroupBox(QWidget *parent);
+ void addServiceMetadata(QXmlStreamWriter &writer);
+
bool m_dirty; // indicates that we need to call syncToEditor()
bool m_stayClean;
int m_errorLine;
diff --git a/src/plugins/android/avddialog.cpp b/src/plugins/android/avddialog.cpp
index 0f9f25e229..b44af13720 100644
--- a/src/plugins/android/avddialog.cpp
+++ b/src/plugins/android/avddialog.cpp
@@ -131,6 +131,10 @@ bool AvdDialog::isValid() const
ProjectExplorer::IDevice::Ptr AvdDialog::device() const
{
+ if (!m_createdAvdInfo.systemImage) {
+ qCWarning(avdDialogLog) << "System image of the created AVD is nullptr";
+ return IDevice::Ptr();
+ }
AndroidDevice *dev = new AndroidDevice();
const Utils::Id deviceId = AndroidDevice::idFromAvdInfo(m_createdAvdInfo);
using namespace ProjectExplorer;
@@ -140,10 +144,6 @@ ProjectExplorer::IDevice::Ptr AvdDialog::device() const
dev->setDeviceState(IDevice::DeviceConnected);
dev->setExtraData(Constants::AndroidAvdName, m_createdAvdInfo.name);
dev->setExtraData(Constants::AndroidCpuAbi, {m_createdAvdInfo.abi});
- if (!m_createdAvdInfo.systemImage) {
- qCWarning(avdDialogLog) << "System image of the created AVD is nullptr";
- return IDevice::Ptr();
- }
dev->setExtraData(Constants::AndroidSdk, m_createdAvdInfo.systemImage->apiLevel());
dev->setExtraData(Constants::AndroidAvdSdcard, QString("%1 MB")
.arg(m_createdAvdInfo.sdcardSize));
diff --git a/src/plugins/android/avdmanageroutputparser.cpp b/src/plugins/android/avdmanageroutputparser.cpp
index 803d4416e2..892405c33e 100644
--- a/src/plugins/android/avdmanageroutputparser.cpp
+++ b/src/plugins/android/avdmanageroutputparser.cpp
@@ -181,6 +181,8 @@ int platformNameToApiLevel(const QString &platformName)
apiLevel = 30;
else if (apiLevelStr == 'S')
apiLevel = 31;
+ else if (apiLevelStr == "Tiramisu")
+ apiLevel = 33;
}
}
return apiLevel;
diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp
index dc8e5d3266..7525fbf160 100644
--- a/src/plugins/clangcodemodel/clangdclient.cpp
+++ b/src/plugins/clangcodemodel/clangdclient.cpp
@@ -1416,7 +1416,12 @@ ClangdClient::ClangdClient(Project *project, const Utils::FilePath &jsonDbDir)
return new ClangdTextMark(filePath, diag, isProjectFile, this);
};
const auto hideDiagsHandler = []{ ClangDiagnosticManager::clearTaskHubIssues(); };
- setDiagnosticsHandlers(textMarkCreator, hideDiagsHandler);
+ static const auto diagsFilter = [](const Diagnostic &diag) {
+ const Diagnostic::Code code = diag.code().value_or(Diagnostic::Code());
+ const QString * const codeString = Utils::get_if<QString>(&code);
+ return !codeString || *codeString != "drv_unknown_argument";
+ };
+ setDiagnosticsHandlers(textMarkCreator, hideDiagsHandler, diagsFilter);
setSymbolStringifier(displayNameFromDocumentSymbol);
setSemanticTokensHandler([this](TextDocument *doc, const QList<ExpandedSemanticToken> &tokens,
int version, bool force) {
@@ -2815,7 +2820,8 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
if (detail.startsWith("operator")) {
return !detail.contains('=')
&& !detail.contains("++") && !detail.contains("--")
- && !detail.contains("<<") && !detail.contains(">>");
+ && !detail.contains("<<") && !detail.contains(">>")
+ && !detail.contains("*");
}
firstChildTree << n.children().value_or(QList<AstNode>());
}
@@ -2826,6 +2832,19 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
return false;
if (it->hasConstType())
return false;
+
+ if (it->kind() == "CXXMemberCall") {
+ if (it == path.rbegin())
+ return false;
+ const QList<AstNode> children = it->children().value_or(QList<AstNode>());
+ QTC_ASSERT(!children.isEmpty(), return false);
+
+ // The called object is never displayed as an output parameter.
+ // TODO: A good argument can be made to display objects on which a non-const
+ // operator or function is called as output parameters.
+ return (it - 1)->range() != children.first().range();
+ }
+
if (it->kind() == "Member" && it->arcanaContains("(")
&& !it->arcanaContains("bound member function type")) {
return false;
@@ -2911,8 +2930,11 @@ static void semanticHighlighter(QFutureInterface<HighlightingResult> &future,
}
if (token.modifiers.contains(QLatin1String("declaration")))
styles.mixinStyles.push_back(C_DECLARATION);
- if (token.modifiers.contains(QLatin1String("static")))
- styles.mixinStyles.push_back(C_STATIC_MEMBER);
+ if (token.modifiers.contains(QLatin1String("static"))) {
+ if (styles.mainStyle != C_FIELD && styles.mainStyle != C_TEXT)
+ styles.mixinStyles.push_back(styles.mainStyle);
+ styles.mainStyle = C_STATIC_MEMBER;
+ }
if (isOutputParameter(token))
styles.mixinStyles.push_back(C_OUTPUT_ARGUMENT);
qCDebug(clangdLogHighlight) << "adding highlighting result"
diff --git a/src/plugins/clangcodemodel/test/clangdtests.cpp b/src/plugins/clangcodemodel/test/clangdtests.cpp
index adaa705cb8..b672dec291 100644
--- a/src/plugins/clangcodemodel/test/clangdtests.cpp
+++ b/src/plugins/clangcodemodel/test/clangdtests.cpp
@@ -998,6 +998,10 @@ void ClangdTestHighlighting::test_data()
<< QList<int>{C_PUNCTUATION} << int(CppEditor::SemanticHighlighter::AngleBracketOpen);
QTest::newRow("class template instantiation (closing angle bracket)") << 384 << 22 << 384 << 23
<< QList<int>{C_PUNCTUATION} << int(CppEditor::SemanticHighlighter::AngleBracketClose);
+ QTest::newRow("static member function decl") << 395 << 17 << 395 << 30
+ << QList<int>{C_STATIC_MEMBER, C_DECLARATION, C_FUNCTION} << 0;
+ QTest::newRow("static member function call") << 400 << 17 << 400 << 30
+ << QList<int>{C_STATIC_MEMBER, C_FUNCTION} << 0;
QTest::newRow("namespace in declaration") << 413 << 4 << 413 << 26
<< QList<int>{C_NAMESPACE} << 0;
QTest::newRow("namespaced class in declaration") << 413 << 28 << 413 << 41
@@ -1122,9 +1126,9 @@ void ClangdTestHighlighting::test_data()
QTest::newRow("local variable captured by lambda") << 442 << 24 << 442 << 27
<< QList<int>{C_LOCAL} << 0;
QTest::newRow("static protected member") << 693 << 16 << 693 << 30
- << QList<int>{C_FIELD, C_DECLARATION, C_STATIC_MEMBER} << 0;
+ << QList<int>{C_STATIC_MEMBER, C_DECLARATION} << 0;
QTest::newRow("static private member") << 696 << 16 << 696 << 28
- << QList<int>{C_FIELD, C_DECLARATION, C_STATIC_MEMBER} << 0;
+ << QList<int>{C_STATIC_MEMBER, C_DECLARATION} << 0;
QTest::newRow("alias template declaration (opening angle bracket)") << 700 << 10 << 700 << 11
<< QList<int>{C_PUNCTUATION} << int(CppEditor::SemanticHighlighter::AngleBracketOpen);
QTest::newRow("alias template declaration (closing angle bracket)") << 700 << 16 << 700 << 17
@@ -1308,6 +1312,9 @@ void ClangdTestHighlighting::test_data()
<< QList<int>{C_PREPROCESSOR} << 0;
QTest::newRow("built-in define 3") << 952 << 21 << 952 << 40
<< QList<int>{C_PREPROCESSOR} << 0;
+ QTest::newRow("deref operator (object)") << 960 << 10 << 960 << 11 << QList<int>{C_LOCAL} << 0;
+ QTest::newRow("deref operator (member)") << 960 << 12 << 960 << 13 << QList<int>{C_FIELD} << 0;
+ QTest::newRow("nested call") << 979 << 20 << 979 << 21 << QList<int>{C_LOCAL} << 0;
}
void ClangdTestHighlighting::test()
@@ -1395,6 +1402,8 @@ void ClangdTestHighlighting::test()
QEXPECT_FAIL("non-final virtual function call via pointer",
"clangd < 14 does not send virtual modifier", Continue);
}
+ QEXPECT_FAIL("non-const reference via member function call as output argument (object)",
+ "See below", Continue);
QEXPECT_FAIL("non-const reference via member function call as output argument (function)",
"Without punctuation and comment tokens from clangd, it's not possible "
"to highlight entire expressions. But do we really want this? What about nested "
diff --git a/src/plugins/clangcodemodel/test/data/completion/completion.pro b/src/plugins/clangcodemodel/test/data/completion/completion.pro
index da641f2237..832b9aac07 100644
--- a/src/plugins/clangcodemodel/test/data/completion/completion.pro
+++ b/src/plugins/clangcodemodel/test/data/completion/completion.pro
@@ -27,5 +27,7 @@ SOURCES = \
privateFuncDefCompletion.cpp \
signalCompletion.cpp
+QMAKE_CXXFLAGS += -ffoo
+
HEADERS = mainwindow.h
FORMS = mainwindow.ui
diff --git a/src/plugins/clangcodemodel/test/data/find-usages/find-usages.pro b/src/plugins/clangcodemodel/test/data/find-usages/find-usages.pro
index c447485530..cf511fee40 100644
--- a/src/plugins/clangcodemodel/test/data/find-usages/find-usages.pro
+++ b/src/plugins/clangcodemodel/test/data/find-usages/find-usages.pro
@@ -2,3 +2,4 @@ TEMPLATE = app
QT = core
HEADERS = defs.h
SOURCES = main.cpp
+QMAKE_CXXFLAGS += -ffoo
diff --git a/src/plugins/clangcodemodel/test/data/follow-symbol/follow-symbol.pro b/src/plugins/clangcodemodel/test/data/follow-symbol/follow-symbol.pro
index 7d2c3147a3..8b0d6d1879 100644
--- a/src/plugins/clangcodemodel/test/data/follow-symbol/follow-symbol.pro
+++ b/src/plugins/clangcodemodel/test/data/follow-symbol/follow-symbol.pro
@@ -2,3 +2,4 @@ TEMPLATE = app
CONFIG -= qt
HEADERS = cursor.h header.h
SOURCES = cursor.cpp main.cpp
+QMAKE_CXXFLAGS += -ffoo
diff --git a/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp b/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp
index 2ef28c11ba..7275ddd330 100644
--- a/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp
+++ b/src/plugins/clangcodemodel/test/data/highlighting/highlighting.cpp
@@ -951,3 +951,30 @@ void builtinDefines()
const auto f2 = __FUNCTION__;
const auto f3 = __PRETTY_FUNCTION__;
}
+
+void derefOperator()
+{
+ struct S { bool operator*(); };
+ struct S2 { S s; };
+ S2 s;
+ if (*s.s)
+ return;
+}
+
+struct my_struct
+{
+ void* method(int dummy);
+};
+
+my_struct* get_my_struct();
+
+struct my_struct2
+{
+ my_struct2(void* p);
+};
+
+void nestedCall()
+{
+ my_struct* s = get_my_struct();
+ new my_struct2(s->method(0));
+}
diff --git a/src/plugins/clangcodemodel/test/data/highlighting/highlighting.pro b/src/plugins/clangcodemodel/test/data/highlighting/highlighting.pro
index 7dd57583ea..32196b9724 100644
--- a/src/plugins/clangcodemodel/test/data/highlighting/highlighting.pro
+++ b/src/plugins/clangcodemodel/test/data/highlighting/highlighting.pro
@@ -1,3 +1,4 @@
TEMPLATE = app
CONFIG -= qt
SOURCES = highlighting.cpp
+QMAKE_CXXFLAGS += -ffoo
diff --git a/src/plugins/clangcodemodel/test/data/local-references/local-references.pro b/src/plugins/clangcodemodel/test/data/local-references/local-references.pro
index c3b335aad8..f47c1c6815 100644
--- a/src/plugins/clangcodemodel/test/data/local-references/local-references.pro
+++ b/src/plugins/clangcodemodel/test/data/local-references/local-references.pro
@@ -1,5 +1,4 @@
TEMPLATE = app
-
CONFIG -= qt
-
SOURCES = references.cpp
+QMAKE_CXXFLAGS += -ffoo
diff --git a/src/plugins/clangformat/clangformatutils.cpp b/src/plugins/clangformat/clangformatutils.cpp
index e59a151f0b..83aa58c167 100644
--- a/src/plugins/clangformat/clangformatutils.cpp
+++ b/src/plugins/clangformat/clangformatutils.cpp
@@ -376,18 +376,27 @@ static std::string readFile(const QString &path)
if (!file.open(QFile::ReadOnly))
return defaultStyle;
- const QByteArray content = file.readAll();
+ const std::string content = file.readAll().toStdString();
file.close();
clang::format::FormatStyle style;
style.Language = clang::format::FormatStyle::LK_Cpp;
- const std::error_code error = clang::format::parseConfiguration(content.toStdString(), &style);
-
+ const std::error_code error = clang::format::parseConfiguration(content, &style);
QTC_ASSERT(error.value() == static_cast<int>(ParseError::Success), return defaultStyle);
addQtcStatementMacros(style);
+ std::string settings = clang::format::configurationAsText(style);
+
+ // Needed workaround because parseConfiguration remove BasedOnStyle field
+ // ToDo: standardize this behavior for future
+ const size_t index = content.find("BasedOnStyle");
+ if (index != std::string::npos) {
+ const size_t size = content.find("\n", index) - index;
+ const size_t insert_index = settings.find("\n");
+ settings.insert(insert_index, "\n" + content.substr(index, size));
+ }
- return clang::format::configurationAsText(style);
+ return settings;
}
std::string currentProjectConfigText()
diff --git a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
index 2e05617604..817098b8f6 100644
--- a/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
+++ b/src/plugins/cmakeprojectmanager/cmakebuildconfiguration.cpp
@@ -1739,14 +1739,14 @@ const QStringList InitialCMakeArgumentsAspect::allValues() const
void InitialCMakeArgumentsAspect::setAllValues(const QString &values, QStringList &additionalOptions)
{
QStringList arguments = values.split('\n', Qt::SkipEmptyParts);
+ QString cmakeGenerator;
for (QString &arg: arguments) {
if (arg.startsWith("-G")) {
const QString strDash(" - ");
const int idxDash = arg.indexOf(strDash);
if (idxDash > 0) {
// -GCodeBlocks - Ninja
- QString generator = "-DCMAKE_GENERATOR:STRING=" + arg.mid(idxDash + strDash.length());
- arguments.append(generator);
+ cmakeGenerator = "-DCMAKE_GENERATOR:STRING=" + arg.mid(idxDash + strDash.length());
arg = arg.left(idxDash);
arg.replace("-G", "-DCMAKE_EXTRA_GENERATOR:STRING=");
@@ -1761,6 +1761,9 @@ void InitialCMakeArgumentsAspect::setAllValues(const QString &values, QStringLis
if (arg.startsWith("-T"))
arg.replace("-T", "-DCMAKE_GENERATOR_TOOLSET:STRING=");
}
+ if (!cmakeGenerator.isEmpty())
+ arguments.append(cmakeGenerator);
+
m_cmakeConfiguration = CMakeConfig::fromArguments(arguments, additionalOptions);
for (CMakeConfigItem &ci : m_cmakeConfiguration)
ci.isInitial = true;
diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp
index 2e66e0c48b..6e3f73358c 100644
--- a/src/plugins/cmakeprojectmanager/cmaketool.cpp
+++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp
@@ -234,7 +234,7 @@ FilePath CMakeTool::qchFilePath() const
FilePath CMakeTool::cmakeExecutable(const FilePath &path)
{
- if (HostOsInfo::isMacHost()) {
+ if (path.osType() == OsTypeMac) {
const QString executableString = path.toString();
const int appIndex = executableString.lastIndexOf(".app");
const int appCutIndex = appIndex + 4;
@@ -251,7 +251,7 @@ FilePath CMakeTool::cmakeExecutable(const FilePath &path)
const FilePath resolvedPath = path.canonicalPath();
// Evil hack to make snap-packages of CMake work. See QTCREATORBUG-23376
- if (HostOsInfo::isLinuxHost() && resolvedPath.fileName() == "snap")
+ if (path.osType() == OsTypeLinux && resolvedPath.fileName() == "snap")
return path;
return resolvedPath;
diff --git a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp
index acd9422fc7..0629273d96 100644
--- a/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp
+++ b/src/plugins/cmakeprojectmanager/cmaketoolsettingsaccessor.cpp
@@ -239,9 +239,10 @@ CMakeToolSettingsAccessor::cmakeTools(const QVariantMap &data, bool fromSdk) con
const QVariantMap dbMap = data.value(key).toMap();
auto item = std::make_unique<CMakeTool>(dbMap, fromSdk);
- if (item->isAutoDetected() && !item->cmakeExecutable().isExecutableFile()) {
- qWarning() << QString::fromLatin1("CMakeTool \"%1\" (%2) dropped since the command is not executable.")
- .arg(item->cmakeExecutable().toUserOutput(), item->id().toString());
+ const FilePath cmakeExecutable = item->cmakeExecutable();
+ if (item->isAutoDetected() && !cmakeExecutable.needsDevice() && !cmakeExecutable.isExecutableFile()) {
+ qWarning() << QString("CMakeTool \"%1\" (%2) dropped since the command is not executable.")
+ .arg(cmakeExecutable.toUserOutput(), item->id().toString());
continue;
}
diff --git a/src/plugins/coreplugin/foldernavigationwidget.cpp b/src/plugins/coreplugin/foldernavigationwidget.cpp
index 52cae41287..1c7d82a145 100644
--- a/src/plugins/coreplugin/foldernavigationwidget.cpp
+++ b/src/plugins/coreplugin/foldernavigationwidget.cpp
@@ -85,6 +85,7 @@ const char kHiddenFilesKey[] = ".HiddenFilesFilter";
const char kSyncKey[] = ".SyncWithEditor";
const char kShowBreadCrumbs[] = ".ShowBreadCrumbs";
const char kSyncRootWithEditor[] = ".SyncRootWithEditor";
+const char kShowFoldersOnTop[] = ".ShowFoldersOnTop";
const char ADDNEWFILE[] = "QtCreator.FileSystem.AddNewFile";
const char RENAMEFILE[] = "QtCreator.FileSystem.RenameFile";
@@ -834,6 +835,7 @@ const bool kHiddenFilesDefault = false;
const bool kAutoSyncDefault = true;
const bool kShowBreadCrumbsDefault = true;
const bool kRootAutoSyncDefault = true;
+const bool kShowFoldersOnTopDefault = true;
void FolderNavigationWidgetFactory::saveSettings(Utils::QtcSettings *settings,
int position,
@@ -852,6 +854,9 @@ void FolderNavigationWidgetFactory::saveSettings(Utils::QtcSettings *settings,
settings->setValueWithDefault(base + kSyncRootWithEditor,
fnw->rootAutoSynchronization(),
kRootAutoSyncDefault);
+ settings->setValueWithDefault(base + kShowFoldersOnTop,
+ fnw->isShowingFoldersOnTop(),
+ kShowFoldersOnTopDefault);
}
void FolderNavigationWidgetFactory::restoreSettings(QSettings *settings, int position, QWidget *widget)
@@ -865,6 +870,8 @@ void FolderNavigationWidgetFactory::restoreSettings(QSettings *settings, int pos
settings->value(base + kShowBreadCrumbs, kShowBreadCrumbsDefault).toBool());
fnw->setRootAutoSynchronization(
settings->value(base + kSyncRootWithEditor, kRootAutoSyncDefault).toBool());
+ fnw->setShowFoldersOnTop(
+ settings->value(base + kShowFoldersOnTop, kShowFoldersOnTopDefault).toBool());
}
void FolderNavigationWidgetFactory::insertRootDirectory(const RootDirectory &directory)
diff --git a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp
index 54c8318a07..c34b01d7c4 100644
--- a/src/plugins/debugger/debuggersourcepathmappingwidget.cpp
+++ b/src/plugins/debugger/debuggersourcepathmappingwidget.cpp
@@ -100,7 +100,8 @@ QStringList qtBuildPaths()
return {"Q:/qt5_workdir/w/s",
"C:/work/build/qt5_workdir/w/s",
"c:/users/qt/work/qt",
- "c:/Users/qt/work/install"};
+ "c:/Users/qt/work/install",
+ "/Users/qt/work/qt"};
} else if (HostOsInfo::isMacHost()) {
return { "/Users/qt/work/qt" };
} else {
diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp
index b25fe0aec2..99b1dca165 100644
--- a/src/plugins/help/helpplugin.cpp
+++ b/src/plugins/help/helpplugin.cpp
@@ -607,12 +607,14 @@ void HelpPluginPrivate::showContextHelp(const HelpItem &contextHelp)
void HelpPluginPrivate::activateIndex()
{
activateHelpMode();
+ showHelpUrl(LocalHelpManager::homePage(), Core::HelpManager::HelpModeAlways);
m_centralWidget->activateSideBarItem(Constants::HELP_INDEX);
}
void HelpPluginPrivate::activateContents()
{
activateHelpMode();
+ showHelpUrl(LocalHelpManager::homePage(), Core::HelpManager::HelpModeAlways);
m_centralWidget->activateSideBarItem(Constants::HELP_CONTENTS);
}
diff --git a/src/plugins/imageviewer/imageviewerfile.cpp b/src/plugins/imageviewer/imageviewerfile.cpp
index 0fb4e22a10..0133cce05c 100644
--- a/src/plugins/imageviewer/imageviewerfile.cpp
+++ b/src/plugins/imageviewer/imageviewerfile.cpp
@@ -111,7 +111,7 @@ Core::IDocument::OpenResult ImageViewerFile::openImpl(QString *errorString,
if (format.startsWith("svg")) {
m_tempSvgItem = new QGraphicsSvgItem(fileName);
QRectF bound = m_tempSvgItem->boundingRect();
- if (qFuzzyIsNull(bound.width()) && qFuzzyIsNull(bound.height())) {
+ if (!bound.isValid() || (qFuzzyIsNull(bound.width()) && qFuzzyIsNull(bound.height()))) {
delete m_tempSvgItem;
m_tempSvgItem = nullptr;
if (errorString)
@@ -123,8 +123,17 @@ Core::IDocument::OpenResult ImageViewerFile::openImpl(QString *errorString,
} else
#endif
if (QMovie::supportedFormats().contains(format)) {
- m_type = TypeMovie;
m_movie = new QMovie(fileName, QByteArray(), this);
+ // force reading movie/image data, so we can catch completely invalid movies/images early:
+ m_movie->jumpToNextFrame();
+ if (!m_movie->isValid()) {
+ if (errorString)
+ *errorString = tr("Failed to read image.");
+ delete m_movie;
+ m_movie = nullptr;
+ return OpenResult::CannotHandle;
+ }
+ m_type = TypeMovie;
m_movie->setCacheMode(QMovie::CacheAll);
connect(
m_movie,
diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp
index a8ec473fc3..d88c0ae86d 100644
--- a/src/plugins/languageclient/client.cpp
+++ b/src/plugins/languageclient/client.cpp
@@ -1085,9 +1085,10 @@ bool Client::hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri,
}
void Client::setDiagnosticsHandlers(const TextMarkCreator &textMarkCreator,
- const HideDiagnosticsHandler &hideHandler)
+ const HideDiagnosticsHandler &hideHandler,
+ const DiagnosticsFilter &filter)
{
- m_diagnosticManager.setDiagnosticsHandlers(textMarkCreator, hideHandler);
+ m_diagnosticManager.setDiagnosticsHandlers(textMarkCreator, hideHandler, filter);
}
void Client::setSemanticTokensHandler(const SemanticTokensHandler &handler)
diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h
index 4a7356e7c5..3327437d41 100644
--- a/src/plugins/languageclient/client.h
+++ b/src/plugins/languageclient/client.h
@@ -189,7 +189,7 @@ public:
bool hasDiagnostic(const LanguageServerProtocol::DocumentUri &uri,
const LanguageServerProtocol::Diagnostic &diag) const;
void setDiagnosticsHandlers(const TextMarkCreator &textMarkCreator,
- const HideDiagnosticsHandler &hideHandler);
+ const HideDiagnosticsHandler &hideHandler, const DiagnosticsFilter &filter);
void setSemanticTokensHandler(const SemanticTokensHandler &handler);
void setSymbolStringifier(const LanguageServerProtocol::SymbolStringifier &stringifier);
LanguageServerProtocol::SymbolStringifier symbolStringifier() const;
diff --git a/src/plugins/languageclient/diagnosticmanager.cpp b/src/plugins/languageclient/diagnosticmanager.cpp
index 2b1d66c477..a1b729ce9b 100644
--- a/src/plugins/languageclient/diagnosticmanager.cpp
+++ b/src/plugins/languageclient/diagnosticmanager.cpp
@@ -90,7 +90,9 @@ void DiagnosticManager::setDiagnostics(const LanguageServerProtocol::DocumentUri
const Utils::optional<int> &version)
{
hideDiagnostics(uri.toFilePath());
- m_diagnostics[uri] = {version, diagnostics};
+ const QList<Diagnostic> filteredDiags = m_filter
+ ? Utils::filtered(diagnostics, m_filter) : diagnostics;
+ m_diagnostics[uri] = {version, filteredDiags};
}
void DiagnosticManager::hideDiagnostics(const Utils::FilePath &filePath)
@@ -201,10 +203,12 @@ bool DiagnosticManager::hasDiagnostic(const LanguageServerProtocol::DocumentUri
}
void DiagnosticManager::setDiagnosticsHandlers(const TextMarkCreator &textMarkCreator,
- const HideDiagnosticsHandler &removalHandler)
+ const HideDiagnosticsHandler &removalHandler,
+ const DiagnosticsFilter &filter)
{
m_textMarkCreator = textMarkCreator;
m_hideHandler = removalHandler;
+ m_filter = filter;
}
} // namespace LanguageClient
diff --git a/src/plugins/languageclient/diagnosticmanager.h b/src/plugins/languageclient/diagnosticmanager.h
index c4bfabf71a..f201aaf50c 100644
--- a/src/plugins/languageclient/diagnosticmanager.h
+++ b/src/plugins/languageclient/diagnosticmanager.h
@@ -45,6 +45,7 @@ class Client;
using TextMarkCreator = std::function<TextEditor::TextMark *(const Utils::FilePath &,
const LanguageServerProtocol::Diagnostic &, bool)>;
using HideDiagnosticsHandler = std::function<void()>;
+using DiagnosticsFilter = std::function<bool(const LanguageServerProtocol::Diagnostic &)>;
class DiagnosticManager
{
@@ -70,7 +71,8 @@ public:
const LanguageServerProtocol::Diagnostic &diag) const;
void setDiagnosticsHandlers(const TextMarkCreator &shownHandler,
- const HideDiagnosticsHandler &removalHandler);
+ const HideDiagnosticsHandler &removalHandler,
+ const DiagnosticsFilter &filter);
private:
TextEditor::TextMark *createTextMark(const Utils::FilePath &filePath,
@@ -83,6 +85,7 @@ private:
QMap<Utils::FilePath, QList<TextEditor::TextMark *>> m_marks;
TextMarkCreator m_textMarkCreator;
HideDiagnosticsHandler m_hideHandler;
+ DiagnosticsFilter m_filter;
Client *m_client;
};
diff --git a/src/plugins/marketplace/qtmarketplacewelcomepage.cpp b/src/plugins/marketplace/qtmarketplacewelcomepage.cpp
index 1abb06dacc..bd1c112a56 100644
--- a/src/plugins/marketplace/qtmarketplacewelcomepage.cpp
+++ b/src/plugins/marketplace/qtmarketplacewelcomepage.cpp
@@ -132,8 +132,9 @@ public:
void onTagClicked(const QString &tag)
{
- QString text = m_searcher->text();
- m_searcher->setText(text + QString("tag:\"%1\" ").arg(tag));
+ const QString text = m_searcher->text();
+ m_searcher->setText((text.startsWith("tag:\"") ? text.trimmed() + " " : QString())
+ + QString("tag:\"%1\" ").arg(tag));
}
private:
diff --git a/src/plugins/mcusupport/mcupackage.cpp b/src/plugins/mcusupport/mcupackage.cpp
index a41138e1cd..171f326fa9 100644
--- a/src/plugins/mcusupport/mcupackage.cpp
+++ b/src/plugins/mcusupport/mcupackage.cpp
@@ -103,7 +103,7 @@ FilePath McuPackage::basePath() const
FilePath McuPackage::path() const
{
- return basePath().resolvePath(m_relativePathModifier).absoluteFilePath();
+ return basePath().pathAppended(m_relativePathModifier.path()).absoluteFilePath();
}
FilePath McuPackage::defaultPath() const
@@ -126,7 +126,7 @@ void McuPackage::updatePath()
void McuPackage::updateStatus()
{
bool validPath = !m_path.isEmpty() && m_path.exists();
- const FilePath detectionPath = basePath().resolvePath(m_detectionPath);
+ const FilePath detectionPath = basePath().pathAppended(m_detectionPath.path());
const bool validPackage = m_detectionPath.isEmpty() || detectionPath.exists();
m_detectedVersion = validPath && validPackage && m_versionDetector
? m_versionDetector->parseVersion(basePath().toString())
diff --git a/src/plugins/mcusupport/mcusupportversiondetection.cpp b/src/plugins/mcusupport/mcusupportversiondetection.cpp
index b5d2dc18a2..b0db763801 100644
--- a/src/plugins/mcusupport/mcusupportversiondetection.cpp
+++ b/src/plugins/mcusupport/mcusupportversiondetection.cpp
@@ -58,7 +58,7 @@ QString McuPackageExecutableVersionDetector::parseVersion(const QString &package
if (m_detectionPath.isEmpty() || m_detectionRegExp.isEmpty())
return QString();
- const Utils::FilePath binaryPath = Utils::FilePath::fromString(packagePath).resolvePath(m_detectionPath);
+ const Utils::FilePath binaryPath = Utils::FilePath::fromString(packagePath).pathAppended(m_detectionPath.path());
if (!binaryPath.exists())
return QString();
diff --git a/src/plugins/projectexplorer/buildconfiguration.cpp b/src/plugins/projectexplorer/buildconfiguration.cpp
index c0907d6d73..481c16be81 100644
--- a/src/plugins/projectexplorer/buildconfiguration.cpp
+++ b/src/plugins/projectexplorer/buildconfiguration.cpp
@@ -58,6 +58,7 @@
#include <QCheckBox>
#include <QDebug>
#include <QFormLayout>
+#include <QLoggingCategory>
#include <QVBoxLayout>
using namespace Utils;
@@ -69,6 +70,8 @@ const char USER_ENVIRONMENT_CHANGES_KEY[] = "ProjectExplorer.BuildConfiguration.
const char CUSTOM_PARSERS_KEY[] = "ProjectExplorer.BuildConfiguration.CustomParsers";
const char PARSE_STD_OUT_KEY[] = "ProjectExplorer.BuildConfiguration.ParseStandardOutput";
+Q_LOGGING_CATEGORY(bcLog, "qtc.buildconfig", QtWarningMsg)
+
namespace ProjectExplorer {
namespace Internal {
@@ -608,6 +611,8 @@ FilePath BuildConfiguration::buildDirectoryFromTemplate(const FilePath &projectD
{
MacroExpander exp;
+ qCDebug(bcLog) << Q_FUNC_INFO << projectDir << mainFilePath << projectName << bcName;
+
// TODO: Remove "Current" variants in ~4.16
exp.registerFileVariables(Constants::VAR_CURRENTPROJECT_PREFIX,
QCoreApplication::translate("ProjectExplorer", "Main file of current project"),
@@ -638,7 +643,9 @@ FilePath BuildConfiguration::buildDirectoryFromTemplate(const FilePath &projectD
exp.registerSubProvider([kit] { return kit->macroExpander(); });
QString buildDir = ProjectExplorerPlugin::buildDirectoryTemplate();
+ qCDebug(bcLog) << "build dir template:" << buildDir;
buildDir = exp.expand(buildDir);
+ qCDebug(bcLog) << "expanded build:" << buildDir;
if (spaceHandling == ReplaceSpaces)
buildDir.replace(" ", "-");
diff --git a/src/plugins/projectexplorer/customparser.cpp b/src/plugins/projectexplorer/customparser.cpp
index 3efa046b99..0229a5287c 100644
--- a/src/plugins/projectexplorer/customparser.cpp
+++ b/src/plugins/projectexplorer/customparser.cpp
@@ -271,7 +271,7 @@ OutputLineParser::Result CustomParser::parseLine(
CustomParserExpression::CustomParserChannel channel
)
{
- const QString line = rawLine.trimmed();
+ const QString line = rightTrimmed(rawLine);
const Result res = hasMatch(line, channel, m_error, Task::Error);
if (res.status != Status::NotHandled)
return res;
@@ -629,6 +629,55 @@ void ProjectExplorerPlugin::testCustomOutputParsers_data()
<< QString() << QString()
<< Tasks({CompileTask(Task::Error, unitTestMessage, unitTestFileName, unitTestLineNumber)})
<< QString();
+
+ const QString leadingSpacesPattern = "^ MESSAGE:(.+)";
+ const QString leadingSpacesMessage = " MESSAGE:Error";
+ const QString noLeadingSpacesMessage = "MESSAGE:Error";
+ QTest::newRow("leading spaces: match")
+ << leadingSpacesMessage
+ << QString()
+ << OutputParserTester::STDOUT
+ << CustomParserExpression::ParseBothChannels
+ << CustomParserExpression::ParseBothChannels
+ << leadingSpacesPattern << 2 << 3 << 1
+ << QString() << 1 << 2 << 3
+ << QString() << QString()
+ << Tasks({CompileTask(Task::Error, "Error", {}, -1)})
+ << QString();
+ QTest::newRow("leading spaces: no match")
+ << noLeadingSpacesMessage
+ << QString()
+ << OutputParserTester::STDOUT
+ << CustomParserExpression::ParseBothChannels
+ << CustomParserExpression::ParseBothChannels
+ << leadingSpacesPattern << 2 << 3 << 1
+ << QString() << 1 << 2 << 3
+ << (noLeadingSpacesMessage + '\n') << QString()
+ << Tasks()
+ << QString();
+ const QString noLeadingSpacesPattern = "^MESSAGE:(.+)";
+ QTest::newRow("no leading spaces: match")
+ << noLeadingSpacesMessage
+ << QString()
+ << OutputParserTester::STDOUT
+ << CustomParserExpression::ParseBothChannels
+ << CustomParserExpression::ParseBothChannels
+ << noLeadingSpacesPattern << 2 << 3 << 1
+ << QString() << 1 << 2 << 3
+ << QString() << QString()
+ << Tasks({CompileTask(Task::Error, "Error", {}, -1)})
+ << QString();
+ QTest::newRow("no leading spaces: no match")
+ << leadingSpacesMessage
+ << QString()
+ << OutputParserTester::STDOUT
+ << CustomParserExpression::ParseBothChannels
+ << CustomParserExpression::ParseBothChannels
+ << noLeadingSpacesPattern << 3 << 2 << 1
+ << QString() << 1 << 2 << 3
+ << (leadingSpacesMessage + '\n') << QString()
+ << Tasks()
+ << QString();
}
void ProjectExplorerPlugin::testCustomOutputParsers()
diff --git a/src/plugins/projectexplorer/kitmanager.cpp b/src/plugins/projectexplorer/kitmanager.cpp
index 52cf506a88..e67bbe71d2 100644
--- a/src/plugins/projectexplorer/kitmanager.cpp
+++ b/src/plugins/projectexplorer/kitmanager.cpp
@@ -813,7 +813,10 @@ QSet<Id> KitFeatureProvider::availablePlatforms() const
QString KitFeatureProvider::displayNameForPlatform(Id id) const
{
if (IDeviceFactory *f = IDeviceFactory::find(id)) {
- const QString dn = f->displayName();
+ QString dn = f->displayName();
+ const QString deviceStr = QStringLiteral("device");
+ if (dn.endsWith(deviceStr, Qt::CaseInsensitive))
+ dn = dn.remove(deviceStr, Qt::CaseInsensitive).trimmed();
QTC_CHECK(!dn.isEmpty());
return dn;
}
diff --git a/src/plugins/projectexplorer/projectwelcomepage.cpp b/src/plugins/projectexplorer/projectwelcomepage.cpp
index 6607454443..e1adf657ad 100644
--- a/src/plugins/projectexplorer/projectwelcomepage.cpp
+++ b/src/plugins/projectexplorer/projectwelcomepage.cpp
@@ -124,28 +124,6 @@ void ProjectModel::resetProjects()
ProjectWelcomePage::ProjectWelcomePage()
{
- const int actionsCount = 9;
- Context welcomeContext(Core::Constants::C_WELCOME_MODE);
-
- const Id projectBase = PROJECT_BASE_ID;
- const Id sessionBase = SESSION_BASE_ID;
- for (int i = 1; i <= actionsCount; ++i) {
- auto act = new QAction(tr("Open Session #%1").arg(i), this);
- Command *cmd = ActionManager::registerAction(act, sessionBase.withSuffix(i), welcomeContext);
- cmd->setDefaultKeySequence(QKeySequence((useMacShortcuts ? tr("Ctrl+Meta+%1") : tr("Ctrl+Alt+%1")).arg(i)));
- connect(act, &QAction::triggered, this, [this, i] {
- if (i <= m_sessionModel->rowCount())
- openSessionAt(i - 1);
- });
-
- act = new QAction(tr("Open Recent Project #%1").arg(i), this);
- cmd = ActionManager::registerAction(act, projectBase.withSuffix(i), welcomeContext);
- cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+%1").arg(i)));
- connect(act, &QAction::triggered, this, [this, i] {
- if (i <= m_projectModel->rowCount(QModelIndex()))
- openProjectAt(i - 1);
- });
- }
}
Utils::Id ProjectWelcomePage::id() const
@@ -185,6 +163,40 @@ void ProjectWelcomePage::openProjectAt(int index)
ProjectExplorerPlugin::openProjectWelcomePage(projectFile);
}
+void ProjectWelcomePage::createActions()
+{
+ static bool actionsRegistered = false;
+
+ if (actionsRegistered)
+ return;
+
+ actionsRegistered = true;
+
+ const int actionsCount = 9;
+ Context welcomeContext(Core::Constants::C_WELCOME_MODE);
+
+ const Id projectBase = PROJECT_BASE_ID;
+ const Id sessionBase = SESSION_BASE_ID;
+
+ for (int i = 1; i <= actionsCount; ++i) {
+ auto act = new QAction(tr("Open Session #%1").arg(i), this);
+ Command *cmd = ActionManager::registerAction(act, sessionBase.withSuffix(i), welcomeContext);
+ cmd->setDefaultKeySequence(QKeySequence((useMacShortcuts ? tr("Ctrl+Meta+%1") : tr("Ctrl+Alt+%1")).arg(i)));
+ connect(act, &QAction::triggered, this, [this, i] {
+ if (i <= m_sessionModel->rowCount())
+ openSessionAt(i - 1);
+ });
+
+ act = new QAction(tr("Open Recent Project #%1").arg(i), this);
+ cmd = ActionManager::registerAction(act, projectBase.withSuffix(i), welcomeContext);
+ cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+%1").arg(i)));
+ connect(act, &QAction::triggered, this, [this, i] {
+ if (i <= m_projectModel->rowCount(QModelIndex()))
+ openProjectAt(i - 1);
+ });
+ }
+}
+
///////////////////
static QColor themeColor(Theme::Color role)
@@ -636,7 +648,11 @@ public:
QWidget *ProjectWelcomePage::createWidget() const
{
- return new SessionsPage(const_cast<ProjectWelcomePage *>(this));
+ auto that = const_cast<ProjectWelcomePage *>(this);
+ QWidget *widget = new SessionsPage(that);
+ that->createActions();
+
+ return widget;
}
} // namespace Internal
diff --git a/src/plugins/projectexplorer/projectwelcomepage.h b/src/plugins/projectexplorer/projectwelcomepage.h
index a24d833328..f56b220529 100644
--- a/src/plugins/projectexplorer/projectwelcomepage.h
+++ b/src/plugins/projectexplorer/projectwelcomepage.h
@@ -75,6 +75,7 @@ signals:
private:
void openSessionAt(int index);
void openProjectAt(int index);
+ void createActions();
friend class SessionsPage;
SessionModel *m_sessionModel = nullptr;
diff --git a/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp b/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp
index 6a1e405b36..d8deb72b77 100644
--- a/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp
+++ b/src/plugins/qmakeprojectmanager/librarydetailscontroller.cpp
@@ -1134,13 +1134,14 @@ QString InternalLibraryDetailsController::snippet() const
const QString proRelavitePath = rootDir.relativeFilePath(proFile().toString());
// project for which we insert the snippet
- const Project *project = SessionManager::projectForFile(proFile());
// the build directory of the active build configuration
QDir rootBuildDir = rootDir; // If the project is unconfigured use the project dir
- if (ProjectExplorer::Target *t = project->activeTarget())
- if (ProjectExplorer::BuildConfiguration *bc = t->activeBuildConfiguration())
- rootBuildDir.setPath(bc->buildDirectory().toString());
+ if (const Project *project = SessionManager::projectForFile(proFile())) {
+ if (ProjectExplorer::Target *t = project->activeTarget())
+ if (ProjectExplorer::BuildConfiguration *bc = t->activeBuildConfiguration())
+ rootBuildDir.setPath(bc->buildDirectory().toString());
+ }
// the project for which we insert the snippet inside build tree
QFileInfo pfi(rootBuildDir.filePath(proRelavitePath));
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
index dc9af2da6c..9fe3524537 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
@@ -27,10 +27,12 @@
#include "assetslibrarydirsmodel.h"
#include "assetslibraryfilesmodel.h"
+#include <designersettings.h>
+#include <documentmanager.h>
+#include <hdrimage.h>
+#include <qmldesignerplugin.h>
#include <synchronousimagecache.h>
#include <theme.h>
-#include <hdrimage.h>
-#include <designersettings.h>
#include <coreplugin/icore.h>
@@ -100,7 +102,7 @@ void AssetsLibraryModel::toggleExpandAll(bool expand)
endResetModel();
}
-void AssetsLibraryModel::deleteFile(const QString &filePath)
+void AssetsLibraryModel::deleteFiles(const QStringList &filePaths)
{
bool askBeforeDelete = DesignerSettings::getValue(
DesignerSettingsKey::ASK_BEFORE_DELETING_ASSET).toBool();
@@ -108,7 +110,10 @@ void AssetsLibraryModel::deleteFile(const QString &filePath)
if (askBeforeDelete) {
QMessageBox msg(QMessageBox::Question, tr("Confirm Delete File"),
- tr("\"%1\" might be in use. Delete anyway?").arg(filePath),
+ tr("File%1 might be in use. Delete anyway?\n\n%2")
+ .arg(filePaths.size() > 1 ? QChar('s') : QChar())
+ .arg(filePaths.join('\n').remove(DocumentManager::currentProjectDirPath()
+ .toString().append('/'))),
QMessageBox::No | QMessageBox::Yes);
QCheckBox cb;
cb.setText(tr("Do not ask this again"));
@@ -123,14 +128,16 @@ void AssetsLibraryModel::deleteFile(const QString &filePath)
}
if (assetDelete) {
- if (!QFile::exists(filePath)) {
- QMessageBox::warning(Core::ICore::dialogParent(),
- tr("Failed to Locate File"),
- tr("Could not find \"%1\".").arg(filePath));
- } else if (!QFile::remove(filePath)) {
- QMessageBox::warning(Core::ICore::dialogParent(),
- tr("Failed to Delete File"),
- tr("Could not delete \"%1\".").arg(filePath));
+ for (const QString &filePath : filePaths) {
+ if (!QFile::exists(filePath)) {
+ QMessageBox::warning(Core::ICore::dialogParent(),
+ tr("Failed to Locate File"),
+ tr("Could not find \"%1\".").arg(filePath));
+ } else if (!QFile::remove(filePath)) {
+ QMessageBox::warning(Core::ICore::dialogParent(),
+ tr("Failed to Delete File"),
+ tr("Could not delete \"%1\".").arg(filePath));
+ }
}
}
}
@@ -298,8 +305,8 @@ void AssetsLibraryModel::setRootPath(const QString &path)
m_fileSystemWatcher->clear();
- std::function<bool(AssetsLibraryDir *, int)> parseDirRecursive;
- parseDirRecursive = [this, &parseDirRecursive](AssetsLibraryDir *currAssetsDir, int currDepth) {
+ std::function<bool(AssetsLibraryDir *, int, bool)> parseDir;
+ parseDir = [this, &parseDir](AssetsLibraryDir *currAssetsDir, int currDepth, bool recursive) {
m_fileSystemWatcher->addDirectory(currAssetsDir->dirPath(), Utils::FileSystemWatcher::WatchAllChanges);
QDir dir(currAssetsDir->dirPath());
@@ -317,20 +324,22 @@ void AssetsLibraryModel::setRootPath(const QString &path)
}
}
- dir.setNameFilters({});
- dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
- QDirIterator itDirs(dir);
-
- while (itDirs.hasNext()) {
- QDir subDir = itDirs.next();
- if (currDepth == 1 && ignoredTopLevelDirs.contains(subDir.dirName()))
- continue;
-
- auto assetsDir = new AssetsLibraryDir(subDir.path(), currDepth,
- loadExpandedState(subDir.path()), currAssetsDir);
- currAssetsDir->addDir(assetsDir);
- saveExpandedState(loadExpandedState(assetsDir->dirPath()), assetsDir->dirPath());
- isEmpty &= parseDirRecursive(assetsDir, currDepth + 1);
+ if (recursive) {
+ dir.setNameFilters({});
+ dir.setFilter(QDir::Dirs | QDir::NoDotAndDotDot);
+ QDirIterator itDirs(dir);
+
+ while (itDirs.hasNext()) {
+ QDir subDir = itDirs.next();
+ if (currDepth == 1 && ignoredTopLevelDirs.contains(subDir.dirName()))
+ continue;
+
+ auto assetsDir = new AssetsLibraryDir(subDir.path(), currDepth,
+ loadExpandedState(subDir.path()), currAssetsDir);
+ currAssetsDir->addDir(assetsDir);
+ saveExpandedState(loadExpandedState(assetsDir->dirPath()), assetsDir->dirPath());
+ isEmpty &= parseDir(assetsDir, currDepth + 1, true);
+ }
}
if (!m_searchText.isEmpty() && isEmpty)
@@ -344,7 +353,8 @@ void AssetsLibraryModel::setRootPath(const QString &path)
beginResetModel();
m_assetsDir = new AssetsLibraryDir(path, 0, true, this);
- bool isEmpty = parseDirRecursive(m_assetsDir, 1);
+ bool hasProject = !QmlDesignerPlugin::instance()->documentManager().currentProjectDirPath().isEmpty();
+ bool isEmpty = parseDir(m_assetsDir, 1, hasProject);
setIsEmpty(isEmpty);
bool noAssets = m_searchText.isEmpty() && isEmpty;
@@ -363,7 +373,7 @@ void AssetsLibraryModel::setSearchText(const QString &searchText)
}
}
-const QSet<QString> &AssetsLibraryModel::supportedSuffixes() const
+const QSet<QString> &AssetsLibraryModel::supportedSuffixes()
{
static QSet<QString> allSuffixes;
if (allSuffixes.isEmpty()) {
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h
index b27d126786..2b87359e07 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h
@@ -68,6 +68,7 @@ public:
static const QStringList &supportedAudioSuffixes();
static const QStringList &supportedVideoSuffixes();
static const QStringList &supportedTexture3DSuffixes();
+ static const QSet<QString> &supportedSuffixes();
const QSet<QString> &previewableSuffixes() const;
@@ -83,7 +84,7 @@ public:
Q_INVOKABLE void toggleExpandAll(bool expand);
Q_INVOKABLE DirExpandState getAllExpandedState() const;
- Q_INVOKABLE void deleteFile(const QString &filePath);
+ Q_INVOKABLE void deleteFiles(const QStringList &filePaths);
Q_INVOKABLE bool renameFolder(const QString &folderPath, const QString &newName);
Q_INVOKABLE void addNewFolder(const QString &folderPath);
Q_INVOKABLE void deleteFolder(const QString &folderPath);
@@ -93,7 +94,6 @@ signals:
void isEmptyChanged();
private:
- const QSet<QString> &supportedSuffixes() const;
void setIsEmpty(bool empty);
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp
index 21478fd39d..b68128099b 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.cpp
@@ -213,9 +213,24 @@ void AssetsLibraryWidget::handleAddAsset()
addResources({});
}
-void AssetsLibraryWidget::handleFilesDrop(const QStringList &filesPaths)
+void AssetsLibraryWidget::handleExtFilesDrop(const QStringList &filesPaths, const QString &targetDirPath)
{
- addResources(filesPaths);
+ QStringList assetPaths;
+ QStringList otherPaths; // as of now 3D models, and 3D Studio presentations
+ std::tie(assetPaths, otherPaths) = Utils::partition(filesPaths, [](const QString &path) {
+ QString suffix = "*." + path.split('.').last().toLower();
+ return AssetsLibraryModel::supportedSuffixes().contains(suffix);
+ });
+
+ AddFilesResult result = ModelNodeOperations::addFilesToProject(assetPaths, targetDirPath);
+ if (result == AddFilesResult::Failed) {
+ Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"),
+ tr("Could not add %1 to project.")
+ .arg(filesPaths.join(' ')));
+ }
+
+ if (!otherPaths.empty())
+ addResources(otherPaths);
}
QSet<QString> AssetsLibraryWidget::supportedDropSuffixes()
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h
index 6c27be54a6..7d3f48ef4d 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarywidget.h
@@ -80,7 +80,7 @@ public:
Q_INVOKABLE void startDragAsset(const QStringList &assetPaths, const QPointF &mousePos);
Q_INVOKABLE void handleAddAsset();
Q_INVOKABLE void handleSearchfilterChanged(const QString &filterText);
- Q_INVOKABLE void handleFilesDrop(const QStringList &filesPaths);
+ Q_INVOKABLE void handleExtFilesDrop(const QStringList &filesPaths, const QString &targetDirPath);
Q_INVOKABLE QSet<QString> supportedDropSuffixes();
signals:
diff --git a/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp b/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp
index c729fd0751..82032b3fc2 100644
--- a/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/crumblebar.cpp
@@ -83,20 +83,29 @@ void CrumbleBar::pushFile(const Utils::FilePath &fileName)
if (!m_isInternalCalled) {
crumblePath()->clear();
} else {
- CrumbleBarInfo lastElementCrumbleBarInfo = crumblePath()->dataForLastIndex().value<CrumbleBarInfo>();
+ // If the path already exists in crumblePath, pop up to first instance of that to avoid
+ // cyclical crumblePath
+ int match = -1;
+ for (int i = crumblePath()->length() - 1; i >= 0; --i) {
+ CrumbleBarInfo info = crumblePath()->dataForIndex(i).value<CrumbleBarInfo>();
+ if (info.fileName == fileName)
+ match = i;
+ }
- if (!lastElementCrumbleBarInfo.displayName.isEmpty()
- && lastElementCrumbleBarInfo.fileName == fileName)
- crumblePath()->popElement();
+ if (match != -1) {
+ for (int i = crumblePath()->length() - 1 - match; i > 0; --i)
+ crumblePath()->popElement();
+ }
}
- CrumbleBarInfo crumbleBarInfo;
- crumbleBarInfo.fileName = fileName;
-
- crumblePath()->pushElement(fileName.fileName(), QVariant::fromValue(crumbleBarInfo));
+ CrumbleBarInfo info = crumblePath()->dataForLastIndex().value<CrumbleBarInfo>();
+ if (info.fileName != fileName) {
+ CrumbleBarInfo crumbleBarInfo;
+ crumbleBarInfo.fileName = fileName;
+ crumblePath()->pushElement(fileName.fileName(), QVariant::fromValue(crumbleBarInfo));
+ }
m_isInternalCalled = false;
-
updateVisibility();
}
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
index 7924290590..f3a93650df 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
@@ -989,7 +989,7 @@ void addTabBarToStackedContainer(const SelectionContext &selectionContext)
}
-static AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory)
+AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory)
{
QString directory = AddImagesDialog::getDirectory(fileNames, defaultDirectory);
if (directory.isEmpty())
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
index f9e39c06f4..317d2d15e7 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.h
@@ -76,6 +76,7 @@ void addItemToStackedContainer(const SelectionContext &selectionContext);
void increaseIndexOfStackedContainer(const SelectionContext &selectionContext);
void decreaseIndexOfStackedContainer(const SelectionContext &selectionContext);
void addTabBarToStackedContainer(const SelectionContext &selectionContext);
+AddFilesResult addFilesToProject(const QStringList &fileNames, const QString &defaultDirectory);
AddFilesResult addImageToProject(const QStringList &fileNames, const QString &directory);
AddFilesResult addFontToProject(const QStringList &fileNames, const QString &directory);
AddFilesResult addSoundToProject(const QStringList &fileNames, const QString &directory);
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
index bb795eb40f..f664d793d8 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
@@ -118,17 +118,18 @@ void Edit3DView::renderImage3DChanged(const QImage &img)
void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState)
{
- const QString sceneKey = QStringLiteral("sceneInstanceId");
- const QString selectKey = QStringLiteral("selectionMode");
- const QString transformKey = QStringLiteral("transformMode");
- const QString perspectiveKey = QStringLiteral("usePerspective");
- const QString orientationKey = QStringLiteral("globalOrientation");
- const QString editLightKey = QStringLiteral("showEditLight");
- const QString gridKey = QStringLiteral("showGrid");
- const QString selectionBoxKey = QStringLiteral("showSelectionBox");
- const QString iconGizmoKey = QStringLiteral("showIconGizmo");
- const QString cameraFrustumKey = QStringLiteral("showCameraFrustum");
- const QString particlesPlayKey = QStringLiteral("particlePlay");
+ const QString sceneKey = QStringLiteral("sceneInstanceId");
+ const QString selectKey = QStringLiteral("selectionMode");
+ const QString transformKey = QStringLiteral("transformMode");
+ const QString perspectiveKey = QStringLiteral("usePerspective");
+ const QString orientationKey = QStringLiteral("globalOrientation");
+ const QString editLightKey = QStringLiteral("showEditLight");
+ const QString gridKey = QStringLiteral("showGrid");
+ const QString selectionBoxKey = QStringLiteral("showSelectionBox");
+ const QString iconGizmoKey = QStringLiteral("showIconGizmo");
+ const QString cameraFrustumKey = QStringLiteral("showCameraFrustum");
+ const QString particleEmitterKey = QStringLiteral("showParticleEmitter");
+ const QString particlesPlayKey = QStringLiteral("particlePlay");
if (sceneState.contains(sceneKey)) {
qint32 newActiveScene = sceneState[sceneKey].value<qint32>();
@@ -188,6 +189,11 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState)
else
m_showCameraFrustumAction->action()->setChecked(false);
+ if (sceneState.contains(particleEmitterKey))
+ m_showParticleEmitterAction->action()->setChecked(sceneState[particleEmitterKey].toBool());
+ else
+ m_showParticleEmitterAction->action()->setChecked(false);
+
if (sceneState.contains(particlesPlayKey))
m_particlesPlayAction->action()->setChecked(sceneState[particlesPlayKey].toBool());
else
@@ -352,6 +358,12 @@ void Edit3DView::createEdit3DActions()
QKeySequence(Qt::Key_C), true, false, {}, {}, nullptr,
QCoreApplication::translate("ShowCameraFrustumAction", "Toggle between always showing the camera frustum visualization and only showing it when the camera is selected."));
+ m_showParticleEmitterAction = new Edit3DAction(
+ QmlDesigner::Constants::EDIT3D_EDIT_SHOW_PARTICLE_EMITTER, View3DActionCommand::ShowParticleEmitter,
+ QCoreApplication::translate("ShowParticleEmitterAction", "Always Show Particle Emitters"),
+ QKeySequence(Qt::Key_M), true, false, {}, {}, nullptr,
+ QCoreApplication::translate("ShowParticleEmitterAction", "Toggle between always showing the particle emitter visualization and only showing it when the emitter is selected."));
+
SelectionContextOperation resetTrigger = [this](const SelectionContext &) {
m_particlesPlayAction->action()->setEnabled(particlemode);
m_particlesRestartAction->action()->setEnabled(particlemode);
@@ -390,13 +402,13 @@ void Edit3DView::createEdit3DActions()
= new Edit3DAction(
QmlDesigner::Constants::EDIT3D_PARTICLES_PLAY, View3DActionCommand::ParticlesPlay,
QCoreApplication::translate("ParticlesPlayAction", "Play Particles"),
- QKeySequence(Qt::Key_W), true, true, Icons::EDIT3D_PARTICLE_PLAY.icon(),
+ QKeySequence(Qt::Key_Comma), true, true, Icons::EDIT3D_PARTICLE_PLAY.icon(),
Icons::EDIT3D_PARTICLE_PAUSE.icon(), particlesPlayTrigger);
m_particlesRestartAction
= new Edit3DAction(
QmlDesigner::Constants::EDIT3D_PARTICLES_RESTART, View3DActionCommand::ParticlesRestart,
QCoreApplication::translate("ParticlesRestartAction", "Restart Particles"),
- QKeySequence(Qt::Key_E), false, false, Icons::EDIT3D_PARTICLE_RESTART.icon(),
+ QKeySequence(Qt::Key_Slash), false, false, Icons::EDIT3D_PARTICLE_RESTART.icon(),
Icons::EDIT3D_PARTICLE_RESTART.icon());
m_particlesPlayAction->action()->setEnabled(particlemode);
m_particlesRestartAction->action()->setEnabled(particlemode);
@@ -458,6 +470,7 @@ void Edit3DView::createEdit3DActions()
m_visibilityToggleActions << m_showSelectionBoxAction;
m_visibilityToggleActions << m_showIconGizmoAction;
m_visibilityToggleActions << m_showCameraFrustumAction;
+ m_visibilityToggleActions << m_showParticleEmitterAction;
}
QVector<Edit3DAction *> Edit3DView::leftActions() const
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h
index daddb84d6c..40e2170873 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h
@@ -102,6 +102,7 @@ private:
Edit3DAction *m_showSelectionBoxAction = nullptr;
Edit3DAction *m_showIconGizmoAction = nullptr;
Edit3DAction *m_showCameraFrustumAction = nullptr;
+ Edit3DAction *m_showParticleEmitterAction = nullptr;
Edit3DAction *m_resetAction = nullptr;
Edit3DAction *m_particleViewModeAction = nullptr;
Edit3DAction *m_particlesPlayAction = nullptr;
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
index 945820d913..72cb0ec21c 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
@@ -79,6 +79,7 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) :
auto handleActions = [this, &context](const QVector<Edit3DAction *> &actions, QMenu *menu, bool left) {
bool previousWasSeparator = true;
QActionGroup *group = nullptr;
+ QActionGroup *proxyGroup = nullptr;
for (auto action : actions) {
if (action) {
QAction *a = action->action();
@@ -99,6 +100,8 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) :
Core::Command *command = Core::ActionManager::registerAction(
a, action->menuId().constData(), context);
command->setDefaultKeySequence(a->shortcut());
+ if (proxyGroup)
+ proxyGroup->addAction(command->action());
// Menu actions will have custom tooltips
if (menu)
a->setToolTip(command->stringWithAppendedShortcut(a->toolTip()));
@@ -110,9 +113,11 @@ Edit3DWidget::Edit3DWidget(Edit3DView *view) :
} else {
if (previousWasSeparator) {
group = new QActionGroup(this);
+ proxyGroup = new QActionGroup(this);
previousWasSeparator = false;
} else {
group = nullptr;
+ proxyGroup = nullptr;
auto separator = new QAction(this);
separator->setSeparator(true);
if (menu) {
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecacheconnectionmanager.cpp b/src/plugins/qmldesigner/designercore/imagecache/imagecacheconnectionmanager.cpp
index a33da7df5d..d1cd65b4c4 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecacheconnectionmanager.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecacheconnectionmanager.cpp
@@ -41,6 +41,8 @@ bool ImageCacheConnectionManager::waitForCapturedData()
disconnect(connections().front().socket.get(), &QIODevice::readyRead, nullptr, nullptr);
while (!m_capturedDataArrived) {
+ if (!(connections().front().socket))
+ return false;
bool dataArrived = connections().front().socket->waitForReadyRead(10000);
if (!dataArrived)
diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
index 48391fe4b9..547d7ad8a6 100644
--- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
@@ -555,6 +555,13 @@ void NodeInstanceView::nodeReparented(const ModelNode &node, const NodeAbstractP
updateChildren(newPropertyParent);
m_nodeInstanceServer->reparentInstances(
createReparentInstancesCommand(node, newPropertyParent, oldPropertyParent));
+
+ // Reset puppet when particle emitter is reparented to work around issue in
+ // autodetecting the particle system it belongs to. QTBUG-101157
+ if (node.isSubclassOf("QtQuick.Particles3D.ParticleEmitter3D")
+ && node.property("system").toBindingProperty().expression().isEmpty()) {
+ resetPuppet();
+ }
}
}
diff --git a/src/plugins/qmldesigner/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/designercore/model/modelnode.cpp
index 98f4f31085..288d9dadc4 100644
--- a/src/plugins/qmldesigner/designercore/model/modelnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/modelnode.cpp
@@ -195,7 +195,9 @@ static bool isIdToAvoid(const QString& id)
"enabled",
"anchors",
"texture",
- "shaderInfo"
+ "shaderInfo",
+ "sprite",
+ "spriteSequence"
};
return ids.contains(id);
diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h
index 03c2f42cca..fc394ae089 100644
--- a/src/plugins/qmldesigner/qmldesignerconstants.h
+++ b/src/plugins/qmldesigner/qmldesignerconstants.h
@@ -68,6 +68,7 @@ const char EDIT3D_EDIT_SHOW_GRID[] = "QmlDesigner.Editor3D.ToggleGrid";
const char EDIT3D_EDIT_SHOW_SELECTION_BOX[] = "QmlDesigner.Editor3D.ToggleSelectionBox";
const char EDIT3D_EDIT_SHOW_ICON_GIZMO[] = "QmlDesigner.Editor3D.ToggleIconGizmo";
const char EDIT3D_EDIT_SHOW_CAMERA_FRUSTUM[] = "QmlDesigner.Editor3D.ToggleCameraFrustum";
+const char EDIT3D_EDIT_SHOW_PARTICLE_EMITTER[] = "QmlDesigner.Editor3D.ToggleParticleEmitter";
const char EDIT3D_RESET_VIEW[] = "QmlDesigner.Editor3D.ResetView";
const char EDIT3D_PARTICLE_MODE[] = "QmlDesigner.Editor3D.ParticleViewModeToggle";
const char EDIT3D_PARTICLES_PLAY[] = "QmlDesigner.Editor3D.ParticlesPlay";
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp
index 2a25819d6e..b9ea5c5107 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.cpp
+++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp
@@ -291,16 +291,15 @@ bool QmlDesignerPlugin::delayedInitialize()
d->settings.fromSettings(Core::ICore::settings());
d->viewManager.registerView(std::make_unique<QmlDesigner::Internal::ConnectionView>());
- if (DesignerSettings::getValue(DesignerSettingsKey::ENABLE_TIMELINEVIEW).toBool()) {
- auto timelineView = d->viewManager.registerView(std::make_unique<QmlDesigner::TimelineView>());
- timelineView->registerActions();
- d->viewManager.registerView(std::make_unique<QmlDesigner::CurveEditorView>());
+ auto timelineView = d->viewManager.registerView(std::make_unique<QmlDesigner::TimelineView>());
+ timelineView->registerActions();
- auto eventlistView = d->viewManager.registerView(
- std::make_unique<QmlDesigner::EventListPluginView>());
- eventlistView->registerActions();
- }
+ d->viewManager.registerView(std::make_unique<QmlDesigner::CurveEditorView>());
+
+ auto eventlistView = d->viewManager.registerView(
+ std::make_unique<QmlDesigner::EventListPluginView>());
+ eventlistView->registerActions();
auto transitionEditorView = d->viewManager.registerView(
std::make_unique<QmlDesigner::TransitionEditorView>());
@@ -316,8 +315,12 @@ bool QmlDesignerPlugin::delayedInitialize()
emitUsageStatistics("StandaloneMode");
if (QmlProjectManager::QmlProject::isQtDesignStudioStartedFromQtC())
emitUsageStatistics("QDSlaunchedFromQtC");
+ emitUsageStatistics("QDSstartupCount");
}
+ if (QmlProjectManager::QmlProject::isQtDesignStudio())
+ d->mainWidget.initialize();
+
return true;
}
@@ -329,9 +332,6 @@ void QmlDesignerPlugin::extensionsInitialized()
integrateIntoQtCreator(&d->mainWidget);
});
- if (QmlProjectManager::QmlProject::isQtDesignStudio())
- d->mainWidget.initialize();
-
auto &actionManager = d->viewManager.designerActionManager();
actionManager.createDefaultDesignerActions();
actionManager.createDefaultAddResourceHandler();
@@ -339,6 +339,14 @@ void QmlDesignerPlugin::extensionsInitialized()
actionManager.polishActions();
}
+ExtensionSystem::IPlugin::ShutdownFlag QmlDesignerPlugin::aboutToShutdown()
+{
+ if (QmlProjectManager::QmlProject::isQtDesignStudio())
+ emitUsageStatistics("QDSstartupCount");
+
+ return SynchronousShutdown;
+}
+
static QStringList allUiQmlFilesforCurrentProject(const Utils::FilePath &fileName)
{
QStringList list;
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.h b/src/plugins/qmldesigner/qmldesignerplugin.h
index 22800aa045..0cd21bd294 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.h
+++ b/src/plugins/qmldesigner/qmldesignerplugin.h
@@ -60,6 +60,7 @@ public:
bool initialize(const QStringList &arguments, QString *errorMessage) final;
bool delayedInitialize() final;
void extensionsInitialized() final;
+ ShutdownFlag aboutToShutdown() final;
static QmlDesignerPlugin *instance();
diff --git a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp
index 93b630c3eb..e163165f96 100644
--- a/src/plugins/qtsupport/gettingstartedwelcomepage.cpp
+++ b/src/plugins/qtsupport/gettingstartedwelcomepage.cpp
@@ -326,8 +326,9 @@ public:
void onTagClicked(const QString &tag)
{
- QString text = m_searcher->text();
- m_searcher->setText(text + QString("tag:\"%1\" ").arg(tag));
+ const QString text = m_searcher->text();
+ m_searcher->setText((text.startsWith("tag:\"") ? text.trimmed() + " " : QString())
+ + QString("tag:\"%1\" ").arg(tag));
}
const bool m_isExamples;
diff --git a/src/plugins/studiowelcome/CMakeLists.txt b/src/plugins/studiowelcome/CMakeLists.txt
index a8b92ab1f8..209bb80b01 100644
--- a/src/plugins/studiowelcome/CMakeLists.txt
+++ b/src/plugins/studiowelcome/CMakeLists.txt
@@ -14,6 +14,7 @@ add_qtc_plugin(StudioWelcome
createproject.cpp createproject.h
wizardhandler.cpp wizardhandler.h
recentpresets.cpp recentpresets.h
+ userpresets.cpp userpresets.h
screensizemodel.h
algorithm.h
stylemodel.h stylemodel.cpp
diff --git a/src/plugins/studiowelcome/presetmodel.cpp b/src/plugins/studiowelcome/presetmodel.cpp
index b8db0503f2..cc06bf59f5 100644
--- a/src/plugins/studiowelcome/presetmodel.cpp
+++ b/src/plugins/studiowelcome/presetmodel.cpp
@@ -25,52 +25,132 @@
#include "presetmodel.h"
#include <utils/optional.h>
-#include <utils/qtcassert.h>
#include "algorithm.h"
using namespace StudioWelcome;
+constexpr int NameRole = Qt::UserRole;
+constexpr int ScreenSizeRole = Qt::UserRole + 1;
+constexpr int IsUserPresetRole = Qt::UserRole + 2;
+
+static const QString RecentsTabName = QObject::tr("Recents");
+static const QString CustomTabName = QObject::tr("Custom");
+
/****************** PresetData ******************/
-void PresetData::setData(const PresetsByCategory &presetsByCategory,
- const std::vector<RecentPreset> &loadedRecents)
+
+QString PresetData::recentsTabName()
{
- QTC_ASSERT(!presetsByCategory.empty(), return);
- m_recents = loadedRecents;
+ return RecentsTabName;
+}
- if (!m_recents.empty()) {
- m_categories.push_back("Recents");
- m_presets.push_back({});
- }
+void PresetData::setData(const PresetsByCategory &presetsByCategory,
+ const std::vector<UserPresetData> &userPresetsData,
+ const std::vector<RecentPresetData> &loadedRecentsData)
+{
+ QTC_ASSERT(!presetsByCategory.empty(), return );
+ m_recents = loadedRecentsData;
+ m_userPresets = userPresetsData;
for (auto &[id, category] : presetsByCategory) {
m_categories.push_back(category.name);
m_presets.push_back(category.items);
}
- PresetItems presets = Utils::flatten(m_presets);
+ PresetItems wizardPresets = Utils::flatten(m_presets);
+
+ PresetItems userPresetItems = makeUserPresets(wizardPresets);
+ if (!userPresetItems.empty()) {
+ m_categories.push_back(CustomTabName);
+ m_presets.push_back(userPresetItems);
+ }
- std::vector<PresetItem> recentPresets = makeRecentPresets(presets);
+ PresetItems allWizardPresets = std::move(wizardPresets);
+ Utils::concat(allWizardPresets, userPresetItems);
- if (!m_recents.empty())
- m_presets[0] = recentPresets;
+ PresetItems recentPresets = makeRecentPresets(allWizardPresets);
+ if (!recentPresets.empty()) {
+ Utils::prepend(m_categories, RecentsTabName);
+ Utils::prepend(m_presets, recentPresets);
+ }
+
+ m_presetsByCategory = presetsByCategory;
}
-std::vector<PresetItem> PresetData::makeRecentPresets(const PresetItems &wizardPresets)
+void PresetData::reload(const std::vector<UserPresetData> &userPresetsData,
+ const std::vector<RecentPresetData> &loadedRecentsData)
{
- static const PresetItem empty;
+ m_categories.clear();
+ m_presets.clear();
+ m_recents.clear();
+ m_userPresets.clear();
+ setData(m_presetsByCategory, userPresetsData, loadedRecentsData);
+}
+std::shared_ptr<PresetItem> PresetData::findPresetItemForUserPreset(const UserPresetData &preset,
+ const PresetItems &wizardPresets)
+{
+ return Utils::findOrDefault(wizardPresets, [&preset](const std::shared_ptr<PresetItem> &item) {
+ return item->wizardName == preset.wizardName && item->categoryId == preset.categoryId;
+ });
+}
+
+PresetItems PresetData::makeUserPresets(const PresetItems &wizardPresets)
+{
PresetItems result;
- for (const RecentPreset &recent : m_recents) {
- auto item = Utils::findOptional(wizardPresets, [&recent](const PresetItem &item) {
- return item.categoryId == std::get<0>(recent) && item.name == std::get<1>(recent);
- });
+ for (const UserPresetData &userPresetData : m_userPresets) {
+ std::shared_ptr<PresetItem> foundPreset = findPresetItemForUserPreset(userPresetData,
+ wizardPresets);
+ if (!foundPreset)
+ continue;
+
+ auto presetItem = std::make_shared<UserPresetItem>();
+
+ presetItem->categoryId = userPresetData.categoryId;
+ presetItem->wizardName = userPresetData.wizardName;
+ presetItem->screenSizeName = userPresetData.screenSize;
- if (item) {
- item->screenSizeName = std::get<2>(recent);
- result.push_back(item.value());
+ presetItem->userName = userPresetData.name;
+ presetItem->qtVersion = userPresetData.qtVersion;
+ presetItem->styleName = userPresetData.styleName;
+ presetItem->useQtVirtualKeyboard = userPresetData.useQtVirtualKeyboard;
+
+ presetItem->create = foundPreset->create;
+ presetItem->description = foundPreset->description;
+ presetItem->fontIconCode = foundPreset->fontIconCode;
+ presetItem->qmlPath = foundPreset->qmlPath;
+
+ result.push_back(presetItem);
+ }
+
+ return result;
+}
+
+std::shared_ptr<PresetItem> PresetData::findPresetItemForRecent(const RecentPresetData &recent, const PresetItems &wizardPresets)
+{
+ return Utils::findOrDefault(wizardPresets, [&recent](const std::shared_ptr<PresetItem> &item) {
+ bool sameName = item->categoryId == recent.category
+ && item->displayName() == recent.presetName;
+
+ bool sameType = (recent.isUserPreset ? item->isUserPreset() : !item->isUserPreset());
+
+ return sameName && sameType;
+ });
+}
+
+PresetItems PresetData::makeRecentPresets(const PresetItems &wizardPresets)
+{
+ PresetItems result;
+
+ for (const RecentPresetData &recent : m_recents) {
+ std::shared_ptr<PresetItem> preset = findPresetItemForRecent(recent, wizardPresets);
+
+ if (preset) {
+ auto clone = std::shared_ptr<PresetItem>{preset->clone()};
+ clone->screenSizeName = recent.sizeName;
+ result.push_back(clone);
}
}
@@ -86,8 +166,8 @@ BasePresetModel::BasePresetModel(const PresetData *data, QObject *parent)
QHash<int, QByteArray> BasePresetModel::roleNames() const
{
- QHash<int, QByteArray> roleNames;
- roleNames[Qt::UserRole] = "name";
+ static QHash<int, QByteArray> roleNames{{NameRole, "name"},
+ {ScreenSizeRole, "resolution"}};
return roleNames;
}
@@ -97,8 +177,9 @@ PresetCategoryModel::PresetCategoryModel(const PresetData *data, QObject *parent
: BasePresetModel(data, parent)
{}
-int PresetCategoryModel::rowCount(const QModelIndex &) const
+int PresetCategoryModel::rowCount(const QModelIndex &parent) const
{
+ Q_UNUSED(parent)
return static_cast<int>(m_data->categories().size());
}
@@ -116,9 +197,9 @@ PresetModel::PresetModel(const PresetData *data, QObject *parent)
QHash<int, QByteArray> PresetModel::roleNames() const
{
- QHash<int, QByteArray> roleNames;
- roleNames[Qt::UserRole] = "name";
- roleNames[Qt::UserRole + 1] = "size";
+ static QHash<int, QByteArray> roleNames{{NameRole, "name"},
+ {ScreenSizeRole, "resolution"},
+ {IsUserPresetRole, "isUserPreset"}};
return roleNames;
}
@@ -132,9 +213,16 @@ int PresetModel::rowCount(const QModelIndex &) const
QVariant PresetModel::data(const QModelIndex &index, int role) const
{
- Q_UNUSED(role)
- PresetItem preset = presetsOfCurrentCategory().at(index.row());
- return QVariant::fromValue<QString>(preset.name + "\n" + preset.screenSizeName);
+ std::shared_ptr<PresetItem> preset = presetsOfCurrentCategory().at(index.row());
+
+ if (role == NameRole)
+ return preset->displayName();
+ else if (role == ScreenSizeRole)
+ return preset->screenSize();
+ else if (role == IsUserPresetRole)
+ return preset->isUserPreset();
+ else
+ return {};
}
void PresetModel::setPage(int index)
@@ -148,7 +236,7 @@ void PresetModel::setPage(int index)
QString PresetModel::fontIconCode(int index) const
{
- Utils::optional<PresetItem> presetItem = preset(index);
+ std::shared_ptr<PresetItem> presetItem = preset(index);
if (!presetItem)
return {};
diff --git a/src/plugins/studiowelcome/presetmodel.h b/src/plugins/studiowelcome/presetmodel.h
index a1c9b0e7d2..e4c6712b81 100644
--- a/src/plugins/studiowelcome/presetmodel.h
+++ b/src/plugins/studiowelcome/presetmodel.h
@@ -31,8 +31,10 @@
#include <utils/filepath.h>
#include <utils/optional.h>
+#include <utils/qtcassert.h>
#include "recentpresets.h"
+#include "userpresets.h"
namespace Utils {
class Wizard;
@@ -40,38 +42,115 @@ class Wizard;
namespace StudioWelcome {
+struct UserPresetItem;
+
struct PresetItem
{
- QString name;
+ PresetItem() = default;
+ PresetItem(const QString &wizardName, const QString &category, const QString &sizeName = "")
+ : wizardName{wizardName}
+ , categoryId{category}
+ , screenSizeName{sizeName}
+ {}
+
+ virtual ~PresetItem() {}
+ virtual QString displayName() const { return wizardName; }
+ virtual QString screenSize() const { return screenSizeName; }
+ virtual std::unique_ptr<PresetItem> clone() const
+ {
+ return std::unique_ptr<PresetItem>{new PresetItem{*this}};
+ }
+
+ virtual bool isUserPreset() const { return false; }
+ virtual UserPresetItem *asUserPreset() { return nullptr; }
+ std::function<Utils::Wizard *(const Utils::FilePath &path)> create;
+
+public:
+ QString wizardName;
QString categoryId;
QString screenSizeName;
QString description;
QUrl qmlPath;
QString fontIconCode;
- std::function<Utils::Wizard *(const Utils::FilePath &path)> create;
};
+struct UserPresetItem : public PresetItem
+{
+ UserPresetItem() = default;
+ UserPresetItem(const QString &userName,
+ const QString &wizardName,
+ const QString &category,
+ const QString &sizeName = "")
+ : PresetItem{wizardName, category, sizeName}
+ , userName{userName}
+ {}
+
+ QString displayName() const override { return userName; }
+ std::unique_ptr<PresetItem> clone() const override
+ {
+ return std::unique_ptr<PresetItem>{new UserPresetItem{*this}};
+ }
+
+ bool isUserPreset() const override { return true; }
+ UserPresetItem *asUserPreset() override { return this; }
+
+ bool isValid() const
+ {
+ return !categoryId.isEmpty() && !wizardName.isEmpty() && !userName.isEmpty();
+ }
+
+public:
+ QString userName;
+ bool useQtVirtualKeyboard;
+ QString qtVersion;
+ QString styleName;
+};
+
+inline QDebug &operator<<(QDebug &d, const UserPresetItem &item);
+
inline QDebug &operator<<(QDebug &d, const PresetItem &item)
{
- d << "name=" << item.name;
+ d << "wizardName=" << item.wizardName;
d << "; category = " << item.categoryId;
d << "; size = " << item.screenSizeName;
+ if (item.isUserPreset())
+ d << "; " << (UserPresetItem &) item;
+
+ return d;
+}
+
+inline QDebug &operator<<(QDebug &d, const UserPresetItem &item)
+{
+ d << "userName=" << item.userName;
+
return d;
}
inline bool operator==(const PresetItem &lhs, const PresetItem &rhs)
{
- return lhs.categoryId == rhs.categoryId && lhs.name == rhs.name;
+ return lhs.categoryId == rhs.categoryId && lhs.wizardName == rhs.wizardName;
}
+using PresetItems = std::vector<std::shared_ptr<PresetItem>>;
+
struct WizardCategory
{
QString id;
QString name;
- std::vector<PresetItem> items;
+ PresetItems items;
};
+inline QDebug &operator<<(QDebug &d, const std::shared_ptr<PresetItem> &preset)
+{
+ if (preset)
+ d << *preset;
+ else
+ d << "(null)";
+
+ return d;
+}
+
inline QDebug &operator<<(QDebug &d, const WizardCategory &cat)
{
d << "id=" << cat.id;
@@ -82,7 +161,6 @@ inline QDebug &operator<<(QDebug &d, const WizardCategory &cat)
}
using PresetsByCategory = std::map<QString, WizardCategory>;
-using PresetItems = std::vector<PresetItem>;
using Categories = std::vector<QString>;
/****************** PresetData ******************/
@@ -90,18 +168,30 @@ using Categories = std::vector<QString>;
class PresetData
{
public:
- void setData(const PresetsByCategory &presets, const std::vector<RecentPreset> &recents);
+ void reload(const std::vector<UserPresetData> &userPresets,
+ const std::vector<RecentPresetData> &loadedRecents);
+ void setData(const PresetsByCategory &presets,
+ const std::vector<UserPresetData> &userPresets,
+ const std::vector<RecentPresetData> &recents);
const std::vector<PresetItems> &presets() const { return m_presets; }
const Categories &categories() const { return m_categories; }
+ static QString recentsTabName();
+
private:
- std::vector<PresetItem> makeRecentPresets(const PresetItems &wizardPresets);
+ PresetItems makeRecentPresets(const PresetItems &wizardPresets);
+ PresetItems makeUserPresets(const PresetItems &wizardPresets);
+
+ std::shared_ptr<PresetItem> findPresetItemForUserPreset(const UserPresetData &preset, const PresetItems &wizardPresets);
+ std::shared_ptr<PresetItem> findPresetItemForRecent(const RecentPresetData &recent, const PresetItems &wizardPresets);
private:
std::vector<PresetItems> m_presets;
Categories m_categories;
- std::vector<RecentPreset> m_recents;
+ std::vector<RecentPresetData> m_recents;
+ std::vector<UserPresetData> m_userPresets;
+ PresetsByCategory m_presetsByCategory;
};
/****************** PresetCategoryModel ******************/
@@ -149,14 +239,14 @@ public:
int page() const { return static_cast<int>(m_page); }
- Utils::optional<PresetItem> preset(size_t selection) const
+ const std::shared_ptr<PresetItem> preset(size_t selection) const
{
auto presets = m_data->presets();
if (presets.empty())
return {};
if (m_page < presets.size()) {
- const std::vector<PresetItem> presetsOfCategory = presets.at(m_page);
+ const PresetItems presetsOfCategory = presets.at(m_page);
if (selection < presetsOfCategory.size())
return presets.at(m_page).at(selection);
}
@@ -166,8 +256,10 @@ public:
bool empty() const { return m_data->presets().empty(); }
private:
- const std::vector<PresetItem> presetsOfCurrentCategory() const
+ const PresetItems presetsOfCurrentCategory() const
{
+ QTC_ASSERT(m_page < m_data->presets().size(), return {});
+
return m_data->presets().at(m_page);
}
diff --git a/src/plugins/studiowelcome/qdsnewdialog.cpp b/src/plugins/studiowelcome/qdsnewdialog.cpp
index 0324a7de93..527204c80e 100644
--- a/src/plugins/studiowelcome/qdsnewdialog.cpp
+++ b/src/plugins/studiowelcome/qdsnewdialog.cpp
@@ -76,22 +76,14 @@ QdsNewDialog::QdsNewDialog(QWidget *parent)
{
setParent(m_dialog);
- m_dialog->rootContext()->setContextProperties(QVector<QQmlContext::PropertyPair>{
- {{"categoryModel"}, QVariant::fromValue(m_categoryModel.data())},
- {{"presetModel"}, QVariant::fromValue(m_presetModel.data())},
- {{"screenSizeModel"}, QVariant::fromValue(m_screenSizeModel.data())},
- {{"styleModel"}, QVariant::fromValue(m_styleModel.data())},
- {{"dialogBox"}, QVariant::fromValue(this)},
- });
-
m_dialog->setResizeMode(QQuickWidget::SizeRootObjectToView); // SizeViewToRootObject
m_dialog->engine()->addImageProvider(QStringLiteral("newprojectdialog_library"),
new Internal::NewProjectDialogImageProvider());
QmlDesigner::Theme::setupTheme(m_dialog->engine());
+ qmlRegisterSingletonInstance<QdsNewDialog>("BackendApi", 1, 0, "BackendApi", this);
m_dialog->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources/imports").toString());
m_dialog->engine()->addImportPath(Core::ICore::resourcePath("qmldesigner/newprojectdialog/imports").toString());
- QString sourcesPath = qmlPath();
- m_dialog->setSource(QUrl::fromLocalFile(sourcesPath));
+ m_dialog->setSource(QUrl::fromLocalFile(qmlPath()));
m_dialog->setWindowModality(Qt::ApplicationModal);
m_dialog->setWindowFlags(Qt::Dialog);
@@ -114,7 +106,7 @@ QdsNewDialog::QdsNewDialog(QWidget *parent)
});
QObject::connect(m_styleModel.data(), &StyleModel::modelAboutToBeReset, this, [this]() {
- this->m_qmlStyleIndex = -1;
+ m_qmlStyleIndex = -1;
});
}
@@ -188,18 +180,47 @@ void QdsNewDialog::onWizardCreated(QStandardItemModel *screenSizeModel, QStandar
m_screenSizeModel->setBackendModel(screenSizeModel);
m_styleModel->setBackendModel(styleModel);
+ auto userPreset = m_currentPreset->asUserPreset();
+
if (m_qmlDetailsLoaded) {
- updateScreenSizes();
+ if (m_currentPreset->isUserPreset()) {
+ if (m_wizard.haveVirtualKeyboard())
+ setUseVirtualKeyboard(userPreset->useQtVirtualKeyboard);
+
+ if (m_wizard.haveTargetQtVersion()) {
+ int index = m_wizard.targetQtVersionIndex(userPreset->qtVersion);
+ if (index != -1)
+ setTargetQtVersionIndex(index);
+ }
+ } else {
+ if (m_wizard.haveTargetQtVersion()) {
+ int index = m_wizard.targetQtVersionIndex();
+ if (index != -1)
+ setTargetQtVersionIndex(index);
+ }
+ }
emit haveVirtualKeyboardChanged();
emit haveTargetQtVersionChanged();
+ updateScreenSizes();
+
setProjectName(m_qmlProjectName);
setProjectLocation(m_qmlProjectLocation.toString());
}
- if (m_qmlStylesLoaded)
+ if (m_qmlStylesLoaded && m_wizard.haveStyleModel()) {
+ if (m_currentPreset->isUserPreset()) {
+ int index = m_wizard.styleIndex(userPreset->styleName);
+ if (index != -1)
+ setStyleIndex(index);
+ } else {
+ /* NOTE: For a builtin preset, we don't need to set style index. That's because defaults
+ * will be loaded from the backend Wizard.
+ */
+ }
m_styleModel->reset();
+ }
}
QString QdsNewDialog::currentPresetQmlPath() const
@@ -221,10 +242,19 @@ int QdsNewDialog::screenSizeIndex() const
return m_wizard.screenSizeIndex();
}
-void QdsNewDialog::setTargetQtVersion(int index)
+void QdsNewDialog::setTargetQtVersionIndex(int index)
+{
+ if (m_qmlTargetQtVersionIndex != index) {
+ m_wizard.setTargetQtVersionIndex(index);
+ m_qmlTargetQtVersionIndex = index;
+
+ emit targetQtVersionIndexChanged();
+ }
+}
+
+int QdsNewDialog::getTargetQtVersionIndex() const
{
- m_wizard.setTargetQtVersionIndex(index);
- m_qmlTargetQtVersionIndex = index;
+ return m_qmlTargetQtVersionIndex;
}
void QdsNewDialog::setStyleIndex(int index)
@@ -267,6 +297,14 @@ int QdsNewDialog::getStyleIndex() const
return m_styleModel->actualIndex(m_qmlStyleIndex);
}
+void QdsNewDialog::setUseVirtualKeyboard(bool value)
+{
+ if (m_qmlUseVirtualKeyboard != value) {
+ m_qmlUseVirtualKeyboard = value;
+ emit useVirtualKeyboardChanged();
+ }
+}
+
void QdsNewDialog::setWizardFactories(QList<Core::IWizardFactory *> factories_,
const Utils::FilePath &defaultLocation,
const QVariantMap &)
@@ -275,8 +313,9 @@ void QdsNewDialog::setWizardFactories(QList<Core::IWizardFactory *> factories_,
WizardFactories factories{factories_, m_dialog, platform};
- std::vector<RecentPreset> recents = m_recentsStore.fetchAll();
- m_presetData.setData(factories.presetsGroupedByCategory(), recents);
+ std::vector<RecentPresetData> recents = m_recentsStore.fetchAll();
+ std::vector<UserPresetData> userPresets = m_userPresetsStore.fetchAll();
+ m_presetData.setData(factories.presetsGroupedByCategory(), userPresets, recents);
m_categoryModel->reset();
m_presetModel->reset();
@@ -296,12 +335,50 @@ void QdsNewDialog::setWizardFactories(QList<Core::IWizardFactory *> factories_,
m_qmlProjectLocation = Utils::FilePath::fromString(QDir::toNativeSeparators(projectLocation.toString()));
emit projectLocationChanged(); // So that QML knows to update the field
+ /* NOTE:
+ * Here we expect that details are loaded && that styles are loaded. We use the
+ * functionality below to update the state of the first item that is selected right when
+ * the dialog pops up. Otherwise, relying solely on onWizardCreated is not useful, since
+ * for the dialog popup, that wizard is created before details & styles are loaded.
+ *
+ * It might be a better alternative to receive notifications from QML in the cpp file, that
+ * style is loaded, and that details is loaded, and do updates from there. But, if we handle
+ * those events, they may be called before the wizard is created - so we would need to make
+ * sure that all events have occurred before we go ahead and configure the wizard.
+ */
+
+ auto userPreset = m_currentPreset->asUserPreset();
+
if (m_qmlDetailsLoaded) {
updateScreenSizes();
+
+ if (m_wizard.haveTargetQtVersion()) {
+ int index = (userPreset ? m_wizard.targetQtVersionIndex(userPreset->qtVersion)
+ : m_wizard.targetQtVersionIndex());
+ if (index != -1)
+ setTargetQtVersionIndex(index);
+ }
+
+ if (m_wizard.haveVirtualKeyboard() && userPreset)
+ setUseVirtualKeyboard(userPreset->useQtVirtualKeyboard);
+
+ emit haveVirtualKeyboardChanged();
+ emit haveTargetQtVersionChanged();
}
- if (m_qmlStylesLoaded)
+ if (m_qmlStylesLoaded && m_wizard.haveStyleModel()) {
+ if (userPreset) {
+ int index = m_wizard.styleIndex(userPreset->styleName);
+ if (index != -1)
+ setStyleIndex(index);
+ }
m_styleModel->reset();
+ }
+}
+
+QString QdsNewDialog::recentsTabName() const
+{
+ return PresetData::recentsTabName();
}
QString QdsNewDialog::qmlPath() const
@@ -338,10 +415,10 @@ void QdsNewDialog::accept()
.withTargetQtVersion(m_qmlTargetQtVersionIndex)
.execute();
- PresetItem item = m_wizard.preset();
+ std::shared_ptr<PresetItem> item = m_wizard.preset();
QString customSizeName = m_qmlCustomWidth + " x " + m_qmlCustomHeight;
- m_recentsStore.add(item.categoryId, item.name, customSizeName);
+ m_recentsStore.add(item->categoryId, item->displayName(), customSizeName, item->isUserPreset());
m_dialog->close();
m_dialog->deleteLater();
@@ -355,6 +432,7 @@ void QdsNewDialog::reject()
m_wizard.destroyWizard();
m_dialog->close();
+ m_dialog = nullptr;
}
QString QdsNewDialog::chooseProjectLocation()
@@ -375,7 +453,76 @@ void QdsNewDialog::setSelectedPreset(int selection)
setProjectDescription(m_currentPreset->description);
m_presetPage = m_presetModel->page();
- m_wizard.reset(m_currentPreset.value(), m_qmlSelectedPreset);
+ m_wizard.reset(m_currentPreset, m_qmlSelectedPreset);
}
}
}
+
+void QdsNewDialog::savePresetDialogAccept()
+{
+ QString screenSize = m_qmlCustomWidth + " x " + m_qmlCustomHeight;
+ QString targetQtVersion = "";
+ QString styleName = "";
+ bool useVirtualKeyboard = false;
+
+ if (m_wizard.haveTargetQtVersion())
+ targetQtVersion = m_wizard.targetQtVersionName(m_qmlTargetQtVersionIndex);
+
+ if (m_wizard.haveStyleModel())
+ styleName = m_wizard.styleName(m_qmlStyleIndex);
+
+ if (m_wizard.haveVirtualKeyboard())
+ useVirtualKeyboard = m_qmlUseVirtualKeyboard;
+
+ UserPresetData preset = {m_currentPreset->categoryId,
+ m_currentPreset->wizardName,
+ m_qmlPresetName,
+ screenSize,
+ useVirtualKeyboard,
+ targetQtVersion,
+ styleName};
+
+ if (!m_userPresetsStore.save(preset)) {
+ QMessageBox::warning(m_dialog,
+ tr("Save Preset"),
+ tr("A preset with this name already exists."));
+ return;
+ }
+
+ // reload model
+ std::vector<RecentPresetData> recents = m_recentsStore.fetchAll();
+ std::vector<UserPresetData> userPresets = m_userPresetsStore.fetchAll();
+ m_presetData.reload(userPresets, recents);
+
+ m_categoryModel->reset();
+
+ emit userPresetSaved();
+}
+
+void QdsNewDialog::removeCurrentPreset()
+{
+ if (!m_currentPreset->isUserPreset()) {
+ qWarning() << "Will not attempt to remove non-user preset";
+ return;
+ }
+
+ // remove preset & reload model
+ std::vector<RecentPresetData> recents = m_recentsStore.remove(m_currentPreset->categoryId,
+ m_currentPreset->displayName());
+
+ auto userPreset = m_currentPreset->asUserPreset();
+ m_userPresetsStore.remove(userPreset->categoryId, userPreset->displayName());
+ std::vector<UserPresetData> userPresets = m_userPresetsStore.fetchAll();
+ m_presetData.reload(userPresets, recents);
+
+ m_qmlSelectedPreset = -1;
+ m_presetPage = -1;
+
+ if (userPresets.size() == 0) {
+ m_presetModel->setPage(0);
+ emit lastUserPresetRemoved();
+ }
+
+ m_categoryModel->reset();
+ m_presetModel->reset();
+}
diff --git a/src/plugins/studiowelcome/qdsnewdialog.h b/src/plugins/studiowelcome/qdsnewdialog.h
index a4afa69e92..670b39192d 100644
--- a/src/plugins/studiowelcome/qdsnewdialog.h
+++ b/src/plugins/studiowelcome/qdsnewdialog.h
@@ -29,13 +29,13 @@
#include <coreplugin/dialogs/newdialog.h>
#include <utils/infolabel.h>
-#include <utils/optional.h>
#include "wizardhandler.h"
#include "presetmodel.h"
#include "screensizemodel.h"
#include "stylemodel.h"
#include "recentpresets.h"
+#include "userpresets.h"
QT_BEGIN_NAMESPACE
class QStandardItemModel;
@@ -57,21 +57,31 @@ public:
Q_PROPERTY(bool useVirtualKeyboard MEMBER m_qmlUseVirtualKeyboard READ getUseVirtualKeyboard WRITE setUseVirtualKeyboard NOTIFY useVirtualKeyboardChanged)
Q_PROPERTY(bool haveVirtualKeyboard MEMBER m_qmlHaveVirtualKeyboard READ getHaveVirtualKeyboard NOTIFY haveVirtualKeyboardChanged)
Q_PROPERTY(bool haveTargetQtVersion MEMBER m_qmlHaveTargetQtVersion READ getHaveTargetQtVersion NOTIFY haveTargetQtVersionChanged)
+ Q_PROPERTY(int targetQtVersionIndex MEMBER m_qmlTargetQtVersionIndex READ getTargetQtVersionIndex WRITE setTargetQtVersionIndex NOTIFY targetQtVersionIndexChanged)
Q_PROPERTY(bool saveAsDefaultLocation MEMBER m_qmlSaveAsDefaultLocation WRITE setSaveAsDefaultLocation)
Q_PROPERTY(QString statusMessage MEMBER m_qmlStatusMessage READ getStatusMessage NOTIFY statusMessageChanged)
Q_PROPERTY(QString statusType MEMBER m_qmlStatusType READ getStatusType NOTIFY statusTypeChanged)
Q_PROPERTY(bool fieldsValid MEMBER m_qmlFieldsValid READ getFieldsValid NOTIFY fieldsValidChanged)
+ Q_PROPERTY(QString presetName MEMBER m_qmlPresetName)
Q_PROPERTY(bool detailsLoaded MEMBER m_qmlDetailsLoaded)
Q_PROPERTY(bool stylesLoaded MEMBER m_qmlStylesLoaded)
+ Q_INVOKABLE void removeCurrentPreset();
Q_INVOKABLE QString currentPresetQmlPath() const;
// TODO: screen size index should better be a property
Q_INVOKABLE void setScreenSizeIndex(int index); // called when ComboBox item is "activated"
Q_INVOKABLE int screenSizeIndex() const;
- Q_INVOKABLE void setTargetQtVersion(int index);
Q_INVOKABLE QString chooseProjectLocation();
+ Q_INVOKABLE QString recentsTabName() const;
+
+ Q_PROPERTY(QAbstractListModel *categoryModel MEMBER m_categoryModel CONSTANT);
+ Q_PROPERTY(QAbstractListModel *presetModel MEMBER m_presetModel CONSTANT);
+ Q_PROPERTY(QAbstractListModel *screenSizeModel MEMBER m_screenSizeModel CONSTANT);
+ Q_PROPERTY(QAbstractListModel *styleModel MEMBER m_styleModel CONSTANT);
+
+ /*********************/
explicit QdsNewDialog(QWidget *parent);
@@ -85,7 +95,11 @@ public:
void setStyleIndex(int index);
int getStyleIndex() const;
- void setUseVirtualKeyboard(bool value) { m_qmlUseVirtualKeyboard = value; }
+
+ void setTargetQtVersionIndex(int index);
+ int getTargetQtVersionIndex() const;
+
+ void setUseVirtualKeyboard(bool value);
bool getUseVirtualKeyboard() const { return m_qmlUseVirtualKeyboard; }
bool getFieldsValid() const { return m_qmlFieldsValid; }
@@ -101,6 +115,8 @@ public slots:
void accept();
void reject();
+ void savePresetDialogAccept();
+
signals:
void projectNameChanged();
void projectLocationChanged();
@@ -111,6 +127,9 @@ signals:
void statusMessageChanged();
void statusTypeChanged();
void fieldsValidChanged();
+ void targetQtVersionIndexChanged();
+ void userPresetSaved();
+ void lastUserPresetRemoved();
private slots:
void onStatusMessageChanged(Utils::InfoLabel::InfoType type, const QString &message);
@@ -160,6 +179,7 @@ private:
bool m_qmlFieldsValid = false;
QString m_qmlStatusMessage;
QString m_qmlStatusType;
+ QString m_qmlPresetName;
int m_presetPage = -1; // i.e. the page in the Presets View
@@ -169,10 +189,11 @@ private:
bool m_qmlDetailsLoaded = false;
bool m_qmlStylesLoaded = false;
- Utils::optional<PresetItem> m_currentPreset;
+ std::shared_ptr<PresetItem> m_currentPreset;
WizardHandler m_wizard;
RecentPresetsStore m_recentsStore;
+ UserPresetsStore m_userPresetsStore;
};
} //namespace StudioWelcome
diff --git a/src/plugins/studiowelcome/recentpresets.cpp b/src/plugins/studiowelcome/recentpresets.cpp
index f6e1335b47..cad2846d75 100644
--- a/src/plugins/studiowelcome/recentpresets.cpp
+++ b/src/plugins/studiowelcome/recentpresets.cpp
@@ -32,19 +32,27 @@
#include <utils/qtcassert.h>
#include <utils/qtcsettings.h>
-using Core::ICore;
-using Utils::QtcSettings;
-
using namespace StudioWelcome;
constexpr char GROUP_NAME[] = "RecentPresets";
constexpr char WIZARDS[] = "Wizards";
-void RecentPresetsStore::add(const QString &categoryId, const QString &name, const QString &sizeName)
+void RecentPresetsStore::add(const QString &categoryId,
+ const QString &name,
+ const QString &sizeName,
+ bool isUserPreset)
{
- std::vector<RecentPreset> existing = fetchAll();
- QStringList encodedRecents = addRecentToExisting(RecentPreset{categoryId, name, sizeName},
- existing);
+ std::vector<RecentPresetData> existing = fetchAll();
+
+ std::vector<RecentPresetData> recents
+ = addRecentToExisting(RecentPresetData{categoryId, name, sizeName, isUserPreset}, existing);
+
+ save(recents);
+}
+
+void RecentPresetsStore::save(const std::vector<RecentPresetData> &recents)
+{
+ QStringList encodedRecents = encodeRecentPresets(recents);
m_settings->beginGroup(GROUP_NAME);
m_settings->setValue(WIZARDS, encodedRecents);
@@ -52,8 +60,26 @@ void RecentPresetsStore::add(const QString &categoryId, const QString &name, con
m_settings->sync();
}
-QStringList RecentPresetsStore::addRecentToExisting(const RecentPreset &preset,
- std::vector<RecentPreset> &recents)
+std::vector<RecentPresetData> RecentPresetsStore::remove(const QString &categoryId, const QString &presetName)
+{
+ std::vector<RecentPresetData> recents = fetchAll();
+ size_t countBefore = recents.size();
+
+ /* NOTE: when removing one preset, it may happen that there are more than one recent for that
+ * preset. In that case, we need to remove all associated recents, for the preset.*/
+
+ Utils::erase(recents, [&](const RecentPresetData &p) {
+ return p.category == categoryId && p.presetName == presetName;
+ });
+
+ if (recents.size() < countBefore)
+ save(recents);
+
+ return recents;
+}
+
+std::vector<RecentPresetData> RecentPresetsStore::addRecentToExisting(
+ const RecentPresetData &preset, std::vector<RecentPresetData> &recents)
{
Utils::erase_one(recents, preset);
Utils::prepend(recents, preset);
@@ -61,48 +87,64 @@ QStringList RecentPresetsStore::addRecentToExisting(const RecentPreset &preset,
if (int(recents.size()) > m_max)
recents.pop_back();
- return encodeRecentPresets(recents);
+ return recents;
}
-std::vector<RecentPreset> RecentPresetsStore::fetchAll() const
+std::vector<RecentPresetData> RecentPresetsStore::fetchAll() const
{
m_settings->beginGroup(GROUP_NAME);
QVariant value = m_settings->value(WIZARDS);
m_settings->endGroup();
- std::vector<RecentPreset> result;
+ std::vector<RecentPresetData> result;
if (value.type() == QVariant::String)
result.push_back(decodeOneRecentPreset(value.toString()));
else if (value.type() == QVariant::StringList)
Utils::concat(result, decodeRecentPresets(value.toList()));
- const RecentPreset empty;
- return Utils::filtered(result, [&empty](const RecentPreset &recent) { return recent != empty; });
+ const RecentPresetData empty;
+ return Utils::filtered(result, [&empty](const RecentPresetData &recent) { return recent != empty; });
}
-QStringList RecentPresetsStore::encodeRecentPresets(const std::vector<RecentPreset> &recents)
+QStringList RecentPresetsStore::encodeRecentPresets(const std::vector<RecentPresetData> &recents)
{
- return Utils::transform<QList>(recents, [](const RecentPreset &p) -> QString {
- return std::get<0>(p) + "/" + std::get<1>(p) + ":" + std::get<2>(p);
+ return Utils::transform<QList>(recents, [](const RecentPresetData &p) -> QString {
+ QString name = p.presetName;
+ if (p.isUserPreset)
+ name.prepend("[U]");
+
+ return p.category + "/" + name + ":" + p.sizeName;
});
}
-RecentPreset RecentPresetsStore::decodeOneRecentPreset(const QString &encoded)
+RecentPresetData RecentPresetsStore::decodeOneRecentPreset(const QString &encoded)
{
- QRegularExpression pattern{R"(^(\S+)/(.+):(\d+ x \d+))"};
+ QRegularExpression pattern{R"(^(\S+)/(.+):(\d+ x \d+)$)"};
auto m = pattern.match(encoded);
if (!m.hasMatch())
- return RecentPreset{};
+ return RecentPresetData{};
QString category = m.captured(1);
QString name = m.captured(2);
QString size = m.captured(3);
+ bool isUserPreset = name.startsWith("[U]");
+ if (isUserPreset)
+ name = name.split("[U]")[1];
+
+ if (!QRegularExpression{R"(^\w[\w ]*$)"}.match(name).hasMatch())
+ return RecentPresetData{};
+
+ RecentPresetData result;
+ result.category = category;
+ result.presetName = name;
+ result.sizeName = size;
+ result.isUserPreset = isUserPreset;
- return std::make_tuple(category, name, size);
+ return result;
}
-std::vector<RecentPreset> RecentPresetsStore::decodeRecentPresets(const QVariantList &values)
+std::vector<RecentPresetData> RecentPresetsStore::decodeRecentPresets(const QVariantList &values)
{
return Utils::transform<std::vector>(values, [](const QVariant &value) {
return decodeOneRecentPreset(value.toString());
diff --git a/src/plugins/studiowelcome/recentpresets.h b/src/plugins/studiowelcome/recentpresets.h
index 3c223d8df5..83ab5fb8cc 100644
--- a/src/plugins/studiowelcome/recentpresets.h
+++ b/src/plugins/studiowelcome/recentpresets.h
@@ -31,8 +31,43 @@
namespace StudioWelcome {
-// preset category, preset name, size name
-using RecentPreset = std::tuple<QString, QString, QString>;
+struct RecentPresetData
+{
+ RecentPresetData() = default;
+ RecentPresetData(const QString &category,
+ const QString &name,
+ const QString &size,
+ bool isUserPreset = false)
+ : category{category}
+ , presetName{name}
+ , sizeName{size}
+ , isUserPreset{isUserPreset}
+ {}
+
+ QString category;
+ QString presetName;
+ QString sizeName;
+ bool isUserPreset = false;
+};
+
+inline bool operator==(const RecentPresetData &lhs, const RecentPresetData &rhs)
+{
+ return lhs.category == rhs.category && lhs.presetName == rhs.presetName
+ && lhs.sizeName == rhs.sizeName && lhs.isUserPreset == rhs.isUserPreset;
+}
+
+inline bool operator!=(const RecentPresetData &lhs, const RecentPresetData &rhs)
+{
+ return !(lhs == rhs);
+}
+
+inline QDebug &operator<<(QDebug &d, const RecentPresetData &preset)
+{
+ d << "RecentPreset{category=" << preset.category << "; name=" << preset.presetName
+ << "; size=" << preset.sizeName << "; isUserPreset=" << preset.isUserPreset << "}";
+
+ return d;
+}
class RecentPresetsStore
{
@@ -42,14 +77,21 @@ public:
{}
void setMaximum(int n) { m_max = n; }
- void add(const QString &categoryId, const QString &name, const QString &sizeName);
- std::vector<RecentPreset> fetchAll() const;
+ void add(const QString &categoryId,
+ const QString &name,
+ const QString &sizeName,
+ bool isUserPreset = false);
+
+ std::vector<RecentPresetData> remove(const QString &categoryId, const QString &presetName);
+ std::vector<RecentPresetData> fetchAll() const;
private:
- QStringList addRecentToExisting(const RecentPreset &preset, std::vector<RecentPreset> &recents);
- static QStringList encodeRecentPresets(const std::vector<RecentPreset> &recents);
- static std::vector<RecentPreset> decodeRecentPresets(const QVariantList &values);
- static RecentPreset decodeOneRecentPreset(const QString &encoded);
+ std::vector<RecentPresetData> addRecentToExisting(const RecentPresetData &preset,
+ std::vector<RecentPresetData> &recents);
+ static QStringList encodeRecentPresets(const std::vector<RecentPresetData> &recents);
+ static std::vector<RecentPresetData> decodeRecentPresets(const QVariantList &values);
+ static RecentPresetData decodeOneRecentPreset(const QString &encoded);
+ void save(const std::vector<RecentPresetData> &recents);
private:
QSettings *m_settings = nullptr;
diff --git a/src/plugins/studiowelcome/studiowelcome.qbs b/src/plugins/studiowelcome/studiowelcome.qbs
index cc655ea5a2..9648eda14d 100644
--- a/src/plugins/studiowelcome/studiowelcome.qbs
+++ b/src/plugins/studiowelcome/studiowelcome.qbs
@@ -38,7 +38,9 @@ QtcPlugin {
"wizardhandler.cpp",
"wizardhandler.h",
"recentpresets.cpp",
- "recentpresets.h"
+ "recentpresets.h",
+ "userpresets.cpp",
+ "userpresets.h"
]
Group {
diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp
index f292d32604..d1436cc043 100644
--- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp
+++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp
@@ -793,7 +793,7 @@ StudioSettingsPage::StudioSettingsPage()
{
const QString toolTip = tr(
"Hide top-level menus with advanced functionality to simplify the UI. <b>Build</b> is "
- "generally not required in the context of Qt Design Studio.<b>Debug</b> and <b>Analyze</b>"
+ "generally not required in the context of Qt Design Studio. <b>Debug</b> and <b>Analyze</b> "
"are only required for debugging and profiling.");
QVBoxLayout *boxLayout = new QVBoxLayout();
diff --git a/src/plugins/studiowelcome/userpresets.cpp b/src/plugins/studiowelcome/userpresets.cpp
new file mode 100644
index 0000000000..d468c3522e
--- /dev/null
+++ b/src/plugins/studiowelcome/userpresets.cpp
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#include "userpresets.h"
+
+#include <coreplugin/icore.h>
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+
+using namespace StudioWelcome;
+
+constexpr char PREFIX[] = "UserPresets";
+
+UserPresetsStore::UserPresetsStore()
+{
+ m_settings = std::make_unique<QSettings>(fullFilePath(), QSettings::IniFormat);
+}
+
+UserPresetsStore::UserPresetsStore(std::unique_ptr<QSettings> &&settings)
+ : m_settings{std::move(settings)}
+{}
+
+void UserPresetsStore::savePresets(const std::vector<UserPresetData> &presets)
+{
+ m_settings->beginWriteArray(PREFIX, static_cast<int>(presets.size()));
+
+ for (size_t i = 0; i < presets.size(); ++i) {
+ m_settings->setArrayIndex(static_cast<int>(i));
+ const auto &preset = presets[i];
+
+ m_settings->setValue("categoryId", preset.categoryId);
+ m_settings->setValue("wizardName", preset.wizardName);
+ m_settings->setValue("name", preset.name);
+ m_settings->setValue("screenSize", preset.screenSize);
+ m_settings->setValue("useQtVirtualKeyboard", preset.useQtVirtualKeyboard);
+ m_settings->setValue("qtVersion", preset.qtVersion);
+ m_settings->setValue("styleName", preset.styleName);
+ }
+ m_settings->endArray();
+ m_settings->sync();
+
+}
+
+bool UserPresetsStore::save(const UserPresetData &newPreset)
+{
+ QTC_ASSERT(newPreset.isValid(), return false);
+
+ std::vector<UserPresetData> presetItems = fetchAll();
+ if (Utils::anyOf(presetItems,
+ [&newPreset](const UserPresetData &p) { return p.name == newPreset.name; })) {
+ return false;
+ }
+
+ presetItems.push_back(newPreset);
+ savePresets(presetItems);
+
+ return true;
+}
+
+void UserPresetsStore::remove(const QString &category, const QString &name)
+{
+ std::vector<UserPresetData> presetItems = fetchAll();
+ auto item = Utils::take(presetItems, [&](const UserPresetData &p) {
+ return p.categoryId == category && p.name == name;
+ });
+
+ if (!item)
+ return;
+
+ savePresets(presetItems);
+}
+
+std::vector<UserPresetData> UserPresetsStore::fetchAll() const
+{
+ std::vector<UserPresetData> result;
+ int size = m_settings->beginReadArray(PREFIX);
+ if (size >= 0)
+ result.reserve(static_cast<size_t>(size) + 1);
+
+ for (int i = 0; i < size; ++i) {
+ m_settings->setArrayIndex(i);
+
+ UserPresetData preset;
+ preset.categoryId = m_settings->value("categoryId").toString();
+ preset.wizardName = m_settings->value("wizardName").toString();
+ preset.name = m_settings->value("name").toString();
+ preset.screenSize = m_settings->value("screenSize").toString();
+ preset.useQtVirtualKeyboard = m_settings->value("useQtVirtualKeyboard").toBool();
+ preset.qtVersion = m_settings->value("qtVersion").toString();
+ preset.styleName = m_settings->value("styleName").toString();
+
+ if (preset.isValid())
+ result.push_back(std::move(preset));
+ }
+ m_settings->endArray();
+
+ return result;
+}
+
+QString UserPresetsStore::fullFilePath() const
+{
+ return Core::ICore::userResourcePath("UserPresets.ini").toString();
+}
diff --git a/src/plugins/studiowelcome/userpresets.h b/src/plugins/studiowelcome/userpresets.h
new file mode 100644
index 0000000000..4f6053ef26
--- /dev/null
+++ b/src/plugins/studiowelcome/userpresets.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <vector>
+#include <QSettings>
+
+namespace StudioWelcome {
+
+struct UserPresetData
+{
+ QString categoryId;
+ QString wizardName;
+ QString name;
+ QString screenSize;
+
+ bool useQtVirtualKeyboard;
+ QString qtVersion;
+ QString styleName;
+
+ bool isValid() const
+ {
+ return !categoryId.isEmpty()
+ && !wizardName.isEmpty()
+ && !name.isEmpty();
+ }
+};
+
+inline QDebug &operator<<(QDebug &d, const UserPresetData &preset)
+{
+ d << "UserPreset{category = " << preset.categoryId;
+ d << "; wizardName = " << preset.wizardName;
+ d << "; name = " << preset.name;
+ d << "; screenSize = " << preset.screenSize;
+ d << "; keyboard = " << preset.useQtVirtualKeyboard;
+ d << "; qt = " << preset.qtVersion;
+ d << "; style = " << preset.styleName;
+ d << "}";
+
+ return d;
+}
+
+inline bool operator==(const UserPresetData &lhs, const UserPresetData &rhs)
+{
+ return lhs.categoryId == rhs.categoryId && lhs.wizardName == rhs.wizardName
+ && lhs.name == rhs.name && lhs.screenSize == rhs.screenSize
+ && lhs.useQtVirtualKeyboard == rhs.useQtVirtualKeyboard && lhs.qtVersion == rhs.qtVersion
+ && lhs.styleName == rhs.styleName;
+}
+
+class UserPresetsStore
+{
+public:
+ UserPresetsStore();
+ UserPresetsStore(std::unique_ptr<QSettings> &&settings);
+
+ bool save(const UserPresetData &preset);
+ void remove(const QString &category, const QString &name);
+ std::vector<UserPresetData> fetchAll() const;
+
+private:
+ QString fullFilePath() const;
+ void savePresets(const std::vector<UserPresetData> &presets);
+
+ std::unique_ptr<QSettings> m_settings;
+};
+
+} // namespace StudioWelcome
diff --git a/src/plugins/studiowelcome/wizardfactories.cpp b/src/plugins/studiowelcome/wizardfactories.cpp
index d374a5258c..e271d5572e 100644
--- a/src/plugins/studiowelcome/wizardfactories.cpp
+++ b/src/plugins/studiowelcome/wizardfactories.cpp
@@ -76,7 +76,7 @@ void WizardFactories::filter()
m_factories = acceptedFactories;
}
-PresetItem WizardFactories::makePresetItem(JsonWizardFactory *f, QWidget *parent,
+std::shared_ptr<PresetItem> WizardFactories::makePresetItem(JsonWizardFactory *f, QWidget *parent,
const Utils::Id &platform)
{
using namespace std::placeholders;
@@ -89,16 +89,17 @@ PresetItem WizardFactories::makePresetItem(JsonWizardFactory *f, QWidget *parent
else
sizeName = screenSizes[index];
- return {
- /*.name =*/f->displayName(),
- /*.categoryId =*/f->category(),
- /*.screenSizeName=*/sizeName,
- /*.description =*/f->description(),
- /*.qmlPath =*/f->detailsPageQmlPath(),
- /*.fontIconCode =*/m_getIconUnicode(f->fontIconName()),
- /*.create =*/ std::bind(&JsonWizardFactory::runWizard, f, _1, parent, platform,
- QVariantMap(), false),
- };
+ auto result = std::make_shared<PresetItem>();
+ result->wizardName = f->displayName();
+ result->categoryId = f->category();
+ result->screenSizeName=sizeName;
+ result->description = f->description();
+ result->qmlPath = f->detailsPageQmlPath();
+ result->fontIconCode = m_getIconUnicode(f->fontIconName());
+ result->create
+ = std::bind(&JsonWizardFactory::runWizard, f, _1, parent, platform, QVariantMap(), false);
+
+ return result;
}
std::map<QString, WizardCategory> WizardFactories::makePresetItemsGroupedByCategory()
diff --git a/src/plugins/studiowelcome/wizardfactories.h b/src/plugins/studiowelcome/wizardfactories.h
index aa209362de..c98fd5e102 100644
--- a/src/plugins/studiowelcome/wizardfactories.h
+++ b/src/plugins/studiowelcome/wizardfactories.h
@@ -64,7 +64,7 @@ private:
void sortByCategoryAndId();
void filter();
- PresetItem makePresetItem(JsonWizardFactory *f, QWidget *parent, const Utils::Id &platform);
+ std::shared_ptr<PresetItem> makePresetItem(JsonWizardFactory *f, QWidget *parent, const Utils::Id &platform);
std::map<QString, WizardCategory> makePresetItemsGroupedByCategory();
private:
diff --git a/src/plugins/studiowelcome/wizardhandler.cpp b/src/plugins/studiowelcome/wizardhandler.cpp
index cd176707ac..56c53fcad9 100644
--- a/src/plugins/studiowelcome/wizardhandler.cpp
+++ b/src/plugins/studiowelcome/wizardhandler.cpp
@@ -38,7 +38,7 @@
using namespace StudioWelcome;
-void WizardHandler::reset(const PresetItem &presetInfo, int presetSelection)
+void WizardHandler::reset(const std::shared_ptr<PresetItem> &presetInfo, int presetSelection)
{
m_preset = presetInfo;
m_selectedPreset = presetSelection;
@@ -67,7 +67,7 @@ void WizardHandler::destroyWizard()
void WizardHandler::setupWizard()
{
- m_wizard = m_preset.create(m_projectLocation);
+ m_wizard = m_preset->create(m_projectLocation);
if (!m_wizard) {
emit wizardCreationFailed();
return;
@@ -142,6 +142,11 @@ QStandardItemModel *WizardHandler::getScreenFactorModel(ProjectExplorer::JsonFie
return cbfield->model();
}
+bool WizardHandler::haveStyleModel() const
+{
+ return m_wizard->hasField("ControlsStyle");
+}
+
QStandardItemModel *WizardHandler::getStyleModel(ProjectExplorer::JsonFieldPage *page)
{
auto *field = page->jsonField("ControlsStyle");
@@ -229,6 +234,47 @@ bool WizardHandler::haveTargetQtVersion() const
return m_wizard->hasField("TargetQtVersion");
}
+QString WizardHandler::targetQtVersionName(int index) const
+{
+ auto *field = m_detailsPage->jsonField("TargetQtVersion");
+ auto *cbfield = dynamic_cast<ProjectExplorer::ComboBoxField *>(field);
+ QTC_ASSERT(cbfield, return "");
+
+ QStandardItemModel *model = cbfield->model();
+ if (index < 0 || index >= model->rowCount())
+ return {};
+
+ QString text = model->item(index)->text();
+ return text;
+}
+
+int WizardHandler::targetQtVersionIndex(const QString &qtVersionName) const
+{
+ auto *field = m_detailsPage->jsonField("TargetQtVersion");
+ auto *cbfield = dynamic_cast<ProjectExplorer::ComboBoxField *>(field);
+ QTC_ASSERT(cbfield, return -1);
+
+ const QStandardItemModel *model = cbfield->model();
+ for (int i = 0; i < model->rowCount(); ++i) {
+ const QStandardItem *item = model->item(i, 0);
+ const QString text = item->text();
+
+ if (text == qtVersionName)
+ return i;
+ }
+
+ return -1;
+}
+
+int WizardHandler::targetQtVersionIndex() const
+{
+ auto *field = m_detailsPage->jsonField("TargetQtVersion");
+ auto *cbfield = dynamic_cast<ProjectExplorer::ComboBoxField *>(field);
+ QTC_ASSERT(cbfield, return -1);
+
+ return cbfield->selectedRow();
+}
+
void WizardHandler::setStyleIndex(int index)
{
auto *field = m_detailsPage->jsonField("ControlsStyle");
@@ -247,6 +293,38 @@ int WizardHandler::styleIndex() const
return cbfield->selectedRow();
}
+int WizardHandler::styleIndex(const QString &styleName) const
+{
+ auto *field = m_detailsPage->jsonField("ControlsStyle");
+ auto *cbfield = dynamic_cast<ProjectExplorer::ComboBoxField *>(field);
+ QTC_ASSERT(cbfield, return -1);
+
+ const QStandardItemModel *model = cbfield->model();
+ for (int i = 0; i < model->rowCount(); ++i) {
+ const QStandardItem *item = model->item(i, 0);
+ const QString text = item->text();
+
+ if (text == styleName)
+ return i;
+ }
+
+ return -1;
+}
+
+QString WizardHandler::styleName(int index) const
+{
+ auto *field = m_detailsPage->jsonField("ControlsStyle");
+ auto *cbfield = dynamic_cast<ProjectExplorer::ComboBoxField *>(field);
+ QTC_ASSERT(cbfield, return "");
+
+ QStandardItemModel *model = cbfield->model();
+ if (index < 0 || index >= model->rowCount())
+ return {};
+
+ QString text = model->item(index)->text();
+ return text;
+}
+
void WizardHandler::setUseVirtualKeyboard(bool value)
{
auto *field = m_detailsPage->jsonField("UseVirtualKeyboard");
diff --git a/src/plugins/studiowelcome/wizardhandler.h b/src/plugins/studiowelcome/wizardhandler.h
index 112accfb15..ce13b77572 100644
--- a/src/plugins/studiowelcome/wizardhandler.h
+++ b/src/plugins/studiowelcome/wizardhandler.h
@@ -47,15 +47,23 @@ class WizardHandler: public QObject
Q_OBJECT
public:
- void reset(const PresetItem &presetInfo, int presetSelection);
+ void reset(const std::shared_ptr<PresetItem> &presetInfo, int presetSelection);
void setScreenSizeIndex(int index);
int screenSizeIndex(const QString &sizeName) const;
QString screenSizeName(int index) const;
int screenSizeIndex() const;
+ int targetQtVersionIndex() const;
+ int targetQtVersionIndex(const QString &qtVersionName) const;
void setTargetQtVersionIndex(int index);
bool haveTargetQtVersion() const;
+ QString targetQtVersionName(int index) const;
+
void setStyleIndex(int index);
int styleIndex() const;
+ int styleIndex(const QString &styleName) const;
+ QString styleName(int index) const;
+ bool haveStyleModel() const;
+
void destroyWizard();
void setUseVirtualKeyboard(bool value);
@@ -66,7 +74,7 @@ public:
void run(const std::function<void (QWizardPage *)> &processPage);
- PresetItem preset() const { return m_preset; }
+ std::shared_ptr<PresetItem> preset() const { return m_preset; }
signals:
void deletingWizard();
@@ -93,7 +101,7 @@ private:
int m_selectedPreset = -1;
- PresetItem m_preset;
+ std::shared_ptr<PresetItem> m_preset;
Utils::FilePath m_projectLocation;
};
diff --git a/src/shared/qbs b/src/shared/qbs
-Subproject c934cbfae91c15511639771fe8c6fc66352005f
+Subproject 58b882945d6faaf928b0f9bd7fcd146935fe758
diff --git a/src/tools/disclaim/disclaim.qbs b/src/tools/disclaim/disclaim.qbs
new file mode 100644
index 0000000000..14a5ce7fae
--- /dev/null
+++ b/src/tools/disclaim/disclaim.qbs
@@ -0,0 +1,12 @@
+import qbs 1.0
+
+QtcTool {
+ name: "disclaim"
+ condition: qbs.targetOS.contains("macos")
+
+ files: [
+ "disclaim.mm"
+ ]
+
+ installDir: qtc.ide_libexec_path
+}
diff --git a/src/tools/sdktool/adddeviceoperation.cpp b/src/tools/sdktool/adddeviceoperation.cpp
index f7137ef366..00628be384 100644
--- a/src/tools/sdktool/adddeviceoperation.cpp
+++ b/src/tools/sdktool/adddeviceoperation.cpp
@@ -55,8 +55,8 @@ QString AddDeviceOperation::helpText() const
QString AddDeviceOperation::argumentsHelpText() const
{
- return QLatin1String(" --id <ID> id of the new kit (required).\n"
- " --name <NAME> display name of the new kit (required).\n"
+ return QLatin1String(" --id <ID> id of the new device (required).\n"
+ " --name <NAME> display name of the new device (required).\n"
" --type <INT> type (required).\n"
" --authentication <INT> authentication.\n"
" --b2qHardware <STRING> Boot2Qt Platform Info Hardware.\n"
@@ -71,6 +71,9 @@ QString AddDeviceOperation::argumentsHelpText() const
" --sshPort <INT> ssh port.\n"
" --timeout <INT> timeout.\n"
" --uname <STRING> uname.\n"
+ " --dockerRepo <STRING> Docker image repo.\n"
+ " --dockerTag <STRING> Docker image tag.\n"
+ " --dockerMappedPaths <STRING> Docker mapped paths (semi-colon separated).\n"
" <KEY> <TYPE:VALUE> extra key value pairs\n");
}
@@ -224,6 +227,30 @@ bool AddDeviceOperation::setArguments(const QStringList &args)
continue;
}
+ if (current == QLatin1String("--dockerMappedPaths")) {
+ if (next.isNull())
+ return false;
+ ++i; // skip next;
+ m_dockerMappedPaths = next.split(';');
+ continue;
+ }
+
+ if (current == QLatin1String("--dockerRepo")) {
+ if (next.isNull())
+ return false;
+ ++i; // skip next;
+ m_dockerRepo = next;
+ continue;
+ }
+
+ if (current == QLatin1String("--dockerTag")) {
+ if (next.isNull())
+ return false;
+ ++i; // skip next;
+ m_dockerTag = next;
+ continue;
+ }
+
if (next.isNull())
return false;
++i; // skip next;
@@ -278,6 +305,9 @@ bool AddDeviceOperation::test() const
devData.m_timeout = 5;
devData.m_uname = "uname";
devData.m_version = 6;
+ devData.m_dockerRepo = "repo";
+ devData.m_dockerTag = "tag";
+ devData.m_dockerMappedPaths = QStringList{"/opt", "/data"};
QVariantMap result = devData.addDevice(map);
QVariantMap data = result.value(QLatin1String(DEVICEMANAGER_ID)).toMap();
@@ -285,7 +315,7 @@ bool AddDeviceOperation::test() const
if (devList.count() != 1)
return false;
QVariantMap dev = devList.at(0).toMap();
- if (dev.count() != 17)
+ if (dev.count() != 20)
return false;
if (dev.value(QLatin1String("Authentication")).toInt() != 2)
return false;
@@ -317,6 +347,13 @@ bool AddDeviceOperation::test() const
return false;
if (dev.value(QLatin1String("Version")).toInt() != 6)
return false;
+ if (dev.value(QLatin1String("DockerDeviceDataRepo")).toString() != "repo")
+ return false;
+ if (dev.value(QLatin1String("DockerDeviceDataTag")).toString() != "tag")
+ return false;
+ const QStringList paths = dev.value(QLatin1String("DockerDeviceMappedPaths")).toStringList();
+ if (paths != QStringList({"/opt", "/data"}))
+ return false;
return true;
}
@@ -351,6 +388,9 @@ QVariantMap AddDeviceData::addDevice(const QVariantMap &map) const
dev.append(KeyValuePair(QLatin1String("Timeout"), QVariant(m_timeout)));
dev.append(KeyValuePair(QLatin1String("Uname"), QVariant(m_uname)));
dev.append(KeyValuePair(QLatin1String("Version"), QVariant(m_version)));
+ dev.append(KeyValuePair(QLatin1String("DockerDeviceMappedPaths"), QVariant(m_dockerMappedPaths)));
+ dev.append(KeyValuePair(QLatin1String("DockerDeviceDataRepo"), QVariant(m_dockerRepo)));
+ dev.append(KeyValuePair(QLatin1String("DockerDeviceDataTag"), QVariant(m_dockerTag)));
dev.append(m_extra);
QVariantMap devMap = AddKeysData{dev}.addKeys(QVariantMap());
diff --git a/src/tools/sdktool/adddeviceoperation.h b/src/tools/sdktool/adddeviceoperation.h
index 2e0c9cfb61..67f4a677d6 100644
--- a/src/tools/sdktool/adddeviceoperation.h
+++ b/src/tools/sdktool/adddeviceoperation.h
@@ -62,6 +62,9 @@ public:
int m_timeout = 5;
QString m_uname;
int m_version = 0;
+ QStringList m_dockerMappedPaths;
+ QString m_dockerRepo;
+ QString m_dockerTag;
KeyValuePairList m_extra;
};
diff --git a/src/tools/tools.qbs b/src/tools/tools.qbs
index 1205104f85..2ebd01f9c9 100644
--- a/src/tools/tools.qbs
+++ b/src/tools/tools.qbs
@@ -7,6 +7,7 @@ Project {
"buildoutputparser/buildoutputparser.qbs",
"clangbackend/clangbackend.qbs",
"cplusplustools.qbs",
+ "disclaim/disclaim.qbs",
"processlauncher/processlauncher.qbs",
"qml2puppet/qml2puppet.qbs",
"qtcdebugger/qtcdebugger.qbs",
diff --git a/tests/auto/qml/qmldesigner/wizard/CMakeLists.txt b/tests/auto/qml/qmldesigner/wizard/CMakeLists.txt
index 0606be1a55..c5040112ef 100644
--- a/tests/auto/qml/qmldesigner/wizard/CMakeLists.txt
+++ b/tests/auto/qml/qmldesigner/wizard/CMakeLists.txt
@@ -18,12 +18,14 @@ add_qtc_test(tst_qml_wizard
wizardfactories-test.cpp
stylemodel-test.cpp
recentpresets-test.cpp
+ userpresets-test.cpp
presetmodel-test.cpp
test-utilities.h
test-main.cpp
"${StudioWelcomeDir}/wizardfactories.cpp"
"${StudioWelcomeDir}/stylemodel.cpp"
"${StudioWelcomeDir}/recentpresets.cpp"
+ "${StudioWelcomeDir}/userpresets.cpp"
"${StudioWelcomeDir}/presetmodel.cpp"
)
diff --git a/tests/auto/qml/qmldesigner/wizard/presetmodel-test.cpp b/tests/auto/qml/qmldesigner/wizard/presetmodel-test.cpp
index dc855b67a3..3c16688458 100644
--- a/tests/auto/qml/qmldesigner/wizard/presetmodel-test.cpp
+++ b/tests/auto/qml/qmldesigner/wizard/presetmodel-test.cpp
@@ -33,10 +33,18 @@ using ::testing::ElementsAreArray;
using ::testing::PrintToString;
namespace StudioWelcome {
+
+void PrintTo(const UserPresetItem &item, std::ostream *os);
+
void PrintTo(const PresetItem &item, std::ostream *os)
{
+ if (typeid(item) == typeid(UserPresetItem)) {
+ PrintTo((UserPresetItem &) item, os);
+ return;
+ }
+
*os << "{categId: " << item.categoryId << ", "
- << "name: " << item.name;
+ << "name: " << item.wizardName;
if (!item.screenSizeName.isEmpty())
*os << ", size: " << item.screenSizeName;
@@ -44,6 +52,26 @@ void PrintTo(const PresetItem &item, std::ostream *os)
*os << "}";
}
+void PrintTo(const UserPresetItem &item, std::ostream *os)
+{
+ *os << "{categId: " << item.categoryId << ", "
+ << "name: " << item.wizardName << ", "
+ << "user name: " << item.userName;
+
+ if (!item.screenSizeName.isEmpty())
+ *os << ", size: " << item.screenSizeName;
+
+ *os << "}";
+}
+
+void PrintTo(const std::shared_ptr<PresetItem> &p, std::ostream *os)
+{
+ if (p)
+ PrintTo(*p, os);
+ else
+ *os << "{null}";
+}
+
} // namespace StudioWelcome
namespace {
@@ -51,20 +79,47 @@ std::pair<QString, WizardCategory> aCategory(const QString &categId,
const QString &categName,
const std::vector<QString> &names)
{
- std::vector<PresetItem> items = Utils::transform(names, [&categId](const QString &name) {
- return PresetItem{name, categId};
- });
+ std::vector<std::shared_ptr<PresetItem>> items
+ = Utils::transform(names, [&categId](const QString &name) {
+ std::shared_ptr<PresetItem> item{new PresetItem};
+ item->wizardName = name;
+ item->categoryId = categId;
+
+ return item;
+ });
return std::make_pair(categId, WizardCategory{categId, categName, items});
}
+UserPresetData aUserPreset(const QString &categId, const QString &wizardName, const QString &userName)
+{
+ UserPresetData preset;
+ preset.categoryId = categId;
+ preset.wizardName = wizardName;
+ preset.name = userName;
+
+ return preset;
+}
+
MATCHER_P2(PresetIs, category, name, PrintToString(PresetItem{name, category}))
{
- return arg.categoryId == category && arg.name == name;
+ return arg->categoryId == category && arg->wizardName == name;
+}
+
+MATCHER_P3(UserPresetIs,
+ category,
+ wizardName,
+ userName,
+ PrintToString(UserPresetItem{wizardName, userName, category}))
+{
+ auto userPreset = dynamic_cast<UserPresetItem *>(arg.get());
+
+ return userPreset->categoryId == category && userPreset->wizardName == wizardName
+ && userPreset->userName == userName;
}
MATCHER_P3(PresetIs, category, name, size, PrintToString(PresetItem{name, category, size}))
{
- return arg.categoryId == category && arg.name == name && size == arg.screenSizeName;
+ return arg->categoryId == category && arg->wizardName == name && size == arg->screenSizeName;
}
} // namespace
@@ -88,6 +143,7 @@ TEST(QdsPresetModel, haveSameArraySizeForPresetsAndCategories)
aCategory("A.categ", "A", {"item a", "item b"}),
aCategory("B.categ", "B", {"item c", "item d"}),
},
+ {/*user presets*/},
{/*recents*/});
ASSERT_THAT(data.presets(), SizeIs(2));
@@ -105,6 +161,7 @@ TEST(QdsPresetModel, haveWizardPresetsNoRecents)
aCategory("A.categ", "A", {"item a", "item b"}),
aCategory("B.categ", "B", {"item c", "item d"}),
},
+ {/*user presets*/},
{/*recents*/});
// Then
@@ -115,11 +172,30 @@ TEST(QdsPresetModel, haveWizardPresetsNoRecents)
ElementsAre(PresetIs("B.categ", "item c"), PresetIs("B.categ", "item d")));
}
+TEST(QdsPresetModel, whenHaveUserPresetsButNoWizardPresetsReturnEmpty)
+{
+ // Given
+ PresetData data;
+
+ // When
+ data.setData({/*builtin presets*/},
+ {
+ aUserPreset("A.Mobile", "Scroll", "iPhone5"),
+ aUserPreset("B.Desktop", "Launcher", "MacBook"),
+ },
+ {/*recents*/});
+
+ // Then
+ ASSERT_THAT(data.categories(), IsEmpty());
+ ASSERT_THAT(data.presets(), IsEmpty());
+}
+
TEST(QdsPresetModel, haveRecentsNoWizardPresets)
{
PresetData data;
data.setData({/*wizardPresets*/},
+ {/*user presets*/},
{
{"A.categ", "Desktop", "640 x 480"},
{"B.categ", "Mobile", "800 x 600"},
@@ -129,7 +205,7 @@ TEST(QdsPresetModel, haveRecentsNoWizardPresets)
ASSERT_THAT(data.presets(), IsEmpty());
}
-TEST(QdsPresetModel, recentsAddedBeforeWizardPresets)
+TEST(QdsPresetModel, recentsAddedWithWizardPresets)
{
// Given
PresetData data;
@@ -141,6 +217,7 @@ TEST(QdsPresetModel, recentsAddedBeforeWizardPresets)
aCategory("A.categ", "A", {"Desktop", "item b"}),
aCategory("B.categ", "B", {"item c", "Mobile"}),
},
+ {/*user presets*/},
/*recents*/
{
{"A.categ", "Desktop", "800 x 600"},
@@ -158,7 +235,171 @@ TEST(QdsPresetModel, recentsAddedBeforeWizardPresets)
ElementsAre(PresetIs("B.categ", "item c"), PresetIs("B.categ", "Mobile"))}));
}
-TEST(QdsPresetModel, recentsShouldNotSorted)
+TEST(QdsPresetModel, userPresetsAddedWithWizardPresets)
+{
+ // Given
+ PresetData data;
+
+ // When
+ data.setData(
+ /*wizard presets*/
+ {
+ aCategory("A.categ", "A", {"Desktop", "item b"}),
+ aCategory("B.categ", "B", {"Mobile"}),
+ },
+ {
+ aUserPreset("A.categ", "Desktop", "Windows10"),
+ },
+ {/*recents*/});
+
+ // Then
+ ASSERT_THAT(data.categories(), ElementsAre("A", "B", "Custom"));
+ ASSERT_THAT(data.presets(),
+ ElementsAre(ElementsAre(PresetIs("A.categ", "Desktop"),
+ PresetIs("A.categ", "item b")),
+ ElementsAre(PresetIs("B.categ", "Mobile")),
+ ElementsAre(UserPresetIs("A.categ", "Desktop", "Windows10"))));
+}
+
+TEST(QdsPresetModel, doesNotAddUserPresetsOfNonExistingCategory)
+{
+ // Given
+ PresetData data;
+
+ // When
+ data.setData(
+ /*wizard presets*/
+ {
+ aCategory("A.categ", "A", {"Desktop"}), // Only category "A.categ" exists
+ },
+ {
+ aUserPreset("Bad.Categ", "Desktop", "Windows8"), // Bad.Categ does not exist
+ },
+ {/*recents*/});
+
+ // Then
+ ASSERT_THAT(data.categories(), ElementsAre("A"));
+ ASSERT_THAT(data.presets(), ElementsAre(ElementsAre(PresetIs("A.categ", "Desktop"))));
+}
+
+TEST(QdsPresetModel, doesNotAddUserPresetIfWizardPresetItRefersToDoesNotExist)
+{
+ // Given
+ PresetData data;
+
+ // When
+ data.setData(
+ /*wizard presets*/
+ {
+ aCategory("A.categ", "A", {"Desktop"}),
+ },
+ {
+ aUserPreset("B.categ", "BadWizard", "Tablet"), // BadWizard referenced does not exist
+ },
+ {/*recents*/});
+
+ // Then
+ ASSERT_THAT(data.categories(), ElementsAre("A"));
+ ASSERT_THAT(data.presets(), ElementsAre(ElementsAre(PresetIs("A.categ", "Desktop"))));
+}
+
+TEST(QdsPresetModel, userPresetWithSameNameAsWizardPreset)
+{
+ // Given
+ PresetData data;
+
+ // When
+ data.setData(
+ /*wizard presets*/
+ {
+ aCategory("A.categ", "A", {"Desktop"}),
+ },
+ {
+ aUserPreset("A.categ", "Desktop", "Desktop"),
+ },
+ {/*recents*/});
+
+ // Then
+ ASSERT_THAT(data.categories(), ElementsAre("A", "Custom"));
+ ASSERT_THAT(data.presets(),
+ ElementsAre(ElementsAre(PresetIs("A.categ", "Desktop")),
+ ElementsAre(UserPresetIs("A.categ", "Desktop", "Desktop"))));
+}
+
+TEST(QdsPresetModel, recentOfUserPresetReferringToExistingWizardPreset)
+{
+ // Given
+ PresetData data;
+
+ // When
+ data.setData(
+ /*wizard presets*/
+ {
+ aCategory("A.categ", "A", {"Desktop"}),
+ },
+ {
+ aUserPreset("A.categ", "Desktop", "Windows 7"),
+ },
+ /*recents*/
+ {
+ {"A.categ", "Windows 7", "200 x 300", /*is user*/true}
+ });
+
+ // Then
+ ASSERT_THAT(data.categories(), ElementsAre("Recents", "A", "Custom"));
+ ASSERT_THAT(data.presets(),
+ ElementsAre(ElementsAre(UserPresetIs("A.categ", "Desktop", "Windows 7")),
+ ElementsAre(PresetIs("A.categ", "Desktop")),
+ ElementsAre(UserPresetIs("A.categ", "Desktop", "Windows 7"))));
+}
+
+TEST(QdsPresetModel, recentOfUserPresetReferringToNonexistingWizardPreset)
+{
+ // Given
+ PresetData data;
+
+ // When
+ data.setData(
+ /*wizard presets*/
+ {
+ aCategory("A.categ", "A", {"Desktop"}),
+ },
+ {
+ aUserPreset("A.categ", "Not-Desktop", "Windows 7"), // Non-existing Wizard Preset
+ },
+ /*recents*/
+ {
+ {"A.categ", "Windows 7", "200 x 300", /*is user*/true}
+ });
+
+ // Then
+ ASSERT_THAT(data.categories(), ElementsAre("A"));
+ ASSERT_THAT(data.presets(), ElementsAre(ElementsAre(PresetIs("A.categ", "Desktop"))));
+}
+
+TEST(QdsPresetModel, recentOfNonExistentUserPreset)
+{
+ // Given
+ PresetData data;
+
+ // When
+ data.setData(
+ /*wizard presets*/
+ {
+ aCategory("A.categ", "A", {"Desktop"}),
+ },
+ {/*user presets*/},
+ /*recents*/
+ {
+ {"A.categ", "Windows 7", "200 x 300", /*is user*/true}
+ });
+
+ // Then
+ ASSERT_THAT(data.categories(), ElementsAre("A"));
+ ASSERT_THAT(data.presets(), ElementsAre(ElementsAre(PresetIs("A.categ", "Desktop"))));
+}
+
+TEST(QdsPresetModel, recentsShouldNotBeSorted)
{
// Given
PresetData data;
@@ -171,6 +412,7 @@ TEST(QdsPresetModel, recentsShouldNotSorted)
aCategory("B.categ", "B", {"item c", "Mobile"}),
aCategory("Z.categ", "Z", {"Z.desktop"}),
},
+ {/*user presets*/},
/*recents*/
{
{"Z.categ", "Z.desktop", "200 x 300"},
@@ -197,6 +439,7 @@ TEST(QdsPresetModel, recentsOfSameWizardProjectButDifferentSizesAreRecognizedAsD
aCategory("A.categ", "A", {"Desktop"}),
aCategory("B.categ", "B", {"Mobile"}),
},
+ {/*user presets*/},
/*recents*/
{
{"B.categ", "Mobile", "400 x 400"},
@@ -223,6 +466,7 @@ TEST(QdsPresetModel, outdatedRecentsAreNotShown)
aCategory("A.categ", "A", {"Desktop"}),
aCategory("B.categ", "B", {"Mobile"}),
},
+ {/*user presets*/},
/*recents*/
{
{"B.categ", "NoLongerExists", "400 x 400"},
diff --git a/tests/auto/qml/qmldesigner/wizard/recentpresets-test.cpp b/tests/auto/qml/qmldesigner/wizard/recentpresets-test.cpp
index b1bb0e0626..745462f5c1 100644
--- a/tests/auto/qml/qmldesigner/wizard/recentpresets-test.cpp
+++ b/tests/auto/qml/qmldesigner/wizard/recentpresets-test.cpp
@@ -38,6 +38,16 @@ using namespace StudioWelcome;
constexpr char GROUP_NAME[] = "RecentPresets";
constexpr char ITEMS[] = "Wizards";
+namespace StudioWelcome {
+void PrintTo(const RecentPresetData &recent, std::ostream *os)
+{
+ *os << "{categId: " << recent.category << ", name: " << recent.presetName
+ << ", size: " << recent.sizeName << ", isUser: " << recent.isUserPreset;
+
+ *os << "}";
+}
+} // namespace StudioWelcome
+
class QdsRecentPresets : public ::testing::Test
{
protected:
@@ -73,7 +83,7 @@ TEST_F(QdsRecentPresets, readFromEmptyStore)
{
RecentPresetsStore store{&settings};
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents, IsEmpty());
}
@@ -82,7 +92,7 @@ TEST_F(QdsRecentPresets, readEmptyRecentPresets)
{
RecentPresetsStore store = aStoreWithOne("");
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents, IsEmpty());
}
@@ -91,25 +101,34 @@ TEST_F(QdsRecentPresets, readOneRecentPresetAsList)
{
RecentPresetsStore store = aStoreWithRecents({"category/preset:640 x 480"});
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
- ASSERT_THAT(recents, ElementsAre(RecentPreset("category", "preset", "640 x 480")));
+ ASSERT_THAT(recents, ElementsAre(RecentPresetData("category", "preset", "640 x 480")));
}
TEST_F(QdsRecentPresets, readOneRecentPresetAsString)
{
RecentPresetsStore store = aStoreWithOne("category/preset:200 x 300");
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
+
+ ASSERT_THAT(recents, ElementsAre(RecentPresetData("category", "preset", "200 x 300")));
+}
+
+TEST_F(QdsRecentPresets, readOneRecentUserPresetAsString)
+{
+ RecentPresetsStore store = aStoreWithOne("category/[U]preset:200 x 300");
+
+ std::vector<RecentPresetData> recents = store.fetchAll();
- ASSERT_THAT(recents, ElementsAre(RecentPreset("category", "preset", "200 x 300")));
+ ASSERT_THAT(recents, ElementsAre(RecentPresetData("category", "preset", "200 x 300", true)));
}
TEST_F(QdsRecentPresets, readBadRecentPresetAsString)
{
RecentPresetsStore store = aStoreWithOne("no_category_only_preset");
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents, IsEmpty());
}
@@ -118,24 +137,32 @@ TEST_F(QdsRecentPresets, readBadRecentPresetAsInt)
{
RecentPresetsStore store = aStoreWithOne(32);
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents, IsEmpty());
}
TEST_F(QdsRecentPresets, readBadRecentPresetsInList)
{
- RecentPresetsStore store = aStoreWithRecents({"bad1", // no category, no size
- "categ/name:800 x 600", // good
- "categ/bad2", //no size
- "categ/bad3:", //no size
- "categ 1/bad4:200 x 300", // category has space
- "categ/bad5: 400 x 300", // size starts with space
- "categ/bad6:400"}); // bad size
-
- std::vector<RecentPreset> recents = store.fetchAll();
+ RecentPresetsStore store = aStoreWithRecents({
+ "bad1", // no category, no size
+ "categ/name:800 x 600", // good
+ "categ/bad2", //no size
+ "categ/bad3:", //no size
+ "categ 1/bad4:200 x 300", // category has space
+ "categ/bad5: 400 x 300", // size starts with space
+ "categ/bad6:400", // bad size
+ "categ/[U]user:300 x 200", // good
+ "categ/[u]user2:300 x 200", // small cap "U"
+ "categ/[x]user3:300 x 200", // must be letter "U"
+ "categ/[U] user4:300 x 200", // space
+ });
+
+ std::vector<RecentPresetData> recents = store.fetchAll();
- ASSERT_THAT(recents, ElementsAre(RecentPreset("categ", "name", "800 x 600")));
+ ASSERT_THAT(recents,
+ ElementsAre(RecentPresetData("categ", "name", "800 x 600", false),
+ RecentPresetData("categ", "user", "300 x 200", true)));
}
TEST_F(QdsRecentPresets, readTwoRecentPresets)
@@ -143,11 +170,23 @@ TEST_F(QdsRecentPresets, readTwoRecentPresets)
RecentPresetsStore store = aStoreWithRecents(
{"category_1/preset 1:640 x 480", "category_2/preset 2:320 x 200"});
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
- ElementsAre(RecentPreset("category_1", "preset 1", "640 x 480"),
- RecentPreset("category_2", "preset 2", "320 x 200")));
+ ElementsAre(RecentPresetData("category_1", "preset 1", "640 x 480"),
+ RecentPresetData("category_2", "preset 2", "320 x 200")));
+}
+
+TEST_F(QdsRecentPresets, readRecentsToDifferentKindsOfPresets)
+{
+ RecentPresetsStore store = aStoreWithRecents(
+ {"category_1/preset 1:640 x 480", "category_2/[U]preset 2:320 x 200"});
+
+ std::vector<RecentPresetData> recents = store.fetchAll();
+
+ ASSERT_THAT(recents,
+ ElementsAre(RecentPresetData("category_1", "preset 1", "640 x 480", false),
+ RecentPresetData("category_2", "preset 2", "320 x 200", true)));
}
TEST_F(QdsRecentPresets, addFirstRecentPreset)
@@ -155,19 +194,44 @@ TEST_F(QdsRecentPresets, addFirstRecentPreset)
RecentPresetsStore store{&settings};
store.add("A.Category", "Normal Application", "400 x 600");
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
- ASSERT_THAT(recents, ElementsAre(RecentPreset("A.Category", "Normal Application", "400 x 600")));
+ ASSERT_THAT(recents, ElementsAre(RecentPresetData("A.Category", "Normal Application", "400 x 600")));
+}
+
+TEST_F(QdsRecentPresets, addFirstRecentUserPreset)
+{
+ RecentPresetsStore store{&settings};
+
+ store.add("A.Category", "Normal Application", "400 x 600", /*user preset*/ true);
+ std::vector<RecentPresetData> recents = store.fetchAll();
+
+ ASSERT_THAT(recents,
+ ElementsAre(RecentPresetData("A.Category", "Normal Application", "400 x 600", true)));
}
TEST_F(QdsRecentPresets, addExistingFirstRecentPreset)
{
- RecentPresetsStore store = aStoreWithRecents({"category/preset"});
+ RecentPresetsStore store = aStoreWithRecents({"category/preset:200 x 300"});
+ ASSERT_THAT(store.fetchAll(), ElementsAre(RecentPresetData("category", "preset", "200 x 300")));
store.add("category", "preset", "200 x 300");
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
+
+ ASSERT_THAT(recents, ElementsAre(RecentPresetData("category", "preset", "200 x 300")));
+}
- ASSERT_THAT(recents, ElementsAre(RecentPreset("category", "preset", "200 x 300")));
+TEST_F(QdsRecentPresets, addRecentUserPresetWithSameNameAsExistingRecentNormalPreset)
+{
+ RecentPresetsStore store = aStoreWithRecents({"category/preset:200 x 300"});
+ ASSERT_THAT(store.fetchAll(), ElementsAre(RecentPresetData("category", "preset", "200 x 300")));
+
+ store.add("category", "preset", "200 x 300", /*user preset*/ true);
+ std::vector<RecentPresetData> recents = store.fetchAll();
+
+ ASSERT_THAT(recents,
+ ElementsAre(RecentPresetData("category", "preset", "200 x 300", true),
+ RecentPresetData("category", "preset", "200 x 300", false)));
}
TEST_F(QdsRecentPresets, addSecondRecentPreset)
@@ -175,11 +239,11 @@ TEST_F(QdsRecentPresets, addSecondRecentPreset)
RecentPresetsStore store = aStoreWithRecents({"A.Category/Preset 1:800 x 600"});
store.add("A.Category", "Preset 2", "640 x 480");
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
- ElementsAre(RecentPreset("A.Category", "Preset 2", "640 x 480"),
- RecentPreset("A.Category", "Preset 1", "800 x 600")));
+ ElementsAre(RecentPresetData("A.Category", "Preset 2", "640 x 480"),
+ RecentPresetData("A.Category", "Preset 1", "800 x 600")));
}
TEST_F(QdsRecentPresets, addSecondRecentPresetSameKindButDifferentSize)
@@ -187,11 +251,11 @@ TEST_F(QdsRecentPresets, addSecondRecentPresetSameKindButDifferentSize)
RecentPresetsStore store = aStoreWithRecents({"A.Category/Preset:800 x 600"});
store.add("A.Category", "Preset", "640 x 480");
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
- ElementsAre(RecentPreset("A.Category", "Preset", "640 x 480"),
- RecentPreset("A.Category", "Preset", "800 x 600")));
+ ElementsAre(RecentPresetData("A.Category", "Preset", "640 x 480"),
+ RecentPresetData("A.Category", "Preset", "800 x 600")));
}
TEST_F(QdsRecentPresets, fetchesRecentPresetsInTheReverseOrderTheyWereAdded)
@@ -201,12 +265,12 @@ TEST_F(QdsRecentPresets, fetchesRecentPresetsInTheReverseOrderTheyWereAdded)
store.add("A.Category", "Preset 1", "640 x 480");
store.add("A.Category", "Preset 2", "640 x 480");
store.add("A.Category", "Preset 3", "800 x 600");
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
- ElementsAre(RecentPreset("A.Category", "Preset 3", "800 x 600"),
- RecentPreset("A.Category", "Preset 2", "640 x 480"),
- RecentPreset("A.Category", "Preset 1", "640 x 480")));
+ ElementsAre(RecentPresetData("A.Category", "Preset 3", "800 x 600"),
+ RecentPresetData("A.Category", "Preset 2", "640 x 480"),
+ RecentPresetData("A.Category", "Preset 1", "640 x 480")));
}
TEST_F(QdsRecentPresets, addingAnExistingRecentPresetMakesItTheFirst)
@@ -216,12 +280,12 @@ TEST_F(QdsRecentPresets, addingAnExistingRecentPresetMakesItTheFirst)
"A.Category/Preset 3:640 x 480"});
store.add("A.Category", "Preset 3", "640 x 480");
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
- ElementsAre(RecentPreset("A.Category", "Preset 3", "640 x 480"),
- RecentPreset("A.Category", "Preset 1", "200 x 300"),
- RecentPreset("A.Category", "Preset 2", "200 x 300")));
+ ElementsAre(RecentPresetData("A.Category", "Preset 3", "640 x 480"),
+ RecentPresetData("A.Category", "Preset 1", "200 x 300"),
+ RecentPresetData("A.Category", "Preset 2", "200 x 300")));
}
TEST_F(QdsRecentPresets, addingTooManyRecentPresetsRemovesTheOldestOne)
@@ -231,9 +295,9 @@ TEST_F(QdsRecentPresets, addingTooManyRecentPresetsRemovesTheOldestOne)
store.setMaximum(2);
store.add("A.Category", "Preset 3", "200 x 300");
- std::vector<RecentPreset> recents = store.fetchAll();
+ std::vector<RecentPresetData> recents = store.fetchAll();
ASSERT_THAT(recents,
- ElementsAre(RecentPreset("A.Category", "Preset 3", "200 x 300"),
- RecentPreset("A.Category", "Preset 2", "200 x 300")));
+ ElementsAre(RecentPresetData("A.Category", "Preset 3", "200 x 300"),
+ RecentPresetData("A.Category", "Preset 2", "200 x 300")));
}
diff --git a/tests/auto/qml/qmldesigner/wizard/userpresets-test.cpp b/tests/auto/qml/qmldesigner/wizard/userpresets-test.cpp
new file mode 100644
index 0000000000..8fa73402c0
--- /dev/null
+++ b/tests/auto/qml/qmldesigner/wizard/userpresets-test.cpp
@@ -0,0 +1,308 @@
+/****************************************************************************
+**
+** 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.
+**
+****************************************************************************/
+
+#include "test-utilities.h"
+#include "userpresets.h"
+
+#include <utils/filepath.h>
+#include <utils/temporarydirectory.h>
+
+namespace StudioWelcome {
+
+void PrintTo(const UserPresetData &preset, std::ostream *os)
+{
+ *os << "UserPresetData{category = " << preset.categoryId;
+ *os << "; wizardName = " << preset.wizardName;
+ *os << "; name = " << preset.name;
+ *os << "; screenSize = " << preset.screenSize;
+ *os << "; keyboard = " << preset.useQtVirtualKeyboard;
+ *os << "; qt = " << preset.qtVersion;
+ *os << "; style = " << preset.styleName;
+ *os << "}";
+}
+
+void PrintTo(const std::vector<UserPresetData> &presets, std::ostream *os)
+{
+ if (presets.size() == 0) {
+ *os << "{}" << std::endl;
+ } else {
+ *os << "{" << std::endl;
+ for (size_t i = 0; i < presets.size(); ++i) {
+ *os << "#" << i << ": ";
+ PrintTo(presets[i], os);
+ *os << std::endl;
+ }
+ *os << "}" << std::endl;
+ }
+}
+
+} // namespace StudioWelcome
+
+using namespace StudioWelcome;
+
+constexpr char ARRAY_NAME[] = "UserPresets";
+
+class QdsUserPresets : public ::testing::Test
+{
+protected:
+ void SetUp()
+ {
+ settings = std::make_unique<QSettings>(tempDir.filePath("test").toString(),
+ QSettings::IniFormat);
+ }
+
+ UserPresetsStore anEmptyStore() { return UserPresetsStore{std::move(settings)}; }
+
+ UserPresetsStore aStoreWithZeroItems()
+ {
+ settings->beginWriteArray(ARRAY_NAME, 0);
+ settings->endArray();
+
+ return UserPresetsStore{std::move(settings)};
+ }
+
+ UserPresetsStore aStoreWithOne(const UserPresetData &preset)
+ {
+ settings->beginWriteArray(ARRAY_NAME, 1);
+ settings->setArrayIndex(0);
+
+ settings->setValue("categoryId", preset.categoryId);
+ settings->setValue("wizardName", preset.wizardName);
+ settings->setValue("name", preset.name);
+ settings->setValue("screenSize", preset.screenSize);
+ settings->setValue("useQtVirtualKeyboard", preset.useQtVirtualKeyboard);
+ settings->setValue("qtVersion", preset.qtVersion);
+ settings->setValue("styleName", preset.styleName);
+
+ settings->endArray();
+
+ return UserPresetsStore{std::move(settings)};
+ }
+
+ UserPresetsStore aStoreWithPresets(const std::vector<UserPresetData> &presets)
+ {
+ settings->beginWriteArray(ARRAY_NAME, presets.size());
+
+ for (size_t i = 0; i < presets.size(); ++i) {
+ settings->setArrayIndex(i);
+ const auto &preset = presets[i];
+
+ settings->setValue("categoryId", preset.categoryId);
+ settings->setValue("wizardName", preset.wizardName);
+ settings->setValue("name", preset.name);
+ settings->setValue("screenSize", preset.screenSize);
+ settings->setValue("useQtVirtualKeyboard", preset.useQtVirtualKeyboard);
+ settings->setValue("qtVersion", preset.qtVersion);
+ settings->setValue("styleName", preset.styleName);
+ }
+ settings->endArray();
+
+ return UserPresetsStore{std::move(settings)};
+ }
+
+ Utils::TemporaryDirectory tempDir{"userpresets-XXXXXX"};
+ std::unique_ptr<QSettings> settings;
+
+private:
+ QString settingsPath;
+};
+
+/******************* TESTS *******************/
+
+TEST_F(QdsUserPresets, readEmptyUserPresets)
+{
+ auto store = anEmptyStore();
+
+ auto presets = store.fetchAll();
+
+ ASSERT_THAT(presets, IsEmpty());
+}
+
+TEST_F(QdsUserPresets, readEmptyArrayOfUserPresets)
+{
+ auto store = aStoreWithZeroItems();
+
+ auto presets = store.fetchAll();
+
+ ASSERT_THAT(presets, IsEmpty());
+}
+
+TEST_F(QdsUserPresets, readOneUserPreset)
+{
+ UserPresetData preset{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
+ auto store = aStoreWithOne(preset);
+
+ auto presets = store.fetchAll();
+
+ ASSERT_THAT(presets, ElementsAreArray({preset}));
+}
+
+TEST_F(QdsUserPresets, readOneIncompleteUserPreset)
+{
+ // A preset entry that has the required entries, but not the others.
+ UserPresetData preset{"A.categ", "3D App", "iPhone7", "", false, "", ""};
+ auto store = aStoreWithOne(preset);
+
+ auto presets = store.fetchAll();
+
+ ASSERT_THAT(presets, ElementsAreArray({preset}));
+}
+
+TEST_F(QdsUserPresets, doesNotReadPresetsThatLackRequiredEntries)
+{
+ // Required entries are: Category id, wizard name, preset name.
+ auto presetsInStore = std::vector<UserPresetData>{
+ UserPresetData{"", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
+ UserPresetData{"A.categ", "", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
+ UserPresetData{"A.categ", "3D App", "", "400 x 20", true, "Qt 5", "Material Dark"},
+ };
+ auto store = aStoreWithPresets(presetsInStore);
+
+ auto presets = store.fetchAll();
+
+ ASSERT_THAT(presets, IsEmpty());
+}
+
+TEST_F(QdsUserPresets, readSeveralUserPresets)
+{
+ auto presetsInStore = std::vector<UserPresetData>{
+ UserPresetData{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
+ UserPresetData{"B.categ", "2D App", "iPhone6", "200 x 50", false, "Qt 6", "Fusion"},
+ UserPresetData{"C.categ", "Empty", "Some Other", "60 x 30", true, "Qt 7", "Material Light"},
+ };
+ auto store = aStoreWithPresets(presetsInStore);
+
+ auto presets = store.fetchAll();
+
+ ASSERT_THAT(presets, ElementsAreArray(presetsInStore));
+}
+
+TEST_F(QdsUserPresets, cannotSaveInvalidPreset)
+{
+ // an invalid preset is a preset that lacks required fields.
+ UserPresetData invalidPreset{"", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
+ auto store = anEmptyStore();
+
+ bool saved = store.save(invalidPreset);
+
+ auto presets = store.fetchAll();
+ ASSERT_THAT(presets, IsEmpty());
+ ASSERT_FALSE(saved);
+}
+
+TEST_F(QdsUserPresets, savePresetInEmptyStore)
+{
+ UserPresetData preset{"B.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
+ auto store = anEmptyStore();
+
+ store.save(preset);
+
+ auto presets = store.fetchAll();
+ ASSERT_THAT(presets, ElementsAre(preset));
+}
+
+TEST_F(QdsUserPresets, saveIncompletePreset)
+{
+ UserPresetData preset{"C.categ", "2D App", "Android", "", false, "", ""};
+ auto store = anEmptyStore();
+
+ store.save(preset);
+
+ auto presets = store.fetchAll();
+ ASSERT_THAT(presets, ElementsAre(preset));
+}
+
+TEST_F(QdsUserPresets, cannotSavePresetWithSameName)
+{
+ UserPresetData existing{"B.categ", "3D App", "Same Name", "400 x 20", true, "Qt 5", "Material Dark"};
+ auto store = aStoreWithOne(existing);
+
+ UserPresetData newPreset{"C.categ", "Empty", "Same Name", "100 x 30", false, "Qt 6", "Fusion"};
+ bool saved = store.save(newPreset);
+
+ ASSERT_FALSE(saved);
+ ASSERT_THAT(store.fetchAll(), ElementsAreArray({existing}));
+}
+
+TEST_F(QdsUserPresets, saveNewPreset)
+{
+ UserPresetData existing{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
+ auto store = aStoreWithOne(existing);
+
+ UserPresetData newPreset{"A.categ", "Empty", "Huawei", "100 x 30", true, "Qt 6", "Fusion"};
+ store.save(newPreset);
+
+ auto presets = store.fetchAll();
+ ASSERT_THAT(presets, ElementsAre(existing, newPreset));
+}
+
+TEST_F(QdsUserPresets, removeUserPresetFromEmptyStore)
+{
+ UserPresetData preset{"C.categ", "2D App", "Android", "", false, "", ""};
+ auto store = anEmptyStore();
+
+ store.remove("A.categ", "User preset name");
+
+ auto presets = store.fetchAll();
+ ASSERT_THAT(presets, IsEmpty());
+}
+
+TEST_F(QdsUserPresets, removeExistingUserPreset)
+{
+ UserPresetData existing{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
+ auto store = aStoreWithOne(existing);
+
+ store.remove("A.categ", "iPhone7");
+
+ auto presets = store.fetchAll();
+ ASSERT_THAT(presets, IsEmpty());
+}
+
+TEST_F(QdsUserPresets, removeNonExistingUserPreset)
+{
+ UserPresetData existing{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"};
+ auto store = aStoreWithOne(existing);
+
+ store.remove("A.categ", "Android");
+
+ auto presets = store.fetchAll();
+ ASSERT_THAT(presets, ElementsAre(existing));
+}
+
+TEST_F(QdsUserPresets, removeExistingUserPresetInStoreWithManyPresets)
+{
+ auto presetsInStore = std::vector<UserPresetData>{
+ UserPresetData{"A.categ", "3D App", "iPhone7", "400 x 20", true, "Qt 5", "Material Dark"},
+ UserPresetData{"B.categ", "2D App", "iPhone6", "200 x 50", false, "Qt 6", "Fusion"},
+ UserPresetData{"C.categ", "Empty", "Some Other", "60 x 30", true, "Qt 7", "Material Light"},
+ };
+ auto store = aStoreWithPresets(presetsInStore);
+
+ store.remove("B.categ", "iPhone6");
+
+ auto presets = store.fetchAll();
+ ASSERT_THAT(presets, ElementsAre(presetsInStore[0], presetsInStore[2]));
+}
+
diff --git a/tests/auto/qml/qmldesigner/wizard/wizardfactories-test.cpp b/tests/auto/qml/qmldesigner/wizard/wizardfactories-test.cpp
index 30c79e9090..6541e7a163 100644
--- a/tests/auto/qml/qmldesigner/wizard/wizardfactories-test.cpp
+++ b/tests/auto/qml/qmldesigner/wizard/wizardfactories-test.cpp
@@ -151,7 +151,7 @@ private:
QStringList presetNames(const WizardCategory &cat)
{
- QStringList result = Utils::transform<QStringList>(cat.items, &PresetItem::name);
+ QStringList result = Utils::transform<QStringList>(cat.items, &PresetItem::wizardName);
return result;
}
@@ -319,9 +319,9 @@ TEST_F(QdsWizardFactories, createsPresetItemAndCategoryCorrectlyFromWizardFactor
ASSERT_EQ("myDisplayCategory", category.name);
auto presetItem = presets["myCategoryId"].items[0];
- ASSERT_EQ("myName", presetItem.name);
- ASSERT_EQ("myDescription", presetItem.description);
- ASSERT_EQ("qrc:/my/qml/path", presetItem.qmlPath.toString());
- ASSERT_EQ("\uABCD", presetItem.fontIconCode);
+ ASSERT_EQ("myName", presetItem->wizardName);
+ ASSERT_EQ("myDescription", presetItem->description);
+ ASSERT_EQ("qrc:/my/qml/path", presetItem->qmlPath.toString());
+ ASSERT_EQ("\uABCD", presetItem->fontIconCode);
}
diff --git a/tests/auto/ssh/tst_ssh.cpp b/tests/auto/ssh/tst_ssh.cpp
index 2f1a236b5f..26fb09caa0 100644
--- a/tests/auto/ssh/tst_ssh.cpp
+++ b/tests/auto/ssh/tst_ssh.cpp
@@ -206,7 +206,7 @@ void tst_Ssh::pristineConnectionObject()
QSsh::SshConnection connection((SshConnectionParameters()));
QCOMPARE(connection.state(), SshConnection::Unconnected);
QRegularExpression assertToIgnore(
- "SOFT ASSERT: \"state\\(\\) == Connected\" in file .*/sshconnection.cpp, line \\d*");
+ "SOFT ASSERT: \"state\\(\\) == Connected\" in file .*[/\\\\]sshconnection.cpp, line \\d*");
QTest::ignoreMessage(QtDebugMsg, assertToIgnore);
QVERIFY(!connection.createRemoteProcess(""));
QTest::ignoreMessage(QtDebugMsg, assertToIgnore);
diff --git a/tests/system/shared/build_utils.py b/tests/system/shared/build_utils.py
index b8187760fc..f74bea0df1 100644
--- a/tests/system/shared/build_utils.py
+++ b/tests/system/shared/build_utils.py
@@ -40,7 +40,7 @@ def checkLastBuild(expectedToFail=False, createTasksFileOnError=True):
test.log("checkLastBuild called without a build")
return
buildIssues = getBuildIssues()
- types = map(lambda i: i[5], buildIssues)
+ types = [i[5] for i in buildIssues]
errors = types.count("1")
warnings = types.count("2")
gotErrors = errors != 0
@@ -78,8 +78,8 @@ def waitForCompile(timeout=60000):
def dumpBuildIssues(listModel):
issueDump = []
for index in dumpIndices(listModel):
- issueDump.extend([map(lambda role: index.data(role).toString(),
- range(Qt.UserRole, Qt.UserRole + 6))])
+ issueDump.extend([[index.data(role).toString() for role
+ in range(Qt.UserRole, Qt.UserRole + 6)]])
return issueDump
# counter for written tasks files
diff --git a/tests/system/suite_HELP/tst_HELP04/test.py b/tests/system/suite_HELP/tst_HELP04/test.py
index 83941679b9..e78afa46b3 100644
--- a/tests/system/suite_HELP/tst_HELP04/test.py
+++ b/tests/system/suite_HELP/tst_HELP04/test.py
@@ -84,10 +84,9 @@ def main():
clickButton(waitForObject("{text='Search' type='QPushButton' unnamed='1' visible='1' "
"window=':Qt Creator_Core::Internal::MainWindow'}"))
resultWidget = waitForObject(':Hits_QResultWidget', 5000)
- if os.getenv("SYSTEST_BUILT_WITH_QT_5_13_1_OR_NEWER", "0") == "1":
- test.verify(waitFor("noMatch in "
- "str(resultWidget.plainText)", 2000),
- "Verifying if search did not match anything.")
+ test.verify(waitFor("noMatch in "
+ "str(resultWidget.plainText)", 2000),
+ "Verifying if search did not match anything.")
# workaround for "endless waiting cursor"
mouseClick(waitForObject("{column='0' container=':Qt Creator_QHelpContentWidget' "
"text='Qt Reference Documentation' type='QModelIndex'}"))
@@ -115,9 +114,8 @@ def main():
if not (searchKeyword == "QODBC" and JIRA.isBugStillOpen(10331)):
verifyUrl(urlDictionary[searchKeyword])
else:
- if os.getenv("SYSTEST_BUILT_WITH_QT_5_13_1_OR_NEWER", "0") == "1":
- test.verify(waitFor("noMatch in "
- "str(resultWidget.plainText)", 1000),
- "Verifying if search did not match anything for: " + searchKeyword)
+ test.verify(waitFor("noMatch in "
+ "str(resultWidget.plainText)", 1000),
+ "Verifying if search did not match anything for: " + searchKeyword)
# exit
invokeMenuItem("File", "Exit")
diff --git a/tests/system/suite_SCOM/tst_SCOM04/test.py b/tests/system/suite_SCOM/tst_SCOM04/test.py
index 511364c9f9..ad9320a01c 100644
--- a/tests/system/suite_SCOM/tst_SCOM04/test.py
+++ b/tests/system/suite_SCOM/tst_SCOM04/test.py
@@ -41,7 +41,10 @@ def main():
# create qt quick application
createNewQtQuickApplication(tempDir(), "SampleApp")
# create syntax error in cpp file
- openDocument("SampleApp.Sources.main\\.cpp")
+ if not openDocument("SampleApp.SampleApp.Source Files.main\\.cpp"):
+ test.fatal("Could not open main.cpp - exiting.")
+ invokeMenuItem("File", "Exit")
+ return
if not appendToLine(waitForObject(":Qt Creator_CppEditor::Internal::CPPEditorWidget"), "QQmlApplicationEngine engine;", "SyntaxError"):
invokeMenuItem("File", "Exit")
return