aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt3
-rw-r--r--CMakePresets.json3
-rw-r--r--README.md4
-rw-r--r--dist/branding/qtdesignstudio/CMakeLists.txt1
-rw-r--r--dist/branding/qtdesignstudio/QtCreatorIDEBranding.cmake18
-rw-r--r--dist/branding/qtdesignstudio/QtProject/QtDesignStudio.ini64
-rw-r--r--dist/branding/qtdesignstudio/QtProject/qtdesignstudio/EasingCurves.ini2
-rw-r--r--dist/branding/qtdesignstudio/images/logo/128/QtProject-qtcreator.pngbin0 -> 5276 bytes
-rw-r--r--dist/branding/qtdesignstudio/images/logo/16/QtProject-qtcreator.pngbin0 -> 482 bytes
-rw-r--r--dist/branding/qtdesignstudio/images/logo/24/QtProject-qtcreator.pngbin0 -> 529 bytes
-rw-r--r--dist/branding/qtdesignstudio/images/logo/256/QtProject-qtcreator.pngbin0 -> 10212 bytes
-rw-r--r--dist/branding/qtdesignstudio/images/logo/32/QtProject-qtcreator.pngbin0 -> 735 bytes
-rw-r--r--dist/branding/qtdesignstudio/images/logo/48/QtProject-qtcreator.pngbin0 -> 1889 bytes
-rw-r--r--dist/branding/qtdesignstudio/images/logo/512/QtProject-qtcreator.pngbin0 -> 24742 bytes
-rw-r--r--dist/branding/qtdesignstudio/images/logo/64/QtProject-qtcreator.pngbin0 -> 2656 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.icobin0 -> 120874 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_128x128.pngbin0 -> 5947 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]bin0 -> 12750 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_16x16.pngbin0 -> 509 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]bin0 -> 1098 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_256x256.pngbin0 -> 12750 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]bin0 -> 30033 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_32x32.pngbin0 -> 1098 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]bin0 -> 2410 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_512x512.pngbin0 -> 30033 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]bin0 -> 66441 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/Contents.json68
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_128x128.pngbin0 -> 5276 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]bin0 -> 10212 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_16x16.pngbin0 -> 482 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]bin0 -> 735 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_256x256.pngbin0 -> 10212 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]bin0 -> 24742 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_32x32.pngbin0 -> 735 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]bin0 -> 2656 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_512x512.pngbin0 -> 24742 bytes
-rw-r--r--dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]bin0 -> 54880 bytes
-rw-r--r--doc/config/macros.qdocconf3
-rw-r--r--doc/qtcreator/src/external-resources/external-resources-qds.qdoc40
-rw-r--r--doc/qtcreator/src/external-resources/external-resources.qdoc6
-rw-r--r--doc/qtcreator/src/howto/creator-external-tools.qdoc2
-rw-r--r--doc/qtcreator/src/linux-mobile/creator-embedded-platforms.qdoc2
-rw-r--r--doc/qtcreator/src/mcu/creator-mcu-dev.qdoc36
-rw-r--r--doc/qtcreator/src/overview/creator-only/creator-desktop-platforms.qdoc2
-rw-r--r--doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc16
-rw-r--r--doc/qtdesignstudio/images/baked-lightmaps-add-property.pngbin0 -> 6288 bytes
-rw-r--r--doc/qtdesignstudio/images/baked-lightmaps-edit-component.pngbin0 -> 10204 bytes
-rw-r--r--doc/qtdesignstudio/images/baked-lightmaps-exit-component.pngbin0 -> 8767 bytes
-rw-r--r--doc/qtdesignstudio/images/baked-lightmaps-navigator-blm.pngbin0 -> 26047 bytes
-rw-r--r--doc/qtdesignstudio/images/baked-lightmaps-navigator.pngbin0 -> 24344 bytes
-rw-r--r--doc/qtdesignstudio/images/baked-lightmaps-property-value.pngbin0 -> 7471 bytes
-rw-r--r--doc/qtdesignstudio/images/qds-mcu-target-deployment.pngbin0 -> 45811 bytes
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-animation-types.qdoc7
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-buttons.qdoc13
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc4
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc10
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-components.qdoc4
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-controls.qdoc39
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-data-models.qdoc8
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-images.qdoc4
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-mcu-support.qdocinc6
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-pathview-editor.qdocinc2
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-positioning.qdoc16
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-preset-components.qdoc2
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-shapes.qdoc11
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-text.qdoc6
-rw-r--r--doc/qtdesignstudio/src/components/qtquick-user-interaction-methods.qdoc5
-rw-r--r--doc/qtdesignstudio/src/mcus/qtdesignstudio-compatibility-with-mcu-sdks.qdoc29
-rw-r--r--doc/qtdesignstudio/src/mcus/qtdesignstudio-on-mcus.qdoc92
-rw-r--r--doc/qtdesignstudio/src/overviews/qtquick-animation-overview.qdoc4
-rw-r--r--doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc5
-rw-r--r--doc/qtdesignstudio/src/overviews/qtquick-creating-ui-logic.qdoc6
-rw-r--r--doc/qtdesignstudio/src/overviews/qtquick-export.qdoc2
-rw-r--r--doc/qtdesignstudio/src/overviews/qtquick-fonts.qdoc5
-rw-r--r--doc/qtdesignstudio/src/overviews/qtquick-motion-design.qdoc2
-rw-r--r--doc/qtdesignstudio/src/overviews/qtquick-prototyping.qdoc26
-rw-r--r--doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc28
-rw-r--r--doc/qtdesignstudio/src/qt-quick-effect-maker.qdoc93
-rw-r--r--doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc22
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-advanced.qdoc8
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-effect-maker-files.qdoc79
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-help-overview.qdoc2
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc4
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc12
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio-using-effect-maker-effects.qdoc44
-rw-r--r--doc/qtdesignstudio/src/qtdesignstudio.qdoc1
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc15
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-maya.qdoc4
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc4
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc5
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc93
-rw-r--r--doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-optimized-3d-scenes.qdoc8
-rw-r--r--doc/qtdesignstudio/src/views/creator-logical-operators.qdocinc3
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-components-view.qdoc2
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc4
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc5
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc5
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc6
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-connection-view.qdoc12
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-designer.qdoc8
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-properties.qdoc2
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-states.qdoc13
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-text-editor.qdoc4
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc3
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-timeline.qdoc3
-rw-r--r--doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc4
-rw-r--r--doc/qtdesignstudio/src/views/studio-workspaces.qdoc4
-rw-r--r--qtcreator.qbs2
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFilesDialog.qml2
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFolderDialog.qml3
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewEffectDialog.qml2
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewFolderDialog.qml8
-rw-r--r--share/qtcreator/qmldesigner/assetsLibraryQmlSources/RenameFolderDialog.qml2
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml15
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml1
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml20
-rw-r--r--share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml1
-rw-r--r--share/qtcreator/qmldesigner/designericons.json3
-rw-r--r--share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsProgressDialog.qml102
-rw-r--r--share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsSetupDialog.qml223
-rw-r--r--share/qtcreator/qmldesigner/insight/Main.qml417
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml5
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserItemName.qml68
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml60
-rw-r--r--share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml51
-rw-r--r--share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml1
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQml/TimerSpecifics.qml3
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TextAreaSpecifics.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TextFieldSpecifics.qml16
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml78
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentButton.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml47
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Controller.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml24
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/InsightSection.qml21
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ItemFilterComboBox.qml21
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml26
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml2
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml6
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/TextInputSection.qml (renamed from share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml)36
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir1
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml28
-rw-r--r--share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml5
-rw-r--r--share/qtcreator/qmldesigner/qt4mcu/metadata.qml14
-rw-r--r--share/qtcreator/qmldesigner/qt4mcu/qul-14.qml29
-rw-r--r--share/qtcreator/qmldesigner/qt4mcu/qul-17.qml29
-rw-r--r--share/qtcreator/qmldesigner/qt4mcu/qul-18.qml33
-rw-r--r--share/qtcreator/qmldesigner/qt4mcu/qul-19.qml33
-rw-r--r--share/qtcreator/qmldesigner/qt4mcu/qul-20.qml33
-rw-r--r--share/qtcreator/qmldesigner/qt4mcu/qul-21.qml36
-rw-r--r--share/qtcreator/qmldesigner/qt4mcu/qul-22.qml37
-rw-r--r--share/qtcreator/qmldesigner/qt4mcu/qul-23.qml211
-rw-r--r--share/qtcreator/qmldesigner/qt4mcu/qul-24.qml210
-rw-r--r--share/qtcreator/qmldesigner/statusbar/Main.qml10
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/app_mcu.qmlproject4
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json14
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Constants.qml.tpl2
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Screen01.ui.qml.tpl2
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/main.qml.tpl2
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json13
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl5
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl6
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/common/insight.tpl19
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/common/qmlcomponents.tpl2
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json13
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json13
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json13
-rw-r--r--share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json13
-rw-r--r--share/qtcreator/qmldesigner/toolbar/CrumbleBread.qml15
-rw-r--r--share/qtcreator/qmldesigner/toolbar/Main.qml26
-rw-r--r--share/qtcreator/qmldesigner/workspacePresets/Advanced-3D.wrk75
-rw-r--r--share/qtcreator/qmldesigner/workspacePresets/Animation-2D.wrk76
-rw-r--r--share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk61
-rw-r--r--share/qtcreator/qmldesigner/workspacePresets/Basic.wrk71
-rw-r--r--share/qtcreator/qmldesigner/workspacePresets/Code.wrk71
-rw-r--r--share/qtcreator/qmldesigner/workspacePresets/Essentials-3D.wrk63
-rw-r--r--share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk90
-rw-r--r--share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk76
-rw-r--r--share/qtcreator/qmldesigner/workspacePresets/Views-All.wrk71
-rw-r--r--share/qtcreator/qmldesigner/workspacePresets/order.json11
-rw-r--r--src/libs/3rdparty/sqlite/sqlite3.c7134
-rw-r--r--src/libs/3rdparty/sqlite/sqlite3.h202
-rw-r--r--src/libs/CMakeLists.txt9
-rw-r--r--src/libs/advanceddockingsystem/CMakeLists.txt4
-rw-r--r--src/libs/advanceddockingsystem/dockcontainerwidget.cpp8
-rw-r--r--src/libs/advanceddockingsystem/dockmanager.cpp1867
-rw-r--r--src/libs/advanceddockingsystem/dockmanager.h436
-rw-r--r--src/libs/advanceddockingsystem/dockwidget.cpp12
-rw-r--r--src/libs/advanceddockingsystem/workspace.cpp95
-rw-r--r--src/libs/advanceddockingsystem/workspace.h55
-rw-r--r--src/libs/advanceddockingsystem/workspacedialog.cpp198
-rw-r--r--src/libs/advanceddockingsystem/workspacedialog.h28
-rw-r--r--src/libs/advanceddockingsystem/workspaceinputdialog.cpp103
-rw-r--r--src/libs/advanceddockingsystem/workspaceinputdialog.h38
-rw-r--r--src/libs/advanceddockingsystem/workspacemodel.cpp214
-rw-r--r--src/libs/advanceddockingsystem/workspacemodel.h28
-rw-r--r--src/libs/advanceddockingsystem/workspaceview.cpp277
-rw-r--r--src/libs/advanceddockingsystem/workspaceview.h24
-rw-r--r--src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h6
-rw-r--r--src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h3
-rw-r--r--src/libs/sqlite/sqliteids.h4
-rw-r--r--src/libs/sqlite/sqlitelibraryinitializer.cpp2
-rw-r--r--src/libs/sqlite/sqlitelibraryinitializer.h2
-rw-r--r--src/libs/sqlite/sqlitereadstatement.h44
-rw-r--r--src/libs/sqlite/sqlitereadwritestatement.h54
-rw-r--r--src/libs/sqlite/sqlitesessions.cpp2
-rw-r--r--src/libs/sqlite/sqlitetransaction.h47
-rw-r--r--src/libs/utils/CMakeLists.txt2
-rw-r--r--src/libs/utils/smallstring.h7
-rw-r--r--src/libs/utils/transientscroll.cpp222
-rw-r--r--src/libs/utils/transientscroll.h51
-rw-r--r--src/libs/utils/uniqueobjectptr.h86
-rw-r--r--src/libs/utils/utils.qbs1
-rw-r--r--src/plugins/CMakeLists.txt26
-rw-r--r--src/plugins/coreplugin/manhattanstyle.cpp948
-rw-r--r--src/plugins/coreplugin/manhattanstyle.h116
-rw-r--r--src/plugins/coreplugin/outputpane.cpp4
-rw-r--r--src/plugins/coreplugin/outputpanemanager.cpp14
-rw-r--r--src/plugins/insight/CMakeLists.txt14
-rw-r--r--src/plugins/insight/Insight.json.in21
-rw-r--r--src/plugins/insight/insightmodel.cpp860
-rw-r--r--src/plugins/insight/insightmodel.h132
-rw-r--r--src/plugins/insight/insightplugin.cpp31
-rw-r--r--src/plugins/insight/insightplugin.h22
-rw-r--r--src/plugins/insight/insightview.cpp57
-rw-r--r--src/plugins/insight/insightview.h40
-rw-r--r--src/plugins/insight/insightwidget.cpp123
-rw-r--r--src/plugins/insight/insightwidget.h45
-rw-r--r--src/plugins/mcusupport/CMakeLists.txt1
-rw-r--r--src/plugins/mcusupport/mcubuildstep.cpp171
-rw-r--r--src/plugins/mcusupport/mcubuildstep.h37
-rw-r--r--src/plugins/mcusupport/mcusupportplugin.cpp7
-rw-r--r--src/plugins/mcusupport/mcusupportplugin.h4
-rw-r--r--src/plugins/qmldesigner/CMakeLists.txt258
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp4
-rw-r--r--src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h2
-rw-r--r--src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp4
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/designericons.h1
-rw-r--r--src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp5
-rw-r--r--src/plugins/qmldesigner/components/componentcore/qmleditormenu.cpp2
-rw-r--r--src/plugins/qmldesigner/components/componentcore/viewmanager.h2
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp5
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp2
-rw-r--r--src/plugins/qmldesigner/components/connectioneditor/connectionview.h2
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp5
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp8
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp2
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h2
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp20
-rw-r--r--src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h3
-rw-r--r--src/plugins/qmldesigner/components/debugview/debugview.cpp2
-rw-r--r--src/plugins/qmldesigner/components/debugview/debugview.h2
-rw-r--r--src/plugins/qmldesigner/components/edit3d/bakelights.cpp430
-rw-r--r--src/plugins/qmldesigner/components/edit3d/bakelights.h74
-rw-r--r--src/plugins/qmldesigner/components/edit3d/bakelightsconnectionmanager.cpp48
-rw-r--r--src/plugins/qmldesigner/components/edit3d/bakelightsconnectionmanager.h28
-rw-r--r--src/plugins/qmldesigner/components/edit3d/bakelightsdatamodel.cpp387
-rw-r--r--src/plugins/qmldesigner/components/edit3d/bakelightsdatamodel.h56
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp40
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dactions.h15
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dview.cpp80
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dview.h10
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp8
-rw-r--r--src/plugins/qmldesigner/components/edit3d/edit3dwidget.h1
-rw-r--r--src/plugins/qmldesigner/components/formeditor/dragtool.cpp6
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorview.cpp2
-rw-r--r--src/plugins/qmldesigner/components/formeditor/formeditorview.h2
-rw-r--r--src/plugins/qmldesigner/components/formeditor/toolbox.cpp4
-rw-r--r--src/plugins/qmldesigner/components/integration/designdocumentview.cpp1
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.cpp4
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.h4
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp82
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h2
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp2
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp28
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h2
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp9
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h6
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp42
-rw-r--r--src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h4
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp20
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h2
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp22
-rw-r--r--src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h3
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp27
-rw-r--r--src/plugins/qmldesigner/components/materialeditor/materialeditorview.h2
-rw-r--r--src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp2
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp40
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorview.cpp2
-rw-r--r--src/plugins/qmldesigner/components/navigator/navigatorview.h2
-rw-r--r--src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp7
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp13
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp85
-rw-r--r--src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h32
-rw-r--r--src/plugins/qmldesigner/components/resources/dockwidgets.css34
-rw-r--r--src/plugins/qmldesigner/components/texteditor/texteditorview.cpp13
-rw-r--r--src/plugins/qmldesigner/components/texteditor/texteditorview.h2
-rw-r--r--src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp25
-rw-r--r--src/plugins/qmldesigner/components/texteditor/texteditorwidget.h5
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp4
-rw-r--r--src/plugins/qmldesigner/components/textureeditor/textureeditorview.h2
-rw-r--r--src/plugins/qmldesigner/components/toolbar/toolbar.cpp28
-rw-r--r--src/plugins/qmldesigner/components/toolbar/toolbar.h8
-rw-r--r--src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp542
-rw-r--r--src/plugins/qmldesigner/components/toolbar/toolbarbackend.h21
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/asynchronousexplicitimagecache.cpp30
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp12
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.cpp10
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.h8
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h57
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/midsizeimagecacheprovider.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/include/abstractproperty.h4
-rw-r--r--src/plugins/qmldesigner/designercore/include/abstractview.h6
-rw-r--r--src/plugins/qmldesigner/designercore/include/asynchronousexplicitimagecache.h12
-rw-r--r--src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h12
-rw-r--r--src/plugins/qmldesigner/designercore/include/asynchronousimagecacheinterface.h12
-rw-r--r--src/plugins/qmldesigner/designercore/include/auxiliarydataproperties.h2
-rw-r--r--src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h8
-rw-r--r--src/plugins/qmldesigner/designercore/include/forwardview.h4
-rw-r--r--src/plugins/qmldesigner/designercore/include/import.h74
-rw-r--r--src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h3
-rw-r--r--src/plugins/qmldesigner/designercore/include/metainfo.h8
-rw-r--r--src/plugins/qmldesigner/designercore/include/model.h49
-rw-r--r--src/plugins/qmldesigner/designercore/include/modelfwd.h42
-rw-r--r--src/plugins/qmldesigner/designercore/include/modelnode.h6
-rw-r--r--src/plugins/qmldesigner/designercore/include/nodeinstanceview.h3
-rw-r--r--src/plugins/qmldesigner/designercore/include/nodemetainfo.h16
-rw-r--r--src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h11
-rw-r--r--src/plugins/qmldesigner/designercore/include/propertymetainfo.h34
-rw-r--r--src/plugins/qmldesigner/designercore/include/qmldesignercorelib_exports.h12
-rw-r--r--src/plugins/qmldesigner/designercore/include/qmldesignercorelib_global.h41
-rw-r--r--src/plugins/qmldesigner/designercore/include/qmlmodelnodefacade.h6
-rw-r--r--src/plugins/qmldesigner/designercore/include/rewriterview.h2
-rw-r--r--src/plugins/qmldesigner/designercore/include/subcomponentmanager.h4
-rw-r--r--src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp7
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp3
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/metainfo.cpp67
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp114
-rw-r--r--src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/model/abstractproperty.cpp1
-rw-r--r--src/plugins/qmldesigner/designercore/model/abstractview.cpp56
-rw-r--r--src/plugins/qmldesigner/designercore/model/bindingproperty.cpp4
-rw-r--r--src/plugins/qmldesigner/designercore/model/import.cpp71
-rw-r--r--src/plugins/qmldesigner/designercore/model/model.cpp210
-rw-r--r--src/plugins/qmldesigner/designercore/model/model_p.h81
-rw-r--r--src/plugins/qmldesigner/designercore/model/modelmerger.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/model/modelnode.cpp7
-rw-r--r--src/plugins/qmldesigner/designercore/model/modelresourcemanagementinterface.h39
-rw-r--r--src/plugins/qmldesigner/designercore/model/modelutils.cpp93
-rw-r--r--src/plugins/qmldesigner/designercore/model/modelutils.h24
-rw-r--r--src/plugins/qmldesigner/designercore/model/nodeabstractproperty.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/model/nodeproperty.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/model/plaintexteditmodifier.cpp46
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmlchangeset.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmlmodelnodefacade.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp1
-rw-r--r--src/plugins/qmldesigner/designercore/model/rewriterview.cpp2
-rw-r--r--src/plugins/qmldesigner/designercore/model/signalhandlerproperty.cpp4
-rw-r--r--src/plugins/qmldesigner/designercore/model/skipiterator.h77
-rw-r--r--src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp345
-rw-r--r--src/plugins/qmldesigner/designercore/model/texttomodelmerger.h8
-rw-r--r--src/plugins/qmldesigner/designercore/model/variantproperty.cpp4
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h17
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/modulescanner.cpp110
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/modulescanner.h46
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h327
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp5
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h42
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h4
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h6
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h52
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcher.h2
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcherinterface.h3
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h170
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp252
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h75
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp14
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h4
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp15
-rw-r--r--src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h15
-rw-r--r--src/plugins/qmldesigner/designmodewidget.cpp198
-rw-r--r--src/plugins/qmldesigner/puppetenvironmentbuilder.cpp6
-rw-r--r--src/plugins/qmldesigner/puppetenvironmentbuilder.h1
-rw-r--r--src/plugins/qmldesigner/qmldesignerconstants.h3
-rw-r--r--src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp92
-rw-r--r--src/plugins/qmldesigner/qmldesignerexternaldependencies.h5
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.cpp53
-rw-r--r--src/plugins/qmldesigner/qmldesignerplugin.h2
-rw-r--r--src/plugins/qmldesigner/qmldesignerprojectmanager.cpp60
-rw-r--r--src/plugins/qmldesigner/qtquickplugin/quick.metainfo1
-rw-r--r--src/plugins/qmldesigner/settingspage.cpp2
-rw-r--r--src/plugins/qmldesigner/shortcutmanager.cpp53
-rw-r--r--src/plugins/qmldesigner/shortcutmanager.h1
-rw-r--r--src/plugins/qmldesigner/studioplugin/studioplugin.metainfo11
-rw-r--r--src/plugins/qmldesigner/utils/filedownloader.cpp12
-rw-r--r--src/plugins/qmldesigner/utils/fileextractor.cpp8
-rw-r--r--src/plugins/qmldesigner/utils/multifiledownloader.cpp6
-rw-r--r--src/plugins/qmldesignerbase/CMakeLists.txt20
-rw-r--r--src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp247
-rw-r--r--src/plugins/qmldesignerbase/qmldesignerbaseplugin.h43
-rw-r--r--src/plugins/qmldesignerbase/studio/studioquickwidget.cpp (renamed from src/plugins/qmldesignerbase/utils/studioquickwidget.cpp)0
-rw-r--r--src/plugins/qmldesignerbase/studio/studioquickwidget.h (renamed from src/plugins/qmldesignerbase/utils/studioquickwidget.h)0
-rw-r--r--src/plugins/qmldesignerbase/studio/studiosettingspage.cpp217
-rw-r--r--src/plugins/qmldesignerbase/studio/studiosettingspage.h49
-rw-r--r--src/plugins/qmldesignerbase/studio/studiostyle.cpp992
-rw-r--r--src/plugins/qmldesignerbase/studio/studiostyle.h76
-rw-r--r--src/plugins/qmldesignerbase/utils/designerpaths.cpp45
-rw-r--r--src/plugins/qmldesignerbase/utils/designerpaths.h20
-rw-r--r--src/plugins/qmlprojectmanager/CMakeLists.txt60
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp368
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.h19
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/projectitem/filefilteritems.cpp (renamed from src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp)75
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/projectitem/filefilteritems.h (renamed from src/plugins/qmlprojectmanager/fileformat/filefilteritems.h)33
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp402
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h116
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/projectnode/qmlprojectnodes.cpp (renamed from src/plugins/qmlprojectmanager/qmlprojectnodes.cpp)4
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/projectnode/qmlprojectnodes.h (renamed from src/plugins/qmlprojectmanager/qmlprojectnodes.h)0
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp598
-rw-r--r--src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.h120
-rw-r--r--src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp198
-rw-r--r--src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.h22
-rw-r--r--src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp118
-rw-r--r--src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h103
-rw-r--r--src/plugins/qmlprojectmanager/qmlmainfileaspect.cpp2
-rw-r--r--src/plugins/qmlprojectmanager/qmlproject.cpp784
-rw-r--r--src/plugins/qmlprojectmanager/qmlproject.h162
-rw-r--r--src/plugins/qmlprojectmanager/qmlprojectmanager.qbs14
-rw-r--r--src/plugins/qmlprojectmanager/qmlprojectplugin.cpp1
-rw-r--r--src/plugins/studiowelcome/examplecheckout.cpp8
-rw-r--r--src/plugins/studiowelcome/qdsnewdialog.cpp5
-rw-r--r--src/plugins/studiowelcome/studiowelcomeplugin.cpp9
-rw-r--r--src/plugins/studiowelcome/stylemodel.cpp2
-rw-r--r--src/plugins/texteditor/texteditor.cpp4
-rw-r--r--src/plugins/texteditor/texteditor.h2
-rw-r--r--src/tools/CMakeLists.txt4
-rw-r--r--src/tools/qml2puppet/CMakeLists.txt4
-rw-r--r--src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp16
-rw-r--r--src/tools/qml2puppet/qml2puppet/editor3d/selectionboxgeometry.cpp10
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/instances.pri2
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserverdispatcher.cpp3
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/objectnodeinstance.cpp33
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/objectnodeinstance.h1
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.cpp5
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.h2
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/qt5bakelightsnodeinstanceserver.cpp235
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/qt5bakelightsnodeinstanceserver.h58
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp15
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp4
-rw-r--r--src/tools/qml2puppet/qml2puppet/instances/servernodeinstance.h1
-rw-r--r--src/tools/qml2puppet/qml2puppet/qml2puppetmain.cpp (renamed from src/tools/qml2puppet/qml2puppet/main.cpp)13
-rw-r--r--tests/CMakeLists.txt4
-rw-r--r--tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp49
-rw-r--r--tests/auto/qml/qmldesigner/coretests/tst_testcore.h3
-rw-r--r--tests/auto/qml/qmlprojectmanager/fileformat/CMakeLists.txt17
-rw-r--r--tests/unit/CMakeLists.txt1
-rw-r--r--tests/unit/README.md49
-rw-r--r--tests/unit/mockup/qmldesigner/designercore/include/itemlibraryinfo.h34
-rw-r--r--tests/unit/mockup/qmldesigner/designercore/include/metainfo.h41
-rw-r--r--tests/unit/mockup/qmldesigner/designercore/include/nodemetainfo.h89
-rw-r--r--tests/unit/mockup/qmldesigner/designercore/include/propertymetainfo.h49
-rw-r--r--tests/unit/tools/CMakeLists.txt1
-rw-r--r--tests/unit/tools/qmlprojectmanager/CMakeLists.txt16
-rw-r--r--tests/unit/tools/qmlprojectmanager/main.cpp95
-rw-r--r--tests/unit/unittest/CMakeLists.txt39
-rw-r--r--tests/unit/unittest/data/modulescanner/Example/qmldir5
-rw-r--r--tests/unit/unittest/data/qml/QmlTime/qmldir4
-rw-r--r--tests/unit/unittest/data/qml/Qt/labs/animation/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/Qt/labs/folderlistmodel/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/Qt/labs/lottieqt/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/Qt/labs/platform/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/Qt/labs/qmlmodels/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/Qt/labs/settings/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/Qt/labs/sharedimage/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/Qt/labs/wavefrontmesh/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/Qt/test/controls/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/Qt3D/Animation/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/Qt3D/Core/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/Qt3D/Extras/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/Qt3D/Input/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/Qt3D/Logic/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/Qt3D/Render/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/Qt5Compat/GraphicalEffects/private/qmldir21
-rw-r--r--tests/unit/unittest/data/qml/Qt5Compat/GraphicalEffects/qmldir60
-rw-r--r--tests/unit/unittest/data/qml/QtApplicationManager/Application/qmldir1
-rw-r--r--tests/unit/unittest/data/qml/QtApplicationManager/SystemUI/qmldir1
-rw-r--r--tests/unit/unittest/data/qml/QtApplicationManager/qmldir1
-rw-r--r--tests/unit/unittest/data/qml/QtCharts/qmldir10
-rw-r--r--tests/unit/unittest/data/qml/QtCore/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/QtDataVisualization/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtInsightTracker/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtInterfaceFramework/Media/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtInterfaceFramework/VehicleFunctions/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtInterfaceFramework/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtLocation/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtMultimedia/qmldir10
-rw-r--r--tests/unit/unittest/data/qml/QtOpcUa/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtPositioning/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQml/Base/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/QtQml/Models/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/QtQml/StateMachine/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQml/WorkerScript/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/QtQml/XmlListModel/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQml/qmldir10
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Controls/Basic/impl/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Controls/Basic/qmldir131
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Controls/Fusion/impl/qmldir20
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Controls/Fusion/qmldir111
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Controls/Imagine/impl/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Controls/Imagine/qmldir108
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Controls/Material/impl/qmldir26
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Controls/Material/qmldir115
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Controls/Universal/impl/qmldir14
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Controls/Universal/qmldir111
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Controls/impl/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Controls/qmldir16
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Dialogs/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Dialogs/quickimpl/qmldir57
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Effects/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Layouts/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/LocalStorage/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/NativeStyle/qmldir38
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Particles/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Pdf/qmldir22
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Scene2D/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Scene3D/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Shapes/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Templates/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Timeline/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Components/qmldir103
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Layouts/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/Hangul/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/OpenWNN/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/Pinyin/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/TCIme/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/Thai/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/qmldir12
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Settings/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Styles/Builtin/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Styles/qmldir30
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/qmldir25
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/Window/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/QtQuick/tooling/qmldir23
-rw-r--r--tests/unit/unittest/data/qml/QtQuick3D/AssetUtils/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/QtQuick3D/Effects/qmldir31
-rw-r--r--tests/unit/unittest/data/qml/QtQuick3D/Helpers/impl/qmldir12
-rw-r--r--tests/unit/unittest/data/qml/QtQuick3D/Helpers/qmldir21
-rw-r--r--tests/unit/unittest/data/qml/QtQuick3D/MaterialEditor/qmldir13
-rw-r--r--tests/unit/unittest/data/qml/QtQuick3D/ParticleEffects/qmldir10
-rw-r--r--tests/unit/unittest/data/qml/QtQuick3D/Particles3D/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/QtQuick3D/Physics/Helpers/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQuick3D/Physics/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtQuick3D/SpatialAudio/qmldir10
-rw-r--r--tests/unit/unittest/data/qml/QtQuick3D/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/QtRemoteObjects/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtScxml/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtSensors/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtTest/qmldir14
-rw-r--r--tests/unit/unittest/data/qml/QtTextToSpeech/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtVncServer/qmldir8
-rw-r--r--tests/unit/unittest/data/qml/QtWayland/Client/TextureSharing/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtWayland/Compositor/IviApplication/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtWayland/Compositor/PresentationTime/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtWayland/Compositor/QtShell/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtWayland/Compositor/TextureSharingExtension/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtWayland/Compositor/WlShell/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtWayland/Compositor/XdgShell/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtWayland/Compositor/qmldir12
-rw-r--r--tests/unit/unittest/data/qml/QtWebChannel/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtWebEngine/ControlsDelegates/qmldir36
-rw-r--r--tests/unit/unittest/data/qml/QtWebEngine/qmldir9
-rw-r--r--tests/unit/unittest/data/qml/QtWebSockets/qmldir7
-rw-r--r--tests/unit/unittest/data/qml/QtWebView/qmldir8
-rw-r--r--tests/unit/unittest/externaldependenciesmock.h44
-rw-r--r--tests/unit/unittest/google-using-declarations.h5
-rw-r--r--tests/unit/unittest/gtest-creator-printing.cpp27
-rw-r--r--tests/unit/unittest/gtest-creator-printing.h11
-rw-r--r--tests/unit/unittest/import-test.cpp340
-rw-r--r--tests/unit/unittest/listmodeleditor-test.cpp21
-rw-r--r--tests/unit/unittest/mocklistmodeleditorview.h16
-rw-r--r--tests/unit/unittest/model-test.cpp491
-rw-r--r--tests/unit/unittest/modelresourcemanagementmock.h42
-rw-r--r--tests/unit/unittest/modulescanner-test.cpp179
-rw-r--r--tests/unit/unittest/nodelistproperty-test.cpp32
-rw-r--r--tests/unit/unittest/projectstorage-test.cpp568
-rw-r--r--tests/unit/unittest/projectstoragemock.cpp89
-rw-r--r--tests/unit/unittest/projectstoragemock.h121
-rw-r--r--tests/unit/unittest/projectstoragepathwatchermock.h11
-rw-r--r--tests/unit/unittest/projectstorageupdater-test.cpp1660
-rw-r--r--tests/unit/unittest/qmldocumentparser-test.cpp66
-rw-r--r--tests/unit/unittest/qmlprojectmanager/CMakeLists.txt7
-rw-r--r--tests/unit/unittest/qmlprojectmanager/converters-test.cpp94
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/README.md32
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/converter/test-set-1/testfile.jsontoqml98
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/converter/test-set-1/testfile.qmlproject110
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/converter/test-set-1/testfile.qmltojson177
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/converter/test-set-2/testfile.jsontoqml54
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/converter/test-set-2/testfile.qmlproject44
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/converter/test-set-2/testfile.qmltojson91
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/MaterialBundle.qmlproject112
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/MaterialBundle.qmlproject.qtds1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/MaterialLibrary.qrc1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/CMakeLists.txt1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/CMakeLists.txt1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/AcrylicPaintMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/AluminiumMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/AsphaltMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/BrickMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CMakeLists.txt1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CarPaintGlitterMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CarPaintMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CarbonFiberMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CeramicMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/ChromeMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/ConcreteMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CopperMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/FabricMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/FabricRoughMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/FabricSatinMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/GlassMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/GlassTintedMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/GoldMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/LeatherMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/MirrorMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PaperMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PlasticMatteMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PlasticShinyMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PlasticTexturedMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/RubberMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SilverMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SteelBrushedMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SteelFloorMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SteelMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/StoneMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WaxMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WoodMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WoodParquetMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WoodPlanksMaterial.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/_asset_ref.json1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/acrylicpaint.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/aluminium.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/asphalt.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/brick.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/carbonfiber.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/carpaint.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/carpaintglitter.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/ceramic.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/chrome.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/concrete.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/copper.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/fabric.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/fabricrough.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/fabricsatin.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/glass.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/glasstinted.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/gold.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/images/material.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/images/material16.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/images/[email protected]1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/leather.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/mirror.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/paper.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/plasticmatte.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/plasticshiny.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/plastictextured.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/rubber.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/silver.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/steel.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/steelbrushed.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/steelfloor.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/stone.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/wax.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/wood.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/woodparquet.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/woodplanks.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_Opacity.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_Roughness.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_AmbientOcclusion.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_Color.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_Roughness.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Concrete032_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Concrete032_2K_Roughness.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/DiamondPlate001_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/DiamondPlate001_2K_Roughness.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric004_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_Displacement.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_Roughness.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_Displacement.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_Roughness.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/LDR_RGB1_3.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_Color.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_Roughness.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal009_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal009_2K_Roughness.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal029_2K_Displacement.jpg1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal029_2K_Displacement.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_AmbientOcclusion.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_Roughness.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_AmbientOcclusion.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_Color.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_Roughness.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_Color.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_Roughness.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_Color.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_Roughness.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_AmbientOcclusion.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_Color.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_NormalGL.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_Roughness.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/blurrynoise.tga1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/noisenormal.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/qmldir1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/CMakeLists.txt1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/SSS.frag1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/SSS.vert1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple.frag1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple.vert1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple_nf.frag1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple_nf.vert1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/glass.frag1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/glass.vert1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/satin.frag1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/satin.vert1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/App.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/CMakeLists.txt1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/CustomRoundButton.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/MaterialNames.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/MouseRotator.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/Screen01.ui.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/fonts/OpenSans-Bold.ttf1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/fonts/OpenSans-Regular.ttf1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/fonts/fonts.txt1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/Ground_ShadowMap.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/HDR/dark_mode.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/HDR/day_mode.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/LDR_RGB1_3.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/QtLogo_HD.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/innerMesh.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/lightToggle.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/outerMesh.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/perfhudicon.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/perfhudicon_on.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/White.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/checkmark.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/groundAlpha.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/qtlogo.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/scratchmap.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/shadow.png1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_AO.jpg1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_Albedo.jpg1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_Normal.jpg1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_Roughness.jpg1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/meshes/floor.mesh1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/content/meshes/materialBall.mesh1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/filelist.txt126
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/CMakeLists.txt1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/CMakeLists.txt1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/Constants.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/DirectoryFontLoader.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/EventListModel.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/EventListSimulator.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/designer/plugin.metainfo1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/qmldir1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/main.qml1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/qmlcomponents1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/qmlmodules1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/qtquickcontrols2.conf1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/share.qrc1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/src/app_environment.h1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/src/import_qml_plugins.h1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/src/main.cpp1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/file-filters/translations.db1
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/getter-setter/empty.qmlproject44
-rw-r--r--tests/unit/unittest/qmlprojectmanager/data/getter-setter/notEmpty.qmlproject96
-rw-r--r--tests/unit/unittest/qmlprojectmanager/projectitem-test.cpp539
-rw-r--r--tests/unit/unittest/qmltypesparser-test.cpp95
-rw-r--r--tests/unit/unittest/smallstring-test.cpp33
-rw-r--r--tests/unit/unittest/sqlitereadstatementmock.cpp1
-rw-r--r--tests/unit/unittest/sqlitereadstatementmock.h6
-rw-r--r--tests/unit/unittest/sqlitetransaction-test.cpp124
-rw-r--r--tests/unit/unittest/storagecache-test.cpp10
-rw-r--r--tests/unit/unittest/unittest-matchers.h68
-rw-r--r--tests/unit/unittest/unittest-utility-functions.h5
796 files changed, 27390 insertions, 10052 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d52a1c8b65b..55bf2bfca85 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -6,6 +6,7 @@ include(Utils)
env_with_default("QTC_BUILD_WITH_PCH" ENV_QTC_BUILD_WITH_PCH ON)
env_with_default("QTC_WITH_TESTS" ENV_QTC_WITH_TESTS OFF)
+env_with_default("QTC_WITH_QMLDESIGNER" ENV_QTC_WITH_QMLDESIGNER ON)
option(BUILD_WITH_PCH "Build with precompiled headers" "${ENV_QTC_BUILD_WITH_PCH}")
@@ -35,6 +36,8 @@ qtc_link_with_qt()
option(WITH_TESTS "Build Tests" ${ENV_QTC_WITH_TESTS})
add_feature_info("Build tests" ${WITH_TESTS} "")
+option(WITH_QMLDESIGNER "Build QmlDesigner" ${ENV_QTC_WITH_QMLDESIGNER})
+add_feature_info("Build QmlDesigner and related code" ${WITH_QMLDESIGNER} "")
option(WITH_DEBUG_CMAKE "Enabled CMake project debugging functionality" OFF)
option(SHOW_BUILD_DATE "Show build date in about dialog" OFF)
option(WITH_SANITIZE "Build with sanitizer enabled" OFF)
diff --git a/CMakePresets.json b/CMakePresets.json
index 2886bc7c125..b4b859933cd 100644
--- a/CMakePresets.json
+++ b/CMakePresets.json
@@ -7,7 +7,8 @@
"generator": "Ninja",
"cacheVariables": {
"BUILD_PLUGINS": "Core;Designer;DiffEditor;TextEditor;ProjectExplorer;CppEditor;CodePaster;Docker;Git;Help;QmakeProjectManager;CMakeProjectManager;ClangCodeModel;ClangTools;ClangFormat;Debugger;QtSupport;ResourceEditor;VcsBase;Welcome;LanguageClient;RemoteLinux",
- "BUILD_EXECUTABLES": "QtCreator;qtcreator_ctrlc_stub;qtcreator_process_stub;win64interrupt;qtcreator_processlauncher"
+ "BUILD_EXECUTABLES": "QtCreator;qtcreator_ctrlc_stub;qtcreator_process_stub;win64interrupt;qtcreator_processlauncher",
+ "WITH_QMLDESIGNER": "OFF"
}
}
]
diff --git a/README.md b/README.md
index 5a5301b3b52..151be8c678c 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@ The standalone binary packages support the following platforms:
* Windows 10 (64-bit) or later
* (K)Ubuntu Linux 20.04 (64-bit) or later
-* macOS 10.14 or later
+* macOS 10.15 or later
## Contributing
@@ -37,7 +37,7 @@ Prerequisites:
* Qt 6.2 or later. The Qt version that you use to build Qt Creator defines the
minimum platform versions that the result supports
- (Windows 10, RHEL/CentOS 8.4, Ubuntu 20.04, macOS 10.14 for Qt 6.2).
+ (Windows 10, RHEL/CentOS 8.4, Ubuntu 20.04, macOS 10.15 for Qt 6.2).
* Qt WebEngine module for QtWebEngine based help viewer
* On Windows:
* MinGW with GCC 9 or Visual Studio 2019 or later
diff --git a/dist/branding/qtdesignstudio/CMakeLists.txt b/dist/branding/qtdesignstudio/CMakeLists.txt
new file mode 100644
index 00000000000..7886ac3ef6d
--- /dev/null
+++ b/dist/branding/qtdesignstudio/CMakeLists.txt
@@ -0,0 +1 @@
+install(DIRECTORY QtProject DESTINATION "${IDE_DATA_PATH}")
diff --git a/dist/branding/qtdesignstudio/QtCreatorIDEBranding.cmake b/dist/branding/qtdesignstudio/QtCreatorIDEBranding.cmake
new file mode 100644
index 00000000000..9b805bff125
--- /dev/null
+++ b/dist/branding/qtdesignstudio/QtCreatorIDEBranding.cmake
@@ -0,0 +1,18 @@
+set(IDE_VERSION "4.2.0") # The IDE version.
+set(IDE_VERSION_COMPAT "4.2.0") # The IDE Compatibility version.
+set(IDE_VERSION_DISPLAY "4.2.0") # The IDE display version.
+set(IDE_COPYRIGHT_YEAR "2023") # The IDE current copyright year.
+
+set(IDE_SETTINGSVARIANT "QtProject") # The IDE settings variation.
+set(IDE_COPY_SETTINGSVARIANT "Nokia") # The IDE settings to initially import.
+set(IDE_DISPLAY_NAME "Qt Design Studio") # The IDE display name.
+set(IDE_ID "qtdesignstudio") # The IDE id (no spaces, lowercase!)
+set(IDE_CASED_ID "QtDesignStudio") # The cased IDE id (no spaces!)
+set(IDE_BUNDLE_IDENTIFIER "org.qt-project.${IDE_ID}") # The macOS application bundle identifier.
+
+set(PROJECT_USER_FILE_EXTENSION .qtds)
+set(IDE_DOC_FILE "qtdesignstudio/qtdesignstudio.qdocconf")
+set(IDE_DOC_FILE_ONLINE "qtdesignstudio/qtdesignstudio-online.qdocconf")
+
+set(IDE_ICON_PATH "${CMAKE_CURRENT_LIST_DIR}")
+set(IDE_LOGO_PATH "${CMAKE_CURRENT_LIST_DIR}")
diff --git a/dist/branding/qtdesignstudio/QtProject/QtDesignStudio.ini b/dist/branding/qtdesignstudio/QtProject/QtDesignStudio.ini
new file mode 100644
index 00000000000..4685e29f3bd
--- /dev/null
+++ b/dist/branding/qtdesignstudio/QtProject/QtDesignStudio.ini
@@ -0,0 +1,64 @@
+[Plugins]
+Ignored=AutoTest, Bazaar, ClangCodeModel, ClangTools, CMakeProjectManager, CVS, ClassView, CodePaster, CppEditor, CtfVisualizer, Designer, FakeVim, GLSLEditor, GenericProjectManager, IncrediBuild, Ios, Macros, Mercurial, ModelEditor, Perforce, PerfProfiler, ScxmlEditor, QbsProjectManager, Qnx, Subversion, Valgrind, VcsBase, Welcome, WinRt, Python
+ForceEnabled=Boot2Qt, StudioWelcome, QmlDesigner, ModuleTools, McuSupport
+
+[Core]
+NewDialog\LastCategory=H.StudioProject
+NewDialog\LastPlatform=Desktop
+NewDialog\ShowPlatformFilter=false
+NewDialog\AllowAllTemplates=false
+NewDialog\BlacklistedCategories=U.Java, R.Qt, T.Import, H.Project, U.General
+NewDialog\AlternativeWizardStyle=true
+CreatorTheme=design
+
+[Menu]
+HideBuild=true
+HideDebug=true
+HideAnalyze=true
+HideTools=true
+
+[QML]
+Designer\StandAloneMode=true
+Designer\EnableTimelineView=true
+Designer\DisableItemLibraryUpdateTimer=false
+Designer\NewWelcomePage=true
+Designer\EnableWelcomePageDownload=true
+Designer\OldStatesEditor=false
+Designer\TopToolBar=true
+
+[Bauhaus]
+LeftSideBar\Views=Library, Navigator
+LeftSideBar\Visible=true
+RightSideBar\VerticalPosition=@ByteArray(\0\0\0\xff\0\0\0\x1\0\0\0\x2\0\0\x2\xdf\0\0\0n\0\0\0\0\x1\x1\0\0\0\x2\0)
+RightSideBar\Views=Properties, ConnectionView
+RightSideBar\Visible=true
+
+[MainWindow]
+ModeSelectorLayout=2
+
+[OutputPanePlaceHolder]
+CurrentIndex=2
+
+[OutputPaneVisibility]
+size=1
+1\id=QtCreator.Pane.CompileOutput
+1\visible=false
+
+[Boot2Qt]
+adbStartEnabled=false
+flashActionDisabled=true
+
+[%General]
+OverrideLanguage=C
+[General]
+HideOptionCategories=C++, Debug, Designer, Kits, BuildAndRun, CPaster, LanguageClient, Version Control
+
+[Help]
+ContextHelpOption=3
+HomePage=qthelp://org.qt-project.qtdesignstudio.200/doc/studio-getting-started.html
+
+[ProjectExplorer]
+Settings\ShowRunOutput=0
+
+[KeyboardShortcutsV2]
+QtCreator.ReturnToEditor=
diff --git a/dist/branding/qtdesignstudio/QtProject/qtdesignstudio/EasingCurves.ini b/dist/branding/qtdesignstudio/QtProject/qtdesignstudio/EasingCurves.ini
new file mode 100644
index 00000000000..4e7a5b3ab11
--- /dev/null
+++ b/dist/branding/qtdesignstudio/QtProject/qtdesignstudio/EasingCurves.ini
@@ -0,0 +1,2 @@
+[General]
+EasingCurveList=@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\f\0l\0i\0n\0\x65\0\x61\0r-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xc9\x99\x99\x99\x99\x99\x9a?\xc9\x99\x99\x99\x99\x99\x9a?\xe9\x99\x99\x99\x99\x99\x9a?\xe9\x99\x99\x99\x99\x99\x9a?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x14\0\x65\0\x61\0s\0\x65\0I\0n\0S\0i\0n\0\x65-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xde\x14z\xe1G\xae\x14\0\0\0\0\0\0\0\0?\xe7\xd7\n=p\xa3\xd7?\xe6\xe1G\xae\x14z\xe1?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x16\0\x65\0\x61\0s\0\x65\0O\0u\0t\0S\0i\0n\0\x65-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xd8\xf5\xc2\x8f\\(\xf6?\xe2\x66\x66\x66\x66\x66\x66?\xe2\x14z\xe1G\xae\x14?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x1a\0\x65\0\x61\0s\0\x65\0I\0n\0O\0u\0t\0S\0i\0n\0\x65-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xdcz\xe1G\xae\x14{?\xa9\x99\x99\x99\x99\x99\x9a?\xe1\x99\x99\x99\x99\x99\x9a?\xee\x66\x66\x66\x66\x66\x66?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x14\0\x65\0\x61\0s\0\x65\0I\0n\0Q\0u\0\x61\0\x64-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xe1\x99\x99\x99\x99\x99\x9a?\xb5\xc2\x8f\\(\xf5\xc3?\xe5\xc2\x8f\\(\xf5\xc3?\xe0\xf5\xc2\x8f\\(\xf6?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x16\0\x65\0\x61\0s\0\x65\0O\0u\0t\0Q\0u\0\x61\0\x64-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xd0\0\0\0\0\0\0?\xddp\xa3\xd7\n=q?\xdc\xcc\xcc\xcc\xcc\xcc\xcd?\xee\x14z\xe1G\xae\x14?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x1a\0\x65\0\x61\0s\0\x65\0I\0n\0O\0u\0t\0Q\0u\0\x61\0\x64-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xdd\x1e\xb8Q\xeb\x85\x1f?\x9e\xb8Q\xeb\x85\x1e\xb8?\xe0z\xe1G\xae\x14{?\xee\x8f\\(\xf5\xc2\x8f?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x16\0\x65\0\x61\0s\0\x65\0I\0n\0\x43\0u\0\x62\0i\0\x63-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xe1\x99\x99\x99\x99\x99\x9a?\xac(\xf5\xc2\x8f\\)?\xe5\x99\x99\x99\x99\x99\x9a?\xc8Q\xeb\x85\x1e\xb8R?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x18\0\x65\0\x61\0s\0\x65\0O\0u\0t\0\x43\0u\0\x62\0i\0\x63-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xcb\x85\x1e\xb8Q\xeb\x85?\xe3\x85\x1e\xb8Q\xeb\x85?\xd6\xb8Q\xeb\x85\x1e\xb8?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x1c\0\x65\0\x61\0s\0\x65\0I\0n\0O\0u\0t\0\x43\0u\0\x62\0i\0\x63-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xe4\xa3\xd7\n=p\xa4?\xa7\n=p\xa3\xd7\n?\xd6\xb8Q\xeb\x85\x1e\xb8?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x16\0\x65\0\x61\0s\0\x65\0I\0n\0Q\0u\0\x61\0r\0t-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xec\xa3\xd7\n=p\xa4?\x9e\xb8Q\xeb\x85\x1e\xb8?\xe5\xeb\x85\x1e\xb8Q\xec?\xcc(\xf5\xc2\x8f\\)?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x18\0\x65\0\x61\0s\0\x65\0O\0u\0t\0Q\0u\0\x61\0r\0t-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xc5\x1e\xb8Q\xeb\x85\x1f?\xea\xe1G\xae\x14z\xe1?\xdc(\xf5\xc2\x8f\\)?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x1c\0\x65\0\x61\0s\0\x65\0I\0n\0O\0u\0t\0Q\0u\0\x61\0r\0t-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xe8\xa3\xd7\n=p\xa4\0\0\0\0\0\0\0\0?\xc6\x66\x66\x66\x66\x66\x66?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x16\0\x65\0\x61\0s\0\x65\0I\0n\0Q\0u\0i\0n\0t-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xe8(\xf5\xc2\x8f\\)?\xa9\x99\x99\x99\x99\x99\x9a?\xeb\\(\xf5\xc2\x8f\\?\xae\xb8Q\xeb\x85\x1e\xb8?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x18\0\x65\0\x61\0s\0\x65\0O\0u\0t\0Q\0u\0i\0n\0t-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xcdp\xa3\xd7\n=q?\xf0\0\0\0\0\0\0?\xd4z\xe1G\xae\x14{?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x1c\0\x65\0\x61\0s\0\x65\0I\0n\0O\0u\0t\0Q\0u\0i\0n\0t-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xeb\x85\x1e\xb8Q\xeb\x85\0\0\0\0\0\0\0\0?\xb1\xeb\x85\x1e\xb8Q\xec?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x14\0\x65\0\x61\0s\0\x65\0I\0n\0\x45\0x\0p\0o-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xee\x66\x66\x66\x66\x66\x66?\xa9\x99\x99\x99\x99\x99\x9a?\xe9p\xa3\xd7\n=q?\xa1\xeb\x85\x1e\xb8Q\xec?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x16\0\x65\0\x61\0s\0\x65\0O\0u\0t\0\x45\0x\0p\0o-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xc8Q\xeb\x85\x1e\xb8R?\xf0\0\0\0\0\0\0?\xcc(\xf5\xc2\x8f\\)?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x1a\0\x65\0\x61\0s\0\x65\0I\0n\0O\0u\0t\0\x45\0x\0p\0o-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x14\0\x65\0\x61\0s\0\x65\0I\0n\0\x43\0i\0r\0\x63-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xe3\x33\x33\x33\x33\x33\x33?\xa4z\xe1G\xae\x14{?\xef\\(\xf5\xc2\x8f\\?\xd5p\xa3\xd7\n=q?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x16\0\x65\0\x61\0s\0\x65\0O\0u\0t\0\x43\0i\0r\0\x63-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xb3\x33\x33\x33\x33\x33\x33?\xea=p\xa3\xd7\n=?\xc5\x1e\xb8Q\xeb\x85\x1f?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x1a\0\x65\0\x61\0s\0\x65\0I\0n\0O\0u\0t\0\x43\0i\0r\0\x63-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xe9\x1e\xb8Q\xeb\x85\x1f?\xc1G\xae\x14z\xe1H?\xc3\x33\x33\x33\x33\x33\x33?\xeb\x85\x1e\xb8Q\xeb\x85?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x14\0\x65\0\x61\0s\0\x65\0I\0n\0\x42\0\x61\0\x63\0k-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xe3\x33\x33\x33\x33\x33\x33\xbf\xd1\xeb\x85\x1e\xb8Q\xec?\xe7\x85\x1e\xb8Q\xeb\x85?\xa7\n=p\xa3\xd7\n?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x16\0\x65\0\x61\0s\0\x65\0O\0u\0t\0\x42\0\x61\0\x63\0k-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xc6\x66\x66\x66\x66\x66\x66?\xecQ\xeb\x85\x1e\xb8R?\xd4z\xe1G\xae\x14{?\xf4Q\xeb\x85\x1e\xb8R?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x1a\0\x65\0\x61\0s\0\x65\0I\0n\0O\0u\0t\0\x42\0\x61\0\x63\0k-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x3?\xe5\xc2\x8f\\(\xf5\xc3\xbf\xe1\x99\x99\x99\x99\x99\x9a?\xd0\xf5\xc2\x8f\\(\xf6?\xf8\xcc\xcc\xcc\xcc\xcc\xcd?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x1a\0\x65\0\x61\0s\0\x65\0I\0n\0\x45\0l\0\x61\0s\0t\0i\0\x63-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\xf?\xd0r\xb0 \xc4\x9b\xa6\xbf~do\x15\x61\x91\x15?\xd6\x66\x66\x66\x66\x66\x66?\xac\x9e\xec\xbf\xb1[W?\xdcj~\xf9\xdb\"\xd1?\xaaxl\"h\t\xd5?\xe1\xeV\x4\x18\x93u?\xab\x98\xc7\xe2\x82@\xb8?\xe3\\(\xf5\xc2\x8f\\\xbf\x90\x96\xbb\x98\xc7\xe2\x82?\xe5\x6$\xdd/\x1a\xa0\xbf\x9b\xc0\x1a\x36\xe2\xeb\x1c?\xe7\xb6\x45\xa1\xca\xc0\x83\xbf\x88*\x99\x30\xbe\r\xed?\xe7t\xbcj~\xf9\xdb?\xbf\xbev\xc8\xb4\x39X?\xe8\xd4\xfd\xf3\xb6\x45\xa2?\xc5\x81\x6$\xdd/\x1b?\xea=p\xa3\xd7\n=?\xc0\xc4\x9b\xa5\xe3S\xf8?\xea\xf1\xa9\xfb\xe7l\x8b\xbf\xa6\xd5\xcf\xaa\xcd\x9e\x84?\xec(\xf5\xc2\x8f\\)\xbf\xb5\x81\x6$\xdd/\x1b?\xed/\x1a\x9f\xbev\xc9\xbf\xa4\x95\x18*\x99\x30\xbe?\xee\x8f\\(\xf5\xc2\x8f?\xdb\xa5\xe3S\xf7\xce\xd9?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x1c\0\x65\0\x61\0s\0\x65\0O\0u\0t\0\x45\0l\0\x61\0s\0t\0i\0\x63-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\xf?\xa3\xdd\x97\xf6+j\xe8?\xdc\xed\x91hr\xb0!?\xa0\x62M\xd2\xf1\xa9\xfc?\xf2\x66\x66\x66\x66\x66\x66?\xb0'RT`\xaa\x65?\xf3\x85\x1e\xb8Q\xeb\x85?\xbc\xac\b1&\xe9y?\xf2\x66\x66\x66\x66\x66\x66?\xc2\xd7\x93\xac\xbaY\x1e?\xec\x8c ]\x1a\x1\xf0?\xc8\xba\xe7\xa4\x89\x32\x35?\xeb}\xcaY\x1n{?\xce;\xed\xc9\x66\x61O?\xec\xf6\x9fV\xf5$\xc1?\xd3\x43\x95\x81\x6$\xdd?\xf1G\xae\x14z\xe1H?\xd7K\xc6\xa7\xef\x9d\xb2?\xf0\xa3\xd7\n=p\xa4?\xdc\xcc\xcc\xcc\xcc\xcc\xcd?\xee\x14z\xe1G\xae\x14?\xe4Z\x1c\xac\b1'?\xef\xe7l\x8b\x43\x95\x81?\xe5\xd2\xf1\xa9\xfb\xe7m?\xf0Q\xeb\x85\x1e\xb8R?\xe7\xdf;dZ\x1c\xac?\xf0\xa3\xd7\n=p\xa4?\xe8\xcc\xcc\xcc\xcc\xcc\xcd?\xef\xae\x14z\xe1G\xae?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0 \0\x65\0\x61\0s\0\x65\0I\0n\0O\0u\0t\0\x45\0l\0\x61\0s\0t\0i\0\x63-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x15?\xacPH\x16\xf0\x6\x8e?\xa3\xb6\x45\xa1\xca\xc0\x83?\xb4`\xaa\x64\xc2\xf8\x38\xbf\xa3\x81\xd7\xdb\xf4\x87\xfd?\xbb\xe7l\x8b\x43\x95\x81\xbf\xa3\x81\xd7\xdb\xf4\x87\xfd?\xc1\xa9\xfb\xe7l\x8b\x44\xbf\xa3\x81\xd7\xdb\xf4\x87\xfd?\xc7\xae\x14z\xe1G\xae?\x9c\x43,\xa5zxl?\xccj~\xf9\xdb\"\xd1?l\xea\xf2Q\xc1\x93\xb4?\xd0\x93t\xbcj~\xfa\xbf\x94\xfd\xf3\xb6\x45\xa1\xcb?\xd5?|\xed\x91hs\xbf\xd0\0\0\0\0\0\0?\xd8\xa3\xd7\n=p\xa4\xbf\xd0 \xc4\x9b\xa5\xe3T?\xdd\x91hr\xb0 \xc5\xbf\xc1\xeb\x85\x1e\xb8Q\xec?\xe1`A\x89\x37K\xc7?\xf2\xe1G\xae\x14z\xe1?\xe3\xbev\xc8\xb4\x39X?\xf3\xd7\n=p\xa3\xd7?\xe5\xa1\xca\xc0\x83\x12o?\xf3\xd7\n=p\xa3\xd7?\xe7\x9d\xb2-\xeV\x4?\xf0\0\0\0\0\0\0?\xe8\xe5`A\x89\x37L?\xef\x43\x95\x81\x6$\xdd?\xea$\xdd/\x1a\x9f\xbe?\xee~\xf9\xdb\"\xd0\xe5?\xeb\\(\xf5\xc2\x8f\\?\xf0Q\xeb\x85\x1e\xb8R?\xecr\xb0 \xc4\x9b\xa6?\xf0z\xe1G\xae\x14{?\xed\x91hr\xb0 \xc5?\xf0z\xe1G\xae\x14{?\xeen\x97\x8dO\xdf;?\xee\xd9\x16\x87+\x2\f?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", @Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x18\0\x65\0\x61\0s\0\x65\0I\0n\0\x42\0o\0u\0n\0\x63\0\x65-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\xf?\xb1\xe4\xf7\x65\xfd\x8a\xdb?U\xf4^\vN\x11\xdc?\xb5\xa1\xca\xc0\x83\x12o?\xb3\xf1\x41 [\xc0\x1a?\xbc\xac\b1&\xe9y?\xb3\xf1\x41 [\xc0\x1a?\xc1\xca\xc0\x83\x12n\x98?\xb3\xf1\x41 [\xc0\x1a?\xc7l\x8b\x43\x95\x81\x6\xbful\roTK\xb2?\xcc\xac\b1&\xe9y\xbful\roTK\xb2?\xd1\x6$\xdd/\x1a\xa0\xbful\roTK\xb2?\xd4\xdd/\x1a\x9f\xbew?\xd0\x31&\xe9x\xd4\xfe?\xd8\xc4\x9b\xa5\xe3S\xf8?\xd0\x31&\xe9x\xd4\xfe?\xdc\xbcj~\xf9\xdb#?\xd0\x31&\xe9x\xd4\xfe?\xdf|\xed\x91hr\xb0?U\xf4^\vN\x11\xdc?\xe3\x2\fI\xba^5\xbfh\xe7W\x92\x8e\f\x9e?\xe6\x45\xa1\xca\xc0\x83\x12\xbf~do\x15\x61\x91\x15?\xe8\x8b\x43\x95\x81\x6%?\xe9\x99\x99\x99\x99\x99\x9a?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0), "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x1a\0\x65\0\x61\0s\0\x65\0O\0u\0t\0\x42\0o\0u\0n\0\x63\0\x65-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\xf?\xcd\xd2\xf1\xa9\xfb\xe7m?\xc4\x9b\xa5\xe3S\xf7\xcf?\xd0\xe5`A\x89\x37L?\xef\xe7l\x8b\x43\x95\x81?\xd9&\xe9x\xd4\xfd\xf4?\xef\xe7l\x8b\x43\x95\x81?\xe0\xb4\x39X\x10\x62N?\xef\xe7l\x8b\x43\x95\x81?\xe1\xc2\x8f\\(\xf5\xc3?\xe8\x10\x62M\xd2\xf1\xaa?\xe3\x85\x1e\xb8Q\xeb\x85?\xe8\0\0\0\0\0\0?\xe5?|\xed\x91hs?\xe7\xef\x9d\xb2-\xeV?\xe7\x8dO\xdf;dZ?\xf0\0\0\0\0\0\0?\xe8\xcc\xcc\xcc\xcc\xcc\xcd?\xf0\0\0\0\0\0\0?\xea\fI\xba^5??\xef\xf7\xce\xd9\x16\x87+?\xeb\x8dO\xdf;dZ?\xec\xd4\xfd\xf3\xb6\x45\xa2?\xecj~\xf9\xdb\"\xd1?\xec\xd4\xfd\xf3\xb6\x45\xa2?\xedO\xdf;dZ\x1d?\xec\xd4\xfd\xf3\xb6\x45\xa2?\xed\x89\x37K\xc6\xa7\xf0?\xef\xd7\n=p\xa3\xd7?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)", "@Variant(\0\0\0\x7f\0\0\0\x1eQmlDesigner::NamedEasingCurve\0\0\0\0\x1e\0\x65\0\x61\0s\0\x65\0I\0n\0O\0u\0t\0\x42\0o\0u\0n\0\x63\0\x65-\0\0\0\0\0\0\0\0\x1?\xd3\x33\x33\x33\x33\x33\x33?\xf0\0\0\0\0\0\0?\xfb\x39\xab\xf3\x38qa\0\0\0\x1e?\xa8\xd4\xfd\xf3\xb6\x45\xa2?wc^t)\x9d\x88?\xaeOv_\xd8\xad\xac?\xa5\xf6\xfd!\xff.I?\xb5\xdc\xc6?\x14\x12\x6?\xa7\x17X\xe2\x19\x65,?\xbcj~\xf9\xdb\"\xd1?\xa8\x37\xb4\xa2\x33\x9c\xf?\xbd/\x1a\x9f\xbev\xc9\xbfh\xe7W\x92\x8e\f\x9e?\xc3t\xbcj~\xf9\xdb\xbfh\xe7W\x92\x8e\f\x9e?\xc8Q\xeb\x85\x1e\xb8R\xbfh\xe7W\x92\x8e\f\x9e?\xcb\x64Z\x1c\xac\b1?\xbf|\xed\x91hr\xb0?\xcf|\xed\x91hr\xb0?\xbf\xbev\xc8\xb4\x39X?\xd1\xdb\"\xd0\xe5`B?\xc0\0\0\0\0\0\0?\xd3\x12n\x97\x8dO\xdf?l\xea\xf2Q\xc1\x93\xb4?\xd6\x87+\x2\fI\xba?l\xea\xf2Q\xc1\x93\xb4?\xd9\xfb\xe7l\x8b\x43\x96?l\xea\xf2Q\xc1\x93\xb4?\xdd\xeV\x4\x18\x93u?\xdd`A\x89\x37K\xc7?\xe0(\xf5\xc2\x8f\\)?\xdf\xdf;dZ\x1c\xac?\xe1\xca\xc0\x83\x12n\x98?\xe1/\x1a\x9f\xbev\xc9?\xe1\xb2-\xeV\x4\x19?\xf0\0\0\0\0\0\0?\xe4\0\0\0\0\0\0?\xf0\0\0\0\0\0\0?\xe6M\xd2\xf1\xa9\xfb\xe7?\xf0\0\0\0\0\0\0?\xe6\xf1\xa9\xfb\xe7l\x8b?\xeb\xd7\n=p\xa3\xd7?\xe7\xf7\xce\xd9\x16\x87+?\xeb\xd7\n=p\xa3\xd7?\xe8\xfd\xf3\xb6\x45\xa1\xcb?\xeb\xd7\n=p\xa3\xd7?\xea\x45\xa1\xca\xc0\x83\x12?\xef\xe7l\x8b\x43\x95\x81?\xeb\x85\x1e\xb8Q\xeb\x85?\xef\xe7l\x8b\x43\x95\x81?\xec\xc4\x9b\xa5\xe3S\xf8?\xef\xdf;dZ\x1c\xac?\xec\xc4\x9b\xa5\xe3S\xf8?\xed\xe3S\xf7\xce\xd9\x17?\xed\x89\x37K\xc6\xa7\xf0?\xed\xe3S\xf7\xce\xd9\x17?\xee\x45\xa1\xca\xc0\x83\x12?\xed\xe3S\xf7\xce\xd9\x17?\xee\xb0 \xc4\x9b\xa5\xe3?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0?\xf0\0\0\0\0\0\0\0\0\0\0\0\0\0\0)"
diff --git a/dist/branding/qtdesignstudio/images/logo/128/QtProject-qtcreator.png b/dist/branding/qtdesignstudio/images/logo/128/QtProject-qtcreator.png
new file mode 100644
index 00000000000..c655d17b870
--- /dev/null
+++ b/dist/branding/qtdesignstudio/images/logo/128/QtProject-qtcreator.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/images/logo/16/QtProject-qtcreator.png b/dist/branding/qtdesignstudio/images/logo/16/QtProject-qtcreator.png
new file mode 100644
index 00000000000..bbcd25e253d
--- /dev/null
+++ b/dist/branding/qtdesignstudio/images/logo/16/QtProject-qtcreator.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/images/logo/24/QtProject-qtcreator.png b/dist/branding/qtdesignstudio/images/logo/24/QtProject-qtcreator.png
new file mode 100644
index 00000000000..24d8e8c9b85
--- /dev/null
+++ b/dist/branding/qtdesignstudio/images/logo/24/QtProject-qtcreator.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/images/logo/256/QtProject-qtcreator.png b/dist/branding/qtdesignstudio/images/logo/256/QtProject-qtcreator.png
new file mode 100644
index 00000000000..d565981cdae
--- /dev/null
+++ b/dist/branding/qtdesignstudio/images/logo/256/QtProject-qtcreator.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/images/logo/32/QtProject-qtcreator.png b/dist/branding/qtdesignstudio/images/logo/32/QtProject-qtcreator.png
new file mode 100644
index 00000000000..d495f225683
--- /dev/null
+++ b/dist/branding/qtdesignstudio/images/logo/32/QtProject-qtcreator.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/images/logo/48/QtProject-qtcreator.png b/dist/branding/qtdesignstudio/images/logo/48/QtProject-qtcreator.png
new file mode 100644
index 00000000000..3501f2e9a71
--- /dev/null
+++ b/dist/branding/qtdesignstudio/images/logo/48/QtProject-qtcreator.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/images/logo/512/QtProject-qtcreator.png b/dist/branding/qtdesignstudio/images/logo/512/QtProject-qtcreator.png
new file mode 100644
index 00000000000..0b8100f185d
--- /dev/null
+++ b/dist/branding/qtdesignstudio/images/logo/512/QtProject-qtcreator.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/images/logo/64/QtProject-qtcreator.png b/dist/branding/qtdesignstudio/images/logo/64/QtProject-qtcreator.png
new file mode 100644
index 00000000000..91419443a71
--- /dev/null
+++ b/dist/branding/qtdesignstudio/images/logo/64/QtProject-qtcreator.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.ico b/dist/branding/qtdesignstudio/qtcreator.ico
new file mode 100644
index 00000000000..a6f5f84a07b
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.ico
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_128x128.png b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_128x128.png
new file mode 100644
index 00000000000..a481d7e8a5d
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_128x128.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected] b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]
new file mode 100644
index 00000000000..e8d3d4a5ba3
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_16x16.png b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_16x16.png
new file mode 100644
index 00000000000..c5493bd4987
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_16x16.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected] b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]
new file mode 100644
index 00000000000..d0c3d22c69c
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_256x256.png b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_256x256.png
new file mode 100644
index 00000000000..e8d3d4a5ba3
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_256x256.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected] b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]
new file mode 100644
index 00000000000..41808164d19
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_32x32.png b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_32x32.png
new file mode 100644
index 00000000000..d0c3d22c69c
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_32x32.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected] b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]
new file mode 100644
index 00000000000..c86812baa61
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_512x512.png b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_512x512.png
new file mode 100644
index 00000000000..41808164d19
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/icon_512x512.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected] b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]
new file mode 100644
index 00000000000..035e3bc4b29
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator-project.iconset/[email protected]
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/Contents.json b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/Contents.json
new file mode 100644
index 00000000000..7cd4f8e120c
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/Contents.json
@@ -0,0 +1,68 @@
+{
+ "images" : [
+ {
+ "size" : "16x16",
+ "idiom" : "mac",
+ "filename" : "icon_16x16.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "16x16",
+ "idiom" : "mac",
+ "filename" : "[email protected]",
+ "scale" : "2x"
+ },
+ {
+ "size" : "32x32",
+ "idiom" : "mac",
+ "filename" : "icon_32x32.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "32x32",
+ "idiom" : "mac",
+ "filename" : "[email protected]",
+ "scale" : "2x"
+ },
+ {
+ "size" : "128x128",
+ "idiom" : "mac",
+ "filename" : "icon_128x128.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "128x128",
+ "idiom" : "mac",
+ "filename" : "[email protected]",
+ "scale" : "2x"
+ },
+ {
+ "size" : "256x256",
+ "idiom" : "mac",
+ "filename" : "icon_256x256.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "256x256",
+ "idiom" : "mac",
+ "filename" : "[email protected]",
+ "scale" : "2x"
+ },
+ {
+ "size" : "512x512",
+ "idiom" : "mac",
+ "filename" : "icon_512x512.png",
+ "scale" : "1x"
+ },
+ {
+ "size" : "512x512",
+ "idiom" : "mac",
+ "filename" : "[email protected]",
+ "scale" : "2x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_128x128.png b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_128x128.png
new file mode 100644
index 00000000000..c655d17b870
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_128x128.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected] b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]
new file mode 100644
index 00000000000..d565981cdae
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_16x16.png b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_16x16.png
new file mode 100644
index 00000000000..bbcd25e253d
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_16x16.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected] b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]
new file mode 100644
index 00000000000..d495f225683
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_256x256.png b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_256x256.png
new file mode 100644
index 00000000000..d565981cdae
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_256x256.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected] b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]
new file mode 100644
index 00000000000..0b8100f185d
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_32x32.png b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_32x32.png
new file mode 100644
index 00000000000..d495f225683
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_32x32.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected] b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]
new file mode 100644
index 00000000000..91419443a71
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_512x512.png b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_512x512.png
new file mode 100644
index 00000000000..0b8100f185d
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/icon_512x512.png
Binary files differ
diff --git a/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected] b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]
new file mode 100644
index 00000000000..8292c415c5d
--- /dev/null
+++ b/dist/branding/qtdesignstudio/qtcreator.xcassets/qtcreator.appiconset/[email protected]
Binary files differ
diff --git a/doc/config/macros.qdocconf b/doc/config/macros.qdocconf
index 97e6fa7593d..1024ddc0278 100644
--- a/doc/config/macros.qdocconf
+++ b/doc/config/macros.qdocconf
@@ -27,11 +27,14 @@ macro.QC = "$IDE_DISPLAY_NAME"
macro.QCE = "$IDE_DISPLAY_NAME Enterprise"
macro.QD = "Qt Designer"
macro.QDS = "Qt Design Studio"
+macro.QQEM = "Qt Quick Effect Maker"
macro.QDV = "Qt Design Viewer"
macro.QL = "Qt Linguist"
+macro.QMCU = "Qt for MCUs"
macro.QMLD = "Qt Quick Designer"
macro.QQV = "Qt QML Viewer"
macro.QSDK = "Qt"
+macro.QUL = "Qt Quick Ultralite"
macro.qtcversion = $QTC_VERSION
macro.param = "\\e"
macro.raisedaster.HTML = "<sup>*</sup>"
diff --git a/doc/qtcreator/src/external-resources/external-resources-qds.qdoc b/doc/qtcreator/src/external-resources/external-resources-qds.qdoc
index 8f9eead2d9d..b1c64e785d1 100644
--- a/doc/qtcreator/src/external-resources/external-resources-qds.qdoc
+++ b/doc/qtcreator/src/external-resources/external-resources-qds.qdoc
@@ -17,3 +17,43 @@
\externalpage https://doc.qt.io/qtdesignstudio/studio-optimized-3d-scenes.html
\title Creating Optimized 3D Scenes
*/
+/*!
+ \externalpage https://doc.qt.io/QtForMCUs/
+ \title \QMCU documentation
+*/
+/*!
+ \externalpage https://doc.qt.io/QtForMCUs/qtul-qsg-traveoii-designui.html
+ \title Designing a UI for Infineon Traveo II
+*/
+/*!
+ \externalpage https://doc.qt.io/QtForMCUs/qtul-qsg-miimxrt1170-designui.html
+ \title Designing a UI for NXP i.MX RT1170
+*/
+/*!
+ \externalpage https://doc.qt.io/QtForMCUs/qtul-qsg-ra6m3g-designui.html
+ \title Designing a UI for Renesas RA6M3G
+*/
+/*!
+ \externalpage https://doc.qt.io/QtForMCUs/qtul-qsg-rh850-designui.html
+ \title Designing a UI for Renesas RH850-D1M1A
+*/
+/*!
+ \externalpage https://doc.qt.io/qtcreator/creator-developing-mcu.html
+ \title Connecting MCUs
+*/
+/*!
+ \externalpage https://doc.qt.io/QtForMCUs/qtul-infineon-traevoii-qsg.html
+ \title Infineon Traveo II quick start guide
+*/
+/*!
+ \externalpage https://doc.qt.io/QtForMCUs/qtul-nxp-rt1170-qsg.html
+ \title NXP i.MX RT1170 quick start guide
+*/
+/*!
+ \externalpage https://doc.qt.io/QtForMCUs/qtul-renesas-ra6-qsg.html
+ \title Renesas EK-RA6M3G quick start guide
+*/
+/*!
+ \externalpage https://doc.qt.io/QtForMCUs/qtul-renesas-rh850-qsg.html
+ \title Renesas RH850-D1M1A quick start guide
+*/
diff --git a/doc/qtcreator/src/external-resources/external-resources.qdoc b/doc/qtcreator/src/external-resources/external-resources.qdoc
index 7576aaf05fe..5d21be4257c 100644
--- a/doc/qtcreator/src/external-resources/external-resources.qdoc
+++ b/doc/qtcreator/src/external-resources/external-resources.qdoc
@@ -3,15 +3,15 @@
/*!
\externalpage https://doc.qt.io/QtForMCUs/index.html
- \title Qt for MCUs
+ \title \QMCU
*/
/*!
\externalpage https://doc.qt.io/QtForMCUs/qtul-qmltypes.html
- \title Qt for MCUs - All QML Types
+ \title \QMCU - All QML Types
*/
/*!
\externalpage https://doc.qt.io/QtForMCUs/qtul-supported-platforms.html
- \title Qt for MCUs - Supported Target Platforms
+ \title \QMCU - Supported Target Platforms
*/
/*!
\externalpage https://doc.qt.io/QtForMCUs/qtul-getting-started-renesas.html
diff --git a/doc/qtcreator/src/howto/creator-external-tools.qdoc b/doc/qtcreator/src/howto/creator-external-tools.qdoc
index dee3f838abe..219856879c5 100644
--- a/doc/qtcreator/src/howto/creator-external-tools.qdoc
+++ b/doc/qtcreator/src/howto/creator-external-tools.qdoc
@@ -11,7 +11,7 @@
\page creator-editor-external.html
\if defined(qtdesignstudio)
\previouspage quick-converting-ui-projects.html
- \nextpage studio-help.html
+ \nextpage studio-on-mcus.html
\else
\previouspage creator-keyboard-shortcuts.html
\nextpage creator-task-lists.html
diff --git a/doc/qtcreator/src/linux-mobile/creator-embedded-platforms.qdoc b/doc/qtcreator/src/linux-mobile/creator-embedded-platforms.qdoc
index c441981d3b8..8f7a7378392 100644
--- a/doc/qtcreator/src/linux-mobile/creator-embedded-platforms.qdoc
+++ b/doc/qtcreator/src/linux-mobile/creator-embedded-platforms.qdoc
@@ -90,7 +90,7 @@
\list
\li \l{Connecting MCUs}
\li \l{Running Applications on MCUs}
- \li \l{https://doc.qt.io/QtForMCUs/index.html}{Qt for MCUs}
+ \li \l{https://doc.qt.io/QtForMCUs/index.html}{\QMCU}
\endlist
\section1 QNX
diff --git a/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc b/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc
index 2719aa3e4c8..012a5d5e2eb 100644
--- a/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc
+++ b/doc/qtcreator/src/mcu/creator-mcu-dev.qdoc
@@ -8,7 +8,7 @@
\title Connecting MCUs
- Qt for MCU enables you to use subsets of QML and Qt Quick Controls
+ \QMCU enables you to use subsets of QML and Qt Quick Controls
to create user interfaces for devices that are powered by microcontroller
units (MCU). It includes a new graphics rendering engine that has a low
memory footprint and is optimized for MCUs and other resource-constrained
@@ -21,18 +21,18 @@
debug them using \QC.
The toolchains are available for cross-compilation on Microsoft Windows,
- Linux, and macOS. However, the Qt for MCU SDK is currently only available
+ Linux, and macOS. However, the Qt for \QMCU SDK is currently only available
for Windows and Linux.
- For a list of Qt for MCU reference implementations, see the
- \l{Qt for MCUs - Supported Target Platforms}{Qt for MCUs} documentation.
+ For a list of \QMCU reference implementations, see the
+ \l{\QMCU - Supported Target Platforms}{\QMCU} documentation.
\section1 Requirements
To use \QC to develop QML applications for MCUs, you need the following:
\list
- \li Qt for MCU SDK (only available for Windows and Linux)
+ \li \QMCU SDK (only available for Windows and Linux)
\li \l{https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnu-toolchain/gnu-rm}
{GNU ARM Embedded Toolchain}
\endlist
@@ -55,7 +55,7 @@
To be able to develop applications for MCUs, you need the MCU plugin.
This plugin is enabled automatically by the Qt Installer when you
- install Qt for MCUs.
+ install \QMCU.
\section2 Specifying MCU Settings
@@ -66,9 +66,9 @@
\image qtcreator-mcu-options.png "MCU preferences"
\list 1
- \li In the \uicontrol {Qt for MCUs SDK} field, specify the path
- to the directory where you installed Qt for MCUs SDK.
- \li In the \uicontrol {Targets supported by the Qt for MCUs SDK}
+ \li In the \uicontrol {\QMCU SDK} field, specify the path
+ to the directory where you installed \QMCU SDK.
+ \li In the \uicontrol {Targets supported by the \QMCU SDK}
field, select your MCU board.
\li In the \uicontrol Requirements section, ensure that the
platform-specific requirements are met. This varies depending
@@ -105,7 +105,7 @@
\li Select \uicontrol Apply to save the settings.
\endlist
- \note When updating to other versions of the Qt for MCUs SDK, \QC will
+ \note When updating to other versions of the \QMCU SDK, \QC will
ask you if you want to replace the existing kits, or create new ones
alongside. This can also be done manually, for each individual target,
via \uicontrol {Update Kit} and \uicontrol {Create Kit}, respectively.
@@ -145,7 +145,7 @@
\uicontrol Preferences > \uicontrol Kits.
However, for adding new kits you should use the \uicontrol {Create Kit}
- button in the {Qt for MCUs} settings tab. This method adds the paths to
+ button in the {\QMCU} settings tab. This method adds the paths to
the kit's toolkits and SDKs, and keeps them synchronized when selecting
\uicontrol Apply or \uicontrol OK.
@@ -156,14 +156,14 @@
You can use a wizard to set up a project for developing an application that
you can run on MCUs. The project uses a subset of QML and Qt Quick Controls
- that are supported by Qt for MCU. For more information about developing
- applications for MCUs, see the Qt for MCU documentation.
+ that are supported by \QMCU. For more information about developing
+ applications for MCUs, see the \QMCU documentation.
To create an application and run it on a MCU board:
\list 1
\li Select \uicontrol File > \uicontrol {New Project} >
- \uicontrol {Application (Qt for MCU)} >
+ \uicontrol {Application (\QMCU)} >
\uicontrol {MCU Support Application} > \uicontrol Choose.
\li Follow the instructions of the wizard to create the project.
\li Select \uicontrol Projects > \uicontrol {Build & Run}, and then
@@ -173,17 +173,17 @@
Usually, you can use the default settings.
\endlist
- \section1 Supported Qt for MCUs SDKs
+ \section1 Supported \QMCU SDKs
- \note The Qt for MCUs SDK 2.3 requires \QC 9.0.0, or later.
+ \note The \QMCU SDK 2.3 requires \QC 9.0.0, or later.
The following table lists the \QC versions you can use to develop
- applications with particular Qt for MCUs SDK versions.
+ applications with particular \QMCU SDK versions.
\table
\header
\li \QC version
- \li Qt for MCUs SDK version
+ \li \QMCU SDK version
\row
\li 9.0.0 or later
\li 2.0 or later
diff --git a/doc/qtcreator/src/overview/creator-only/creator-desktop-platforms.qdoc b/doc/qtcreator/src/overview/creator-only/creator-desktop-platforms.qdoc
index d97f7073cd6..91696e03c1c 100644
--- a/doc/qtcreator/src/overview/creator-only/creator-desktop-platforms.qdoc
+++ b/doc/qtcreator/src/overview/creator-only/creator-desktop-platforms.qdoc
@@ -47,7 +47,7 @@
\section1 macOS
- \macos 10.14 or later is supported with the Xcode tools for your \macos
+ \macos 10.15 or later is supported with the Xcode tools for your \macos
version available in the Mac App Store.
\section1 Windows
diff --git a/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc b/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc
index 45ab960f7d0..a003d922d47 100644
--- a/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc
+++ b/doc/qtdesignstudio/examples/doc/washingMachineUI.qdoc
@@ -33,15 +33,15 @@
In addition, all screens contain a small clock component that displays
the current time. We implement a \e TimeDate JavaScript object to
support this feature on \l{https://doc.qt.io/QtForMCUs/qtul-qmltypes.html}
- {Qt for MCUs}, which does not support the \l Date component at the time of
+ {\QMCU}, which does not support the \l Date component at the time of
writing.
\section1 Creating an Application for MCUs
- We use the \uicontrol {Qt for MCUs Application} project template to create
+ We use the \uicontrol {\QMCU Application} project template to create
an application for MCUs, which support only a subset of the preset
\l{glossary-component}{components}. We select \uicontrol File >
- \uicontrol {New Project} > \uicontrol {Qt for MCUs Application} >
+ \uicontrol {New Project} > \uicontrol {\QMCU Application} >
\uicontrol Choose, and follow the instructions of the wizard to create our
project.
@@ -54,16 +54,16 @@
that we can use to configure and build our example application for running
it on MCUs.
- \note This example has been tested to run using Qt for MCUs versions since
+ \note This example has been tested to run using \QMCU versions since
1.6. You cannot run it on older versions. Also, at the time of writing,
- Qt for MCUs only supports Qt 5.
+ \QMCU only supports Qt 5.
\section1 Creating Screens
For this example, we used an external tool to design the UI and then
exported and imported our design into \QDS as assets and components
using \QB, as instructed in \l{Exporting from Design Tools}. While
- exporting, we only picked components supported by Qt for MCUs to use
+ exporting, we only picked components supported by \QMCU to use
for our components. For the button components, we mostly use the
\l {basic-image}{Image}, \l Text, and \l {Mouse Area} components. For the
screen background, we use the \l {basic-rectangle}{Rectangle} component.
@@ -171,7 +171,7 @@
\image washingmachineui-states.png "States view"
- In Qt for MCU, states work differently from Qt Quick, and therefore we
+ In \QMCU, states work differently from Qt Quick, and therefore we
sometimes use \c when conditions to determine the state to apply, and
sometimes switch states using signals and JavaScript expressions.
@@ -217,7 +217,7 @@
\section1 Showing the Current Time
- The \l Date component is not supported on Qt for MCUs, and the
+ The \l Date component is not supported on \QMCU, and the
\l{https://doc.qt.io/QtForMCUs/qtul-javascript-environment.html}
{implementation of the JavaScript \c Date()} object returns elapsed
time since when the application was started instead of the current
diff --git a/doc/qtdesignstudio/images/baked-lightmaps-add-property.png b/doc/qtdesignstudio/images/baked-lightmaps-add-property.png
new file mode 100644
index 00000000000..96d4e3e3276
--- /dev/null
+++ b/doc/qtdesignstudio/images/baked-lightmaps-add-property.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/baked-lightmaps-edit-component.png b/doc/qtdesignstudio/images/baked-lightmaps-edit-component.png
new file mode 100644
index 00000000000..54ba462e2da
--- /dev/null
+++ b/doc/qtdesignstudio/images/baked-lightmaps-edit-component.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/baked-lightmaps-exit-component.png b/doc/qtdesignstudio/images/baked-lightmaps-exit-component.png
new file mode 100644
index 00000000000..58b5893bed2
--- /dev/null
+++ b/doc/qtdesignstudio/images/baked-lightmaps-exit-component.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/baked-lightmaps-navigator-blm.png b/doc/qtdesignstudio/images/baked-lightmaps-navigator-blm.png
new file mode 100644
index 00000000000..1fe50f46a27
--- /dev/null
+++ b/doc/qtdesignstudio/images/baked-lightmaps-navigator-blm.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/baked-lightmaps-navigator.png b/doc/qtdesignstudio/images/baked-lightmaps-navigator.png
new file mode 100644
index 00000000000..a6fac65a00d
--- /dev/null
+++ b/doc/qtdesignstudio/images/baked-lightmaps-navigator.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/baked-lightmaps-property-value.png b/doc/qtdesignstudio/images/baked-lightmaps-property-value.png
new file mode 100644
index 00000000000..69a5fd3a82a
--- /dev/null
+++ b/doc/qtdesignstudio/images/baked-lightmaps-property-value.png
Binary files differ
diff --git a/doc/qtdesignstudio/images/qds-mcu-target-deployment.png b/doc/qtdesignstudio/images/qds-mcu-target-deployment.png
new file mode 100644
index 00000000000..456a75560a7
--- /dev/null
+++ b/doc/qtdesignstudio/images/qds-mcu-target-deployment.png
Binary files differ
diff --git a/doc/qtdesignstudio/src/components/qtquick-animation-types.qdoc b/doc/qtdesignstudio/src/components/qtquick-animation-types.qdoc
index f51b3d376ac..a8bddc66ff8 100644
--- a/doc/qtdesignstudio/src/components/qtquick-animation-types.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-animation-types.qdoc
@@ -3,11 +3,8 @@
/*!
\page quick-animations.html
- \if defined(qtdesignstudio)
+
\previouspage quick-logic-helpers.html
- \else
- \previouspage quick-data-models.html
- \endif
\nextpage studio-3d-view.html
\title Animations
@@ -72,10 +69,8 @@
\image qtquick-number-animation.gif "Number animation"
- \if defined(qtdesignstudio)
For an example of using property animation to animate the scale and opacity
of components, see the \l{Coffee Machine} example.
- \endif
\section2 Setting Non-Animated Properties
diff --git a/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc b/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc
index d2a1a1760dd..071cf04554b 100644
--- a/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-buttons.qdoc
@@ -19,11 +19,7 @@
\list 1
\li Select \uicontrol File > \uicontrol {New File} >
- \if defined(qtcreator)
- \uicontrol Qt > \uicontrol {Qt Quick UI File} >
- \else
\uicontrol {Qt Quick Files} > \uicontrol {Qt Quick UI File} >
- \endif
\uicontrol Choose to create a \l{UI Files}{UI file} called
Button.ui.qml (for example).
@@ -105,11 +101,7 @@
/*!
\previouspage quick-buttons.html
\page quick-scalable-image.html
- \if defined(qtdesignstudio)
\nextpage qtquick-properties.html
- \else
- \nextpage studio-optimized-3d-scenes.html
- \endif
\title Creating Scalable Buttons and Borders
@@ -136,11 +128,8 @@
To create a button component, select \uicontrol File >
\uicontrol {New File} >
- \if defined(qtcreator)
- \uicontrol Qt > \uicontrol {Qt Quick UI File} >
- \else
\uicontrol {Qt Quick Files} > \uicontrol {Qt Quick UI File} >
- \endif
+
\uicontrol Choose to create a \l{UI Files}{UI file} called Button.ui.qml
(for example).
diff --git a/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc b/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc
index 1d6b1cd08a7..34140b88947 100644
--- a/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc
+++ b/doc/qtdesignstudio/src/components/qtquick-component-context-menu.qdocinc
@@ -22,11 +22,9 @@
\row
\li Anchors
\li \l{Setting Anchors and Margins}
- \if defined(qtdesignstudio)
\row
\li Group
\li \l{Organizing Components}
- \endif
\row
\li Position
\li \l{Using Positioners}
@@ -39,11 +37,9 @@
\row
\li Timeline
\li \l{Creating a Timeline}
- \if defined(qtdesignstudio)
\row
\li Event List
\li \l{Simulating Events}
- \endif
\row
\li Edit Color
\li \l{Editing Properties Inline}
diff --git a/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc b/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc
index 7d394de29e8..fc6ccdcf3cb 100644
--- a/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-components-custom.qdoc
@@ -26,11 +26,7 @@
\list 1
\li Select \uicontrol File > \uicontrol {New File} >
- \if defined(qtcreator)
- \uicontrol Qt > \uicontrol {Qt Quick UI File} >
- \else
\uicontrol {Qt Quick Files} > \uicontrol {Qt Quick UI File} >
- \endif
\uicontrol Choose to create a new \c .ui.qml file.
\note Components are listed in \uicontrol Components >
\uicontrol {My Components} only if the filename begins with a
@@ -80,9 +76,7 @@
that screen. For example, \e myButton_myMenu_home, \e myButton_myMenu_profile,
and \e myButton_myMenu_settings
- \if defined(qtdesignstudio)
\include qtdesignstudio-components.qdocinc creating studio components
- \endif
\section1 Turning Component Instances into Custom Components
@@ -107,11 +101,7 @@
additional ways of opening base components, see \l{Moving Within Components}.
For an example of creating a reusable custom component, see
- \if defined(qtcreator)
- \l{Creating a Mobile Application}.
- \else
\l{Progress Bar}.
- \endif
Custom components are listed in \uicontrol Components
> \uicontrol {My Components}, and you can use instances of them to build
diff --git a/doc/qtdesignstudio/src/components/qtquick-components.qdoc b/doc/qtdesignstudio/src/components/qtquick-components.qdoc
index 092a8bea3b1..edd28485db3 100644
--- a/doc/qtdesignstudio/src/components/qtquick-components.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-components.qdoc
@@ -3,11 +3,7 @@
/*!
\page quick-components.html
- \if defined(qtdesignstudio)
\previouspage studio-flow-external-events.html
- \else
- \previouspage creator-using-qt-quick-designer.html
- \endif
\nextpage quick-preset-components.html
\title Using Components
diff --git a/doc/qtdesignstudio/src/components/qtquick-controls.qdoc b/doc/qtdesignstudio/src/components/qtquick-controls.qdoc
index abcdde5e5b0..15b2189d2ac 100644
--- a/doc/qtdesignstudio/src/components/qtquick-controls.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-controls.qdoc
@@ -94,12 +94,10 @@
\image qtquickcontrols2-button.gif "Qt Quick Controls - Button"
- \if defined(qtdesignstudio)
Alternatively, you can use a wizard to create a \l{Creating Custom Controls}
{custom button}:
\image studio-custom-button.gif "Custom button"
- \endif
A button can be pushed or clicked by users. Typically, buttons
are used to perform an action or to answer a question. For example, \e OK,
@@ -133,14 +131,12 @@
\image qtquickcontrols2-button-flat.gif "Flat button"
- \if defined(qtdesignstudio)
\section3 Icon Buttons
To create a button that contains an icon, use the wizard template to
\l{Creating Custom Controls}{create a custom button} and drag-and-drop
the icon to the button background component. For an example of using the
wizard template, see \l{Creating a Push Button}.
- \endif
\section2 Delay Button
@@ -162,12 +158,10 @@
\image qtquickcontrols2-checkbox.gif "Check boxes"
- \if defined(qtdesignstudio)
Alternatively, you can use a wizard to create \l{Creating Custom Controls}
{custom check boxes}:
\image studio-custom-check-box.gif "Custom check boxes"
- \endif
A check box presents an option button that can be toggled on
(checked) or off (unchecked). Check boxes are typically used to select
@@ -255,12 +249,10 @@
\image qtquickcontrols2-switch.gif "Switch"
- \if defined(qtdesignstudio)
Alternatively, you can use a wizard to create a \l{Creating Custom Controls}
{custom switch}:
\image studio-custom-switch.gif "Custom switch"
- \endif
A switch is an option button that can be dragged or toggled on
(checked) or off (unchecked). Switches are typically used to select between
@@ -441,12 +433,10 @@
\image qtquickcontrols2-slider.gif "Slider"
- \if defined(qtdesignstudio)
Alternatively, you can use a wizard to create a \l{Creating Custom Controls}
{custom slider}:
\image studio-custom-slider.gif "Custom slider"
- \endif
A slider is used to select a value by sliding a handle along a
track, whereas \uicontrol {Range Slider} is used to select a range
@@ -463,12 +453,10 @@
\image qtquickcontrols2-dial-no-wrap.gif "Dial"
- \if defined(qtdesignstudio)
Alternatively, you can use a wizard to create a \l{Creating Custom Controls}
{custom dial}:
\image studio-custom-dial.gif "Custom dial"
- \endif
In the \uicontrol From and \uicontrol To fields, set the range of the
slider or dial. Set the value of the slide handle or dial in the
@@ -514,12 +502,10 @@
\image qtquickcontrols2-spinbox.png "Spin Box"
- \if defined(qtdesignstudio)
Alternatively, you can use a wizard to create a \l{Creating Custom Controls}
{custom spin box}:
\image studio-custom-spinbox.gif "Custom spin box"
- \endif
A spin box enables users to choose an integer value by clicking
the up or down indicator buttons, or by pressing up or down on the keyboard.
@@ -661,31 +647,6 @@
For more information about how to customize a particular control, see
\l{Customization Reference}.
- \if defined(qtcreator)
- \section1 History of Qt Quick Controls
-
- In Qt 4, ready-made Qt Quick 1 Components were provided for creating
- UIs with a native look and feel for a particular target platform.
- In Qt 5.1, Qt Quick Controls, Dialogs, and Layouts were added for
- creating classic desktop-style user interfaces using Qt Quick 2.1. The
- Qt Quick Controls Styles could be used to customize Qt Quick Controls.
-
- Since Qt 5.7, \l {Qt Quick Controls 2} replace Qt Quick Controls 1 and
- Qt Labs Controls. They provide lightweight components for creating performant
- user interfaces for \l{glossary-device}{devices}.
-
- Qt Quick Controls 2 work in conjunction with Qt Quick and Qt Quick Layouts.
-
- The \QC project wizards create Qt Quick applications that use Qt Quick
- 2 types or Qt Quick Controls 2 types.
-
- Even if you use Qt Quick Controls 2, you can still write cross-platform
- applications, by using different sets of QML files for each platform.
-
- Some ready-made controls, such as a gauge, dial, status indicator, and
- tumbler, are provided by the \l {Qt Quick Extras} module.
- \endif
-
\section1 Summary of UI Controls
The following table lists preset UI controls with links to their developer
diff --git a/doc/qtdesignstudio/src/components/qtquick-data-models.qdoc b/doc/qtdesignstudio/src/components/qtquick-data-models.qdoc
index 6ecd695a2e7..400e264d02e 100644
--- a/doc/qtdesignstudio/src/components/qtquick-data-models.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-data-models.qdoc
@@ -4,11 +4,7 @@
/*!
\page quick-data-models.html
\previouspage quick-controls.html
- \if defined(qtdesignstudio)
\nextpage quick-2d-effects.html
- \else
- \nextpage quick-animations.html
- \endif
\title Lists and Other Data Models
@@ -167,9 +163,7 @@
> \uicontrol {Qt Quick Controls}.
\include qtquick-pathview-editor.qdocinc pathview
- \if defined(qtdesignstudio)
\include qtquick-pathview-editor.qdocinc svgpath
- \endif
\section1 Summary of Model Components
@@ -223,14 +217,12 @@
\li Qt Quick Controls
\li
\li A stack-based navigation model.
- \if defined(qtdesignstudio)
\row
\li \inlineimage icons/item-svg-16px.png
\li \l{SVG Path Item}
\li Qt Quick Studio Components
\li
\li An SVG path data string that is used to draw a path as a line.
- \endif
\row
\li \inlineimage icons/itemdelegate-icon16.png
\li \l{SwipeDelegate}{Swipe Delegate}
diff --git a/doc/qtdesignstudio/src/components/qtquick-images.qdoc b/doc/qtdesignstudio/src/components/qtquick-images.qdoc
index 3d6879826c5..176e4409f8a 100644
--- a/doc/qtdesignstudio/src/components/qtquick-images.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-images.qdoc
@@ -187,7 +187,6 @@
\youtube DVWd_xMMgvg
- \if defined(qtdesignstudio)
\section1 Iso Icon
\note The Iso Icon component is not available if you selected
@@ -207,7 +206,6 @@
set the value of \uicontrol {Icon color}.
\image iso-icon-browser.png
- \endif
\section1 Summary of Images
@@ -243,7 +241,6 @@
\li \inlineimage ok.png
\li An image in one of the supported formats, including bitmap formats
such as PNG and JPEG and vector graphics formats such as SVG.
- \if defined(qtdesignstudio)
\row
\li \inlineimage icons/iso-icons-16px.png
\li \l{Iso Icon}
@@ -253,6 +250,5 @@
component. You can select the icon to use and its color.
\note This component is not supported on Qt 6.
- \endif
\endtable
*/
diff --git a/doc/qtdesignstudio/src/components/qtquick-mcu-support.qdocinc b/doc/qtdesignstudio/src/components/qtquick-mcu-support.qdocinc
index e01af788b80..edd75e3a467 100644
--- a/doc/qtdesignstudio/src/components/qtquick-mcu-support.qdocinc
+++ b/doc/qtdesignstudio/src/components/qtquick-mcu-support.qdocinc
@@ -6,9 +6,9 @@
\section1 Creating UIs for MCUs
- \l{Qt for MCUs} enables you to use subsets of components to create UIs for
+ \l{\QMCU} enables you to use subsets of components to create UIs for
devices that are powered by microcontroller units (MCU). The subset of
- supported components depends on the Qt for MCUs version that you use for
+ supported components depends on the \QMCU version that you use for
development. In this manual, we indicate which components are supported at
the time of writing.
@@ -21,7 +21,7 @@
\image qmldesigner-mcu-support.png "Components and Text properties supported for MCUs"
For more information about the supported components and their properties,
- see \l{Qt for MCUs - All QML Types}.
+ see \l{\QMCU - All QML Types}.
//! [mcu qtquick components]
*/
diff --git a/doc/qtdesignstudio/src/components/qtquick-pathview-editor.qdocinc b/doc/qtdesignstudio/src/components/qtquick-pathview-editor.qdocinc
index 73422f6676b..dd50cf67986 100644
--- a/doc/qtdesignstudio/src/components/qtquick-pathview-editor.qdocinc
+++ b/doc/qtdesignstudio/src/components/qtquick-pathview-editor.qdocinc
@@ -49,10 +49,8 @@
In the \uicontrol {Path View Highlight} section, you can specify properties
for \l{View Highlight}{highlighting} path objects.
- \if defined(qtdesignstudio)
\note You can also use the \l {SVG Path Item} Studio Component to specify an
SVG path data string that draws a path.
- \endif
//! [pathview]
diff --git a/doc/qtdesignstudio/src/components/qtquick-positioning.qdoc b/doc/qtdesignstudio/src/components/qtquick-positioning.qdoc
index a71831fdd1e..1eb55ebd771 100644
--- a/doc/qtdesignstudio/src/components/qtquick-positioning.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-positioning.qdoc
@@ -4,11 +4,7 @@
/*!
\page qtquick-positioning.html
\previouspage qtquick-properties.html
- \if defined(qtdesignstudio)
\nextpage qtquick-annotations.html
- \else
- \nextpage qtquick-fonts.html
- \endif
\title Scalable Layouts
@@ -386,13 +382,9 @@
\section2 Using Layouts
- \if defined(qtcreator)
- Since Qt 5.1, you can use QML types in the \l{qtquicklayouts-index.html}
- {Qt Quick Layouts} module to arrange components in UIs.
- \else
You can use the components available in \uicontrol Components
> \uicontrol {Qt Quick Layouts} to arrange components in UIs.
- \endif
+
Unlike positioners, layouts manage both the positions and sizes of their
child components, and are therefore well suited for dynamic and resizable
UIs. However, this means that you should not specify fixed positions and
@@ -502,10 +494,8 @@
You can use the \uicontrol Frame and \uicontrol {Group Box} controls to
draw frames around groups of controls.
- \if defined(qtdesignstudio)
- If you don't want a frame, use the \uicontrol Group component instead.
- \endif
+ If you don't want a frame, use the \uicontrol Group component instead.
The following table lists the UI controls that you can use to organize
components in UIs (since Qt 5.7). The \e Location column indicates the
@@ -522,13 +512,11 @@
\li \l [QtQuickControls]{Frame}
\li Qt Quick Controls
\li A visual frame around a group of controls.
- \if defined(qtdesignstudio)
\row
\li \inlineimage icons/group-16px.png
\li Group
\li Qt Quick Studio Components
\li Enables handling the selected components as a group.
- \endif
\row
\li \inlineimage icons/groupbox-icon16.png
\li \l [QtQuickControls]{GroupBox}{Group Box}
diff --git a/doc/qtdesignstudio/src/components/qtquick-preset-components.qdoc b/doc/qtdesignstudio/src/components/qtquick-preset-components.qdoc
index d05d800546a..875d0f9ea67 100644
--- a/doc/qtdesignstudio/src/components/qtquick-preset-components.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-preset-components.qdoc
@@ -30,10 +30,8 @@
\li \l {User Interaction Methods}
\li \l {UI Controls}
\li \l {Lists and Other Data Models}
- \if defined(qtdesignstudio)
\li \l {2D Effects}
\li \l {Logic Helpers}
- \endif
\li \l Animations
\endlist
diff --git a/doc/qtdesignstudio/src/components/qtquick-shapes.qdoc b/doc/qtdesignstudio/src/components/qtquick-shapes.qdoc
index 02ef0e06cf5..73ccc3971a5 100644
--- a/doc/qtdesignstudio/src/components/qtquick-shapes.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-shapes.qdoc
@@ -8,7 +8,6 @@
\title Shapes
- \if defined(qtdesignstudio)
\QDS is a UI design tool rather than a generic drawing tool, and therefore,
the focus is on providing ready-made UI controls that you can modify
according to your needs. The values of some properties of the controls are
@@ -22,12 +21,6 @@
\image studio-shapes.png "Shapes in the 2D view"
- \else
- You can use the Rectangle component to draw basic shapes in
- the \l {2D} view.
- \image qml-shapes.png "Shapes in the 2D view"
- \endif
-
Most visual components in \uicontrol Components are based on the \l [QtQuick]
{Item} component. Even though it has no visual appearance itself (similarly
to a mouse area, for example), it defines all the properties that are
@@ -48,9 +41,7 @@
The basic \l [QtQuick] {Rectangle} component is used for drawing shapes
with four sides and corners, as well as a solid border.
- \if defined(qtdesignstudio)
\image qml-shapes-rectangle.png "A rectangle and its properties"
- \endif
Rectangles can be filled either with a solid fill color or a linear
gradient that you set in the \uicontrol {Fill color} field. You can
@@ -74,7 +65,6 @@
check box in the \uicontrol Advanced section to improve the appearance of
your shape.
- \if defined(qtdesignstudio)
\target studio-rectangle
\section2 Studio Rectangle
@@ -279,5 +269,4 @@
\li A triangle with different dimensions and shapes that is
enclosed in an invisible rectangle.
\endtable
- \endif
*/
diff --git a/doc/qtdesignstudio/src/components/qtquick-text.qdoc b/doc/qtdesignstudio/src/components/qtquick-text.qdoc
index 7f515c7e98f..f47ac82d7bd 100644
--- a/doc/qtdesignstudio/src/components/qtquick-text.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-text.qdoc
@@ -79,12 +79,6 @@
For more information, see
\l {Internationalization and Localization with Qt Quick}.
- \if defined(qtcreator)
- When you \l{Creating Qt Quick Projects}{create a new project}, you can
- automatically generate a translation source file (TS) for one language.
- You can add other languages later by editing the project file.
- \endif
-
\section1 Character Properties
You can set font properties in the \uicontrol Character section
diff --git a/doc/qtdesignstudio/src/components/qtquick-user-interaction-methods.qdoc b/doc/qtdesignstudio/src/components/qtquick-user-interaction-methods.qdoc
index bb29fb7f36e..71b3fee6305 100644
--- a/doc/qtdesignstudio/src/components/qtquick-user-interaction-methods.qdoc
+++ b/doc/qtdesignstudio/src/components/qtquick-user-interaction-methods.qdoc
@@ -59,11 +59,6 @@
\li \c released()
\endlist
- \if defined(qtcreator)
- A more modern way of handling events from all pointing devices, including
- mouse and touchscreen, is via \l {Qt Quick Input Handlers}.
- \endif
-
\section2 Mouse Area Properties
A \uicontrol {Mouse Area} is an invisible component that is typically used
diff --git a/doc/qtdesignstudio/src/mcus/qtdesignstudio-compatibility-with-mcu-sdks.qdoc b/doc/qtdesignstudio/src/mcus/qtdesignstudio-compatibility-with-mcu-sdks.qdoc
new file mode 100644
index 00000000000..c6dab76398d
--- /dev/null
+++ b/doc/qtdesignstudio/src/mcus/qtdesignstudio-compatibility-with-mcu-sdks.qdoc
@@ -0,0 +1,29 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \previouspage studio-on-mcus.html
+ \page studio-compatibility-with-mcu-sdks.html
+ \nextpage studio-help.html
+
+ \title \QDS Version Compatibility with \QMCU SDKs
+
+ The following table lists the \QDS versions you can use to develop
+ applications with particular \QMCU SDK versions.
+
+ \table
+ \header
+ \li \QDS Version
+ \li \QMCU SDK Version
+ \row
+ \li 4.0 or later
+ \li 2.4 or later
+ \row
+ \li 3.8 up to 3.9
+ \li 2.3
+ \row
+ \li 3.4 up to 3.7
+ \li 2.2 (LTS)
+ \endtable
+
+*/
diff --git a/doc/qtdesignstudio/src/mcus/qtdesignstudio-on-mcus.qdoc b/doc/qtdesignstudio/src/mcus/qtdesignstudio-on-mcus.qdoc
new file mode 100644
index 00000000000..a16df932c91
--- /dev/null
+++ b/doc/qtdesignstudio/src/mcus/qtdesignstudio-on-mcus.qdoc
@@ -0,0 +1,92 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \previouspage creator-editor-external.html
+ \page studio-on-mcus.html
+ \nextpage studio-compatibility-with-mcu-sdks.html
+
+ \title \QDS on MCUs
+
+ \QMCU is a comprehensive framework that supports various hardware ecosystems
+ and platforms. One of the most important libraries provided by the \QMCU
+ framework is \QUL (QUL), a lightweight implementation of the Qt Quick
+ framework. \QUL provides a QML API and an efficient graphics rendering engine
+ that has a low memory footprint and is optimized for MCUs and other
+ resource-constrained devices.
+
+ In addition to a lightweight graphics framework, \QMCU offers a toolkit that
+ enables you to design, develop, and deploy graphical user interfaces (GUI)
+ on microcontrollers (MCU). Also, it lets you run the applications either
+ on BareMetal or a real-time operating system (RTOS).
+
+ For more information on \QMCU, see \l {\QMCU documentation}.
+
+ \section1 Designing application UIs for MCU devices with \QDS
+
+ As a technical artist or a designer you can use specialized UI design tools,
+ such as Adobe Photoshop, Sketch, Figma, Blender, or Maya to create the
+ original UI design files for your MCU application. After the initial design
+ work, export your design from the design tools, and import your 2D and 3D UI
+ design assets into \QDS, which can convert them into code for developers.
+ For more information on managing the original assets created with
+ specialized UI design tools, see \l {Asset Creation with Other Tools}.
+
+ Once your UI design assets are in \QDS, use it to \l {Wireframing} {wireframe}
+ your MCU application, to visualize its structure. To modify the look and feel
+ of your UI further, utilize the preset UI components available in \QDS.
+
+ For an example on how to create a UI that runs both on the desktop and
+ on MCUs, see \l {Washing Machine UI}. For step-by-step instructions on how
+ to use \QDS to design a UI for a specific MCU target device, see:
+
+ \list
+ \li \l {Designing a UI for Infineon Traveo II}
+ \li \l {Designing a UI for NXP i.MX RT1170}
+ \li \l {Designing a UI for Renesas RA6M3G}
+ \li \l {Designing a UI for Renesas RH850-D1M1A}
+ \endlist
+
+ \section1 Developing applications for MCU devices with \QDS
+
+ As a GUI/application developer, use \QDS to bring your designs to life. Add
+ further functionality to your applications and utilize the \l {Prototyping}
+ {prototyping} features of \QDS to simulate and validate interactions and
+ their dynamic behavior.
+
+ You can also test, preview, and fine-tune your designs to pixel-perfection
+ live on the desktop or on an actual MCU target device. For more information,
+ see \l {Validating with Target Hardware}.
+
+ \image qds-mcu-target-deployment.png
+
+ \QDS enables designers and developers to work together on common projects to
+ develop applications. Designers can use the views in the Design mode to modify
+ UI files (.ui.qml), whereas developers can use Qt Creator to work on the Qt
+ Quick (.qml) and other files that are needed to implement the application
+ logic and to prepare the application for production. For more information,
+ see \l {Implementing Applications}.
+
+ \section1 Connecting MCUs with Qt Creator
+
+ \l {Connecting MCUs} {Connect MCU boards} to a development host to
+ build applications for them using the GNU Arm Embedded GCC compiler, libraries,
+ and other GNU tools necessary for BareMetal software development on devices
+ based on the Arm Cortex-M processors. Deploy the applications on MCUs to run
+ and debug them using Qt Creator.
+
+ The toolchains are available for cross-compilation on Microsoft Windows,
+ Linux, and macOS. However, the \QMCU SDK is currently only available for
+ Windows and Linux.
+
+ For more information on how to manage the complete cycle of developing \QMCU
+ applications using Qt tools, see:
+
+ \list
+ \li \l {Infineon Traveo II quick start guide}
+ \li \l {NXP i.MX RT1170 quick start guide}
+ \li \l {Renesas EK-RA6M3G quick start guide}
+ \li \l {Renesas RH850-D1M1A quick start guide}
+ \endlist
+
+*/
diff --git a/doc/qtdesignstudio/src/overviews/qtquick-animation-overview.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-animation-overview.qdoc
index ef7fccc3c7d..86132b5ce1a 100644
--- a/doc/qtdesignstudio/src/overviews/qtquick-animation-overview.qdoc
+++ b/doc/qtdesignstudio/src/overviews/qtquick-animation-overview.qdoc
@@ -87,12 +87,10 @@
\header
\li Technique
\li Use Case
- \if defined(qtdesignstudio)
\row
\li \l{Designing Application Flows}{Application flows}
\li An interactive prototype that can be clicked through to simulate
the user experience of the application.
- \endif
\row
\li \l{Transitions}{Transitions between states}
\li Transitions between different states of the UI using a transition
@@ -100,7 +98,6 @@
to the keyframes.
\endtable
- \if defined(qtdesignstudio)
\section2 Application Flows
You can design an application in the form of a \e {schematic diagram}
@@ -111,7 +108,6 @@
as the base of the production version of the application.
For more information, see \l{Designing Application Flows}.
- \endif
\section2 Transitions Between States
diff --git a/doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc
index d5f19de7a45..aeaf304bfcf 100644
--- a/doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc
+++ b/doc/qtdesignstudio/src/overviews/qtquick-annotations.qdoc
@@ -3,13 +3,8 @@
/*!
\page qtquick-annotations.html
- \if defined(qtdesignstudio)
\previouspage qtquick-positioning.html
\nextpage qtquick-prototyping.html
- \else
- \previouspage qtquick-fonts.html
- \nextpage creator-quick-ui-forms.html
- \endif
\title Annotating Designs
diff --git a/doc/qtdesignstudio/src/overviews/qtquick-creating-ui-logic.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-creating-ui-logic.qdoc
index 226c2a4982d..a5e05f8beb3 100644
--- a/doc/qtdesignstudio/src/overviews/qtquick-creating-ui-logic.qdoc
+++ b/doc/qtdesignstudio/src/overviews/qtquick-creating-ui-logic.qdoc
@@ -38,13 +38,11 @@
to define how their properties will animate when they change due to a
state change.
- \if defined(qtdesignstudio)
The \l{Log In UI - States} example illustrates using states to create
two UI screens and signals emitted by buttons to apply the states.
The button components also switch states when they are pressed down.
\image loginui3.gif "Clicking buttons to switch between screens"
- \endif
Using property aliases and states to create the differences in your
component instances enables you to reuse components instead of duplicating
@@ -57,7 +55,6 @@
instances of the controls into custom components and specify new properties
for them.
- \if defined(qtdesignstudio)
To have your UI perform certain operations, you might need to write
JavaScript expressions for conditions or convert numbers to strings.
To make this easier, \QDS provides preset components called
@@ -74,7 +71,6 @@
to implement the UI logic.
\image studio-logic-helper-combining-example.gif "Logic helper example application"
- \endif
The following table summarizes some typical use cases with links to more
information.
@@ -107,11 +103,9 @@
\row
\li Using preset UI controls that have default properties and states
\li \l{UI Controls}
- \if defined(qtdesignstudio)
\row
\li Creating conditional conditions
\li \l{Logic Helpers}
- \endif
\row
\li Adding custom properties for a particular component type
\li \l{Specifying Custom Properties}
diff --git a/doc/qtdesignstudio/src/overviews/qtquick-export.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-export.qdoc
index 1d7661fdd34..f9ae3b8d7b4 100644
--- a/doc/qtdesignstudio/src/overviews/qtquick-export.qdoc
+++ b/doc/qtdesignstudio/src/overviews/qtquick-export.qdoc
@@ -4,7 +4,7 @@
/*!
\page creator-exporting-qml.html
\previouspage studio-importing-3d.html
- \nextpage qt-effect-maker-files.html
+ \nextpage qt-using-effect-maker-effects.html
\title Exporting Components
diff --git a/doc/qtdesignstudio/src/overviews/qtquick-fonts.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-fonts.qdoc
index e2cfd05679a..d2f6745df5e 100644
--- a/doc/qtdesignstudio/src/overviews/qtquick-fonts.qdoc
+++ b/doc/qtdesignstudio/src/overviews/qtquick-fonts.qdoc
@@ -3,13 +3,8 @@
/*!
\page qtquick-fonts.html
- \if defined(qtdesignstudio)
\previouspage studio-importing-2d.html
\nextpage studio-importing-3d.html
- \else
- \previouspage qtquick-positioning.html
- \nextpage qtquick-annotations.html
- \endif
\title Using Custom Fonts
diff --git a/doc/qtdesignstudio/src/overviews/qtquick-motion-design.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-motion-design.qdoc
index aade258132c..70ebb9115dc 100644
--- a/doc/qtdesignstudio/src/overviews/qtquick-motion-design.qdoc
+++ b/doc/qtdesignstudio/src/overviews/qtquick-motion-design.qdoc
@@ -3,7 +3,7 @@
/*!
\page qtquick-motion-design.html
- \previouspage qt-effect-maker.html
+ \previouspage qt-using-effect-maker-effects.html
\nextpage quick-animation-overview.html
\title Motion Design
diff --git a/doc/qtdesignstudio/src/overviews/qtquick-prototyping.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-prototyping.qdoc
index 414e608a9c7..2cda8239de4 100644
--- a/doc/qtdesignstudio/src/overviews/qtquick-prototyping.qdoc
+++ b/doc/qtdesignstudio/src/overviews/qtquick-prototyping.qdoc
@@ -3,11 +3,7 @@
/*!
\page qtquick-prototyping.html
- \if defined(qtdesignstudio)
\previouspage qtquick-annotations.html
- \else
- \previouspage creator-quick-ui-forms.html
- \endif
\nextpage qtquick-creating-ui-logic.html
\title Prototyping
@@ -39,10 +35,8 @@
You can connect UIs to different forms of data from various
sources, such as QML-based data models, JavaScript files, and
backend services.
- \if defined(qtdesignstudio)
You can also connect your UI to Simulink to load live data from
a Simulink simulation.
- \endif
\li \l {Dynamic Behaviors}
@@ -50,7 +44,6 @@
communicate with each other. The connections can be triggered by
changes in component property values or in UI states.
- \if defined(qtdesignstudio)
\li \l {Validating with Target Hardware}
You can use the live preview feature to preview a UI file or the
@@ -64,24 +57,5 @@
files that you can import to projects in \QDS, how to import them,
and how to export them from \QDS back to the metadata format.
- \else
- \li \l {Exporting 3D Assets}
-
- You can export assets from 3D graphics applications into several
- widely-used formats, such as .blend, .dae, .fbx, .glb, .gltf, .obj,
- .uia, or .uip.
-
- \li \l {Importing 3D Assets}
-
- You can import exported assets into \QDS. For a list of formats
- supported by each \l{Qt Quick 3D} version, see the module
- documentation.
-
- \li \l {Exporting Components}
-
- You can export components contained in \l{UI Files}{UI files}
- (.ui.qml) to JSON metadata format and PNG assets.
- \endif
-
\endlist
*/
diff --git a/doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc b/doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc
index 59eb00ab94b..82a6f2acfa3 100644
--- a/doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc
+++ b/doc/qtdesignstudio/src/overviews/qtquick-uis.qdoc
@@ -3,13 +3,8 @@
/*!
\page quick-uis.html
- \if defined(qtdesignstudio)
\previouspage {Examples}
\nextpage studio-app-flows.html
- \else
- \previouspage qtquick-text-editor.html
- \nextpage quick-components.html
- \endif
\title Wireframing
@@ -44,7 +39,6 @@
\list
- \if defined(qtdesignstudio)
\li \l {Designing Application Flows}
You can design an application in the form of a \e {schematic diagram}
@@ -52,7 +46,6 @@
interconnections by means of symbols. This results in an
interactive prototype that can be clicked through to simulate
the user experience of the application.
- \endif
\li \l {Using Components}
@@ -79,31 +72,10 @@
methods, such as anchors, layouts, positioners, and property
bindings, for dynamic UIs.
- \if defined(qtcreator)
- \li \l {Using Custom Fonts}
-
- You can load custom fonts to \QC and use them in your designs.
- \endif
-
\li \l {Annotating Designs}
You can annotate your designs to provide reviewers or developers
with additional information about them.
- \if defined(qtcreator)
- \li \l {Loading Placeholder Data}
-
- You can create QML files that contain placeholder data, so that
- you can test grid, list, or path views, even though you don't
- have access to real data.
-
- \li \l{UI Files}
-
- Some of the wizards create projects that contain UI files
- (.ui.qml). You should always edit UI files in the \l {2D}
- and \l Properties view, to avoid breaking the code.
-
- \endif
-
\endlist
*/
diff --git a/doc/qtdesignstudio/src/qt-quick-effect-maker.qdoc b/doc/qtdesignstudio/src/qt-quick-effect-maker.qdoc
deleted file mode 100644
index 56dfebfe301..00000000000
--- a/doc/qtdesignstudio/src/qt-quick-effect-maker.qdoc
+++ /dev/null
@@ -1,93 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2022 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Design Studio documentation.
-**
-** 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 Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-**
-****************************************************************************/
-
-/*!
-
- \page qt-effect-maker.html
- \previouspage qt-effect-maker-files.html
- \nextpage qtquick-motion-design.html
- \sa {Creating Qt Quick Effect Maker Files}
-
- \title Working with Effects in Qt Quick Effect Maker
-
- The Qt Quick Effect Maker is a tool to create high-performance
- shader effects for Qt Quick.
-
- You can import these effects to \QDS and you can run Qt Quick Effect Maker
- from \QDS.
-
- \section1 Creating Effects
-
- When you run Qt Quick Effect Maker, it starts with an empty project. To
- create your effect, add nodes to the node tree.
-
- \image qt-quick-effect-maker.webp
-
- Consider the following things when creating effects:
-
- \list
- \li Some nodes do not function alone, they need a helper node. For
- example, the \uicontrol FastBlur node needs a \uicontrol BlurHelper node
- and the \uicontrol Noise node needs a \uicontrol NoiseHelper node. If the
- node needs another node, it is mentioned in the node description.
- \li If your effect appears cropped, you need to go to \uicontrol Edit >
- \uicontrol {Project Settings} and increase the item padding.
- \endlist
-
- \section2 Creating a Blur Effect
-
- To create a blur effect:
-
- \list 1
- \li Add a \uicontrol FastBlur node to the node tree.
- \li Add a \uicontrol BlurHelper node to the node tree. You need the
- \uicontrol BlurHelper node for all effects that contains a blur effect.
- \endlist
-
- \image blur-effect-nodes.png
-
- You can now select the \uicontrol FastBlur node and in the settings, change
- the \uicontrol fastBlurAmount value to control the amount of blur.
-
- \image blur-effect-step-1.webp
-
- \section3 Adjusting Item Borders
-
- The effect appears cropped. You need to adjust item borders:
-
- \list 1
- \li Select \inlineimage effect-item-borders-icon.png
- to display item borders.
- \image blur-effect-step-2.webp
- \li Go to \uicontrol Edit > \uicontrol {Project Settings}.
- \li Set the item padding for all sides to 100.
- \image effect-item-padding-dialog.png
- \endlist
-
- Now, you can see the complete blur effect.
-
- \image blur-effect-step-3.webp
-
-*/
diff --git a/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc b/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc
index d21e9ab7046..e2e8e8f389e 100644
--- a/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc
+++ b/doc/qtdesignstudio/src/qtbridge/qtbridge-ps-setup.qdoc
@@ -31,14 +31,16 @@
\list 1
\li Copy the \QBPS ZXP package from
\c {Qt\Tools\QtDesignStudio\photoshop_bridge} to the
- \c Documents directory in your user directory.
+ \c Documents directory in your user directory. The \c {file-name}
+ should look similar to: \c {qt.QtBridge}.
\li Open Windows PowerShell.
- \li Enter the following commands:
+ \li Enter the following commands, replacing
+ \c {<bridge-installation-file-name>} with the \c {file-name}:
\badcode
cd "$env:UserProfile\Documents"
- mv .\io.qt.QtBridge.zxp .\io.qt.QtBridge.zip
- expand-archive .\io.qt.QtBridge.zip
- xcopy /E /I .\io.qt.QtBridge "$env:APPDATA\Adobe\CEP\extensions\io.qt.QtBridge"
+ mv .\<bridge-installation-file-name>.zxp .\<bridge-installation-file-name>.zip
+ expand-archive .\<bridge-installation-file-name>.zip
+ xcopy /E /I .\<bridge-installation-file-name> "$env:APPDATA\Adobe\CEP\extensions\<bridge-installation-file-name>"
\endcode
\endlist
@@ -49,14 +51,16 @@
\list 1
\li Copy the \QBPS ZXP package from
\c {Qt/QtDesignStudio/photoshop_bridge}
- to your \c Documents directory.
+ to your \c Documents directory. The \c {file-name}
+ should look similar to: \c {qt.QtBridge}.
\li Open Terminal.
- \li Enter the following commands:
+ \li Enter the following commands, replacing
+ \c {<bridge-installation-file-name>} with the \c {file-name}:
\badcode
cd ~/Documents
- unzip io.qt.QtBridge.zxp -d io.qt.QtBridge
+ unzip <bridge-installation-file-name>.zxp -d <bridge-installation-file-name>
sudo mkdir -p /Library/Application\ Support/Adobe/CEP/extensions
- sudo cp -R ./io.qt.QtBridge /Library/Application\ Support/Adobe/CEP/extensions
+ sudo cp -R ./<bridge-installation-file-name> /Library/Application\ Support/Adobe/CEP/extensions
\endcode
\endlist
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-advanced.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-advanced.qdoc
index 0ff4c90faf9..21733c996ac 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-advanced.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-advanced.qdoc
@@ -25,18 +25,12 @@
and \l Properties view, to avoid breaking the code.
\li \l{Managing Data Collection}
- \if defined (qtcreator)
- You can enable \QC to report crashes automatically. If you agreed to
- pseudonymous user statistics collection during the \QC installation,
- you can turn it on and determine what type of data is collected and
- transmitted to the backend storage.
- \else
You can enable \QDS to report crashes automatically. If you enable
the telemetry plugin, you can turn on the pseudonymous user
statistics collection and determine what type of data is collected
and transmitted to the backend storage. You can also modify
settings for collecting user feedback.
- \endif
+
\li \l{Packaging Applications}
When you are ready to deliver your application to users or upload
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-effect-maker-files.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-effect-maker-files.qdoc
deleted file mode 100644
index 06b3ea15906..00000000000
--- a/doc/qtdesignstudio/src/qtdesignstudio-effect-maker-files.qdoc
+++ /dev/null
@@ -1,79 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2022 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the Qt Design Studio documentation.
-**
-** 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 Free Documentation License Usage
-** Alternatively, this file may be used under the terms of the GNU Free
-** Documentation License version 1.3 as published by the Free Software
-** Foundation and appearing in the file included in the packaging of
-** this file. Please review the following information to ensure
-** the GNU Free Documentation License version 1.3 requirements
-** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
-**
-****************************************************************************/
-
-/*!
-
- \page qt-effect-maker-files.html
- \nextpage qt-effect-maker.html
- \previouspage creator-exporting-qml.html
- \sa {Working with Effects in Qt Quick Effect Maker}
-
- \title Creating Qt Quick Effect Maker Files
-
- \section1 Creating an Effect File
-
- You can create Qt Quick Effect Maker effect (.qep) files in \QDS and
- then edit them in Qt Quick Effect Maker.
-
- To create an effect file:
-
- \list 1
- \li In \QDS, right-click in the \uicontrol Assets view and
- select \uicontrol {New Effect}.
- \QDS creates an effect file and opens it in Qt Quick Effect Maker.
- \image qt-quick-effect-maker.webp
- \li Edit the effect.
- \li In Qt Quick Effect Maker, go to \uicontrol File > \uicontrol Save.
- \li Select \uicontrol File > \uicontrol Export.
- \li With the default settings, select \uicontrol OK.
- \image effect-maker-export.png
- \endlist
-
- Now, you can close Qt Quick Effect Maker and return to \QDS and apply the
- effect.
-
- \section1 Applying an Effect
-
- You can apply effects to components in \QDS. To do so, drag the effect
- from the \uicontrol Assets view to the component in the \uicontrol 2D or
- \uicontrol Navigator view.
-
- \image apply-effect-maker-effect.webp
-
- \section1 Animated Effect
-
- When you import an animated effect, you need to turn on the animation for it
- to see the animation in your \QDS application.
-
- To turn on animation for an effect, first apply the effect to a component,
- and then:
-
- \list 1
- \li Select the effect in \uicontrol Navigator.
- \li In \uicontrol Properties, go to the
- \uicontrol {Exposed Custom Properties} section and set
- \uicontrol timeRunning to true.
- \endlist
-*/
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-help-overview.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-help-overview.qdoc
index 772885ca385..e3a00cb8dfb 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-help-overview.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-help-overview.qdoc
@@ -3,7 +3,7 @@
/*!
\page studio-help.html
- \previouspage creator-editor-external.html
+ \previouspage studio-compatibility-with-mcu-sdks.html
\nextpage creator-help.html
\title Help
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc
index ffb23d35f2e..1aab65187ab 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-projects.qdoc
@@ -47,10 +47,10 @@
\li Creates a project that uses default and 3D components such as
cameras, lights, 3D models, and materials.
\row
- \li Qt for MCUs
+ \li \QMCU
\li MCU
\li Creates an application that uses a subset of default components
- (as supported by Qt for MCUs) that you can deploy, run, and debug
+ (as supported by \QMCU) that you can deploy, run, and debug
on MCU boards.
\row
\li {1,3} Mobile
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc
index 89a93a4d435..6fc2014020f 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio-toc.qdoc
@@ -162,7 +162,7 @@
\list
\li \l{Setting Up Qt Bridge for Figma}
\li \l{Using Qt Bridge for Figma}
- \li \l{Using Figma Quick Control Template in Qt Design Studio}
+ \li \l{Using Figma Quick Control Template Components in Qt Design Studio}
\endlist
\endlist
\li \l {Exporting 3D Assets}
@@ -180,11 +180,7 @@
\li \l{Importing 3D Assets}
\endlist
\li \l{Exporting Components}
- \li Qt Quick Effect Maker
- \list
- \li \l{Creating Qt Quick Effect Maker Files}
- \li \l{Working with Effects in Qt Quick Effect Maker}
- \endlist
+ \li \l{Using Qt Quick Effect Maker Effects}
\endlist
\endlist
\li \l{Motion Design}
@@ -263,6 +259,10 @@
\li \l{Converting Qt 5 Projects into Qt 6 Projects}
\li \l{Converting UI Projects to Applications}
\li \l{Using External Tools}
+ \li \l{\QDS on MCUs}
+ \list
+ \li \l {\QDS Version Compatibility with \QMCU SDKs}
+ \endlist
\endlist
\li \l Help
\list
diff --git a/doc/qtdesignstudio/src/qtdesignstudio-using-effect-maker-effects.qdoc b/doc/qtdesignstudio/src/qtdesignstudio-using-effect-maker-effects.qdoc
new file mode 100644
index 00000000000..1e53c53ba0f
--- /dev/null
+++ b/doc/qtdesignstudio/src/qtdesignstudio-using-effect-maker-effects.qdoc
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+
+ \page qt-using-effect-maker-effects.html
+ \nextpage qtquick-motion-design.html
+ \previouspage creator-exporting-qml.html
+
+ \title Using Qt Quick Effect Maker Effects
+
+ \QQEM is integrated into \QDS for creating shader effects. To create an
+ effect, you first create the effect file in \QDS, and then you edit it in \QQEM.
+
+ For more information about \QQEM, see the
+ \l{https://doc.qt.io/qt-6/qtquickeffectmaker-index.html}{Qt Quick Effect Maker Manual}.
+
+ \section1 Creating an Effect File
+
+ To create an effect file in \QDS:
+
+ \list 1
+ \li Right-click in the \uicontrol Assets view and
+ select \uicontrol {New Effect}.
+ \QDS creates an effect file and opens it in \QQEM.
+ \image qt-quick-effect-maker.webp
+ \li Edit the effect.
+ \li In \QQEM, go to \uicontrol File > \uicontrol Save.
+ \li With the default settings, select \uicontrol OK.
+ \image effect-maker-export.png
+ \endlist
+
+ Now, you can close \QQEM and return to \QDS and apply the
+ effect.
+
+ \section1 Applying an Effect
+
+ You can apply effects to components in \QDS. To do so, drag the effect
+ from the \uicontrol Assets view to the component in the \uicontrol 2D or
+ \uicontrol Navigator view.
+
+ \image apply-effect-maker-effect.webp
+
+*/
diff --git a/doc/qtdesignstudio/src/qtdesignstudio.qdoc b/doc/qtdesignstudio/src/qtdesignstudio.qdoc
index e9f302ce859..adf772987d4 100644
--- a/doc/qtdesignstudio/src/qtdesignstudio.qdoc
+++ b/doc/qtdesignstudio/src/qtdesignstudio.qdoc
@@ -81,6 +81,7 @@
\li \l{Converting Qt 5 Projects into Qt 6 Projects}
\li \l{Converting UI Projects to Applications}
\li \l{Using External Tools}
+ \li \l{\QDS on MCUs}
\endlist
\li \b {\l Help}
\list
diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc
index e861133efd5..7af07ae66e4 100644
--- a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc
+++ b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-3d-assets.qdoc
@@ -4,26 +4,11 @@
/*!
\page exporting-3d-assets.html
- \if defined(qtdesignstudio)
\previouspage qtbridge-figma-template.html
- \else
- \previouspage quick-states.html
- \endif
\nextpage exporting-from-blender.html
\title Exporting 3D Assets
- \if defined(qtcreator)
- \table
- \row
- \li \inlineimage blender-logo.png
- \li \inlineimage maya-logo.png
- \row
- \li \l{Exporting from Blender}{Blender}
- \li \l{Exporting from Maya}{Maya}
- \endtable
- \endif
-
You can import files you created using 3D graphics applications and exported
to several widely-used formats, such as .blend, .dae, .fbx, .glb, .gltf,
.obj, .uia, or .uip. For a list of formats supported by each \l{Qt Quick 3D}
diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-maya.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-maya.qdoc
index 238b6e6dfdb..16494923806 100644
--- a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-maya.qdoc
+++ b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-maya.qdoc
@@ -4,11 +4,7 @@
/*!
\page exporting-from-maya.html
\previouspage exporting-from-blender.html
- \if defined (qtdesignstudio)
\nextpage exporting-from-qt3ds.html
- \else
- \nextpage studio-importing-3d.html
- \endif
\title Exporting from Maya
diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc
index 49bc8894139..360a21183b0 100644
--- a/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc
+++ b/doc/qtdesignstudio/src/qtquick3d-editor/exporting-3d/exporting-from-qt3ds.qdoc
@@ -4,11 +4,7 @@
/*!
\page exporting-from-qt3ds.html
\previouspage exporting-from-maya.html
- \if defined(qtdesignstudio)
\nextpage studio-importing-designs.html
- \else
- \nextpage studio-importing-3d.html
- \endif
\title Exporting from Qt 3D Studio
diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc
index fd31970ef51..45d517a0bf4 100644
--- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc
+++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-importing.qdoc
@@ -3,11 +3,8 @@
/*!
\page studio-importing-3d.html
- \if defined(qtdesignstudio)
+
\previouspage qtquick-fonts.html
- \else
- \previouspage exporting-from-maya.html
- \endif
\nextpage creator-exporting-qml.html
\title Importing 3D Assets
diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc
index 47e39f32118..8c798a31a4f 100644
--- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc
+++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-3d-lights.qdoc
@@ -208,4 +208,97 @@
To specify the maximum distance for the shadow map, set the
\uicontrol {Shadow map far} property value. Using smaller values
may improve the precision and effects of the map.
+
+ \section1 Baking Lightmaps
+
+ \note Lightmaps baking is released as technical preview in \QDS 4.1.
+
+ \section2 Baking Lightmaps for a 3D Model
+ Baked lightmap components are not visible in the \uicontrol Navigator view by default. To make
+ them visible, select \inlineimage icons/visibilityon.png
+ in the \uicontrol Navigator view.
+
+ To bake lightmaps for a 3D model:
+ \list 1
+ \li From \uicontrol Components, drag a \uicontrol {Baked Lightmap} component to
+ the 3D model in the \uicontrol Navigator view.
+ \image baked-lightmaps-navigator.png
+ \li In the \uicontrol Navigator view, select \e bakedLightmap and in the \uicontrol Properties
+ view:
+ \list
+ \li Select \uicontrol Enabled.
+ \li In \uicontrol Key, set the filename base for the generated light maps. This must be
+ a unique name.
+ \li In \uicontrol {Load Prefix}, set the relative path to the folder where the generated
+ light map files are saved.
+ \endlist
+ \li In the \uicontrol Navigator view, select the 3D model and in the \uicontrol Properties
+ view, select \uicontrol {Used in Baked Lighting}.
+ \li Optional. Adjust \uicontrol Resolution to set the light map resoution. This effects how
+ accurate and time-consuming the lightmap baking is.
+ \li In the \uicontrol Navigator view, select the light component that you want to bake
+ lightmaps for, and in the \uicontrol Properties view, set \uicontrol {Bake Mode} to BakeModeAll.
+ \li Right-click anywhere in the \uicontrol 3D view and select \uicontrol {Bake Lights}.
+ \endlist
+
+ \section2 Baking Lightmaps for a 3D Model Inside a Sub Component
+
+ To bake lightmaps for a 3D model inside a sub component, first add a local custom property to
+ expose the model:
+
+ \list 1
+ \li In the \uicontrol Navigator view, right-click the sub component and select
+ \uicontrol {Edit Component}.
+ \image baked-lightmaps-edit-component.png
+ \li In the \uicontrol Navigator view, select the root component.
+ \li In the \uicontrol Properties view, select \inlineimage icons/plus.png
+ in the \uicontrol {Local Custom Properties} section.
+ \li Add a new property, set \uicontrol Type to alias.
+ \image baked-lightmaps-add-property.png
+ \li For the property, set the value to the ID of the 3D model that you want
+ to bake lightmaps for.
+ \image baked-lightmaps-property-value.png
+ \li In the \uicontrol Navigator view, select the 3D model and in the \uicontrol Properties
+ view:
+ \list
+ \li Select \uicontrol {Used in Baked Lighting}.
+ \li Set \uicontrol Resolution to, for example, 128.
+ \endlist
+ \li Save your changes (\key {Ctrl+S}) and return to the main project file. To do this, select
+ the bread crumb in the top toolbar.
+ \image baked-lightmaps-exit-component.png
+ \li From the \uicontrol Components view, drag a \uicontrol {Baked Lightmap} component to the
+ sub component in the \uicontrol Navigator view.
+ \image baked-lightmaps-navigator-blm.png
+ \li In the \uicontrol Navigator view, select the sub component and go to the
+ \uicontrol Code view.
+ \li In the \uicontrol Code view, you need to set the properties for the model inside the sub
+ component by using the exposed property.
+
+ Add the following code inside the sub component.
+ \code
+ lmSphere.bakedLightmap: bakedLightmap
+ \endcode
+
+ It should look something like this:
+ \code
+ MyGroup {
+ id: group
+ lmSphere.bakedLightmap: bakedLightmap
+ BakedLightmap {
+ id: bakedLightmap
+ loadPrefix: "lightmaps"
+ }
+ }
+ \endcode
+ \li In the \uicontrol Navigator view, select \e bakedLightMap, and in the \uicontrol
+ Properties view:
+ \list
+ \li Select \uicontrol Enabled.
+ \li In \uicontrol Key, set the filename base for the generated light maps. This must be
+ a unique name.
+ \endlist
+ \li Right-click anywhere in the \uicontrol 3D view and select \uicontrol {Bake Lights}.
+ \endlist
+
*/
diff --git a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-optimized-3d-scenes.qdoc b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-optimized-3d-scenes.qdoc
index 4032685223c..535bb392cab 100644
--- a/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-optimized-3d-scenes.qdoc
+++ b/doc/qtdesignstudio/src/qtquick3d-editor/qtdesignstudio-optimized-3d-scenes.qdoc
@@ -4,11 +4,7 @@
/*!
\page studio-optimized-3d-scenes.html
\previouspage qtquick-optimizing-designs.html
- \if defined(qtdesignstudio)
\nextpage studio-implementing-applications.html
- \else
- \nextpage qtquick-iso-icon-browser.html
- \endif
\title Creating Optimized 3D Scenes
@@ -22,11 +18,7 @@
\section1 The Optimal 3D Scene Example
- \if defined(qtdesignstudio)
The \l {Optimal 3D Scene}
- \else
- The Optimal 3D Scene
- \endif
example features four versions of the same kitchen
scene that have been created using different strategies: High, Low, Combined,
and Vertex Color. The High Scene includes a significantly higher number of
diff --git a/doc/qtdesignstudio/src/views/creator-logical-operators.qdocinc b/doc/qtdesignstudio/src/views/creator-logical-operators.qdocinc
index e3bb54af62c..307dfbfd36a 100644
--- a/doc/qtdesignstudio/src/views/creator-logical-operators.qdocinc
+++ b/doc/qtdesignstudio/src/views/creator-logical-operators.qdocinc
@@ -62,13 +62,10 @@
different type.
\endtable
- \if defined(qtdesignstudio)
Alternatively, you can use \uicontrol {And Operator},
\uicontrol {Or Operator}, and \uicontrol {Not Operator}
components to bind property values using the boolean AND,
OR, and NOT operator. For more information, see \l{Logic Helpers}.
- \endif
-
In addition, you can use arithmetic operators to compare numbers before
checks. However, we recommend that you create separate properties for this
diff --git a/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc
index 8592db6a046..1e2786bfbc1 100644
--- a/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-components-view.qdoc
@@ -36,10 +36,8 @@
\li \l {UI Controls}
\li \l {User Interaction Methods}
\li \l {Lists and Other Data Models}
- \if defined(qtdesignstudio)
\li \l {2D Effects}
\li \l {Logic Helpers}
- \endif
\li \l Animations
\li \l{3D Views}
\li \l{Node}
diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc
index 4221657e6b8..613d8fd02f4 100644
--- a/doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-connection-editor-bindings.qdoc
@@ -54,11 +54,7 @@
\list
\li \l{Using States to Change Component Property Values}
- \if defined(qtdesignstudio)
\li \l{Exporting Properties}
- \else
- \li \l{Moving the Bubble} in \l{Creating a Mobile Application}
- \endif
\endlist
For more information, watch the following video:
diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc
index 0d61823fc66..8accd1df488 100644
--- a/doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-connection-editor-properties.qdoc
@@ -4,11 +4,8 @@
/*!
\page quick-dynamic-properties.html
\previouspage quick-property-bindings.html
- \if defined(qtdesignstudio)
\nextpage quick-states.html
- \else
- \nextpage quick-connections-backend.html
- \endif
+
\sa {Specifying Component Properties}
\title Specifying Custom Properties
diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc
index a37d41c6355..420226750dc 100644
--- a/doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-connection-editor-signals.qdoc
@@ -63,17 +63,12 @@
in the context menu to specify the connection in
\uicontrol {Connection Editor}.
- \if defined(qtcreator)
- For an example of using the \uicontrol {Connections} view, see
- \l{Connecting Mouse Clicks to State Changes}.
- \else
For examples of using the \uicontrol {Connections} view, see:
\list
\li \l{Connecting Buttons to States} in \l{Log In UI - States}
\li \l{Connecting Buttons to State Changes} in \l{Washing Machine UI}
\endlist
- \endif
\section1 Adding Signal Handlers
diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc
index 0512af58ad1..58831990191 100644
--- a/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-connection-editor.qdoc
@@ -33,12 +33,6 @@
not otherwise exist for a particular \l{Component Types}
{component type} or your custom components.
- \if defined(qtcreator)
- \li \l{Managing C++ Backend Objects}
-
- Application developers can access QObject objects implemented in C++
- from QML files.
- \endif
\endlist
For an example of using properties, bindings, and connections to create a
diff --git a/doc/qtdesignstudio/src/views/qtquick-connection-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-connection-view.qdoc
index 69c2a78dc9c..93fbdc7ea7a 100644
--- a/doc/qtdesignstudio/src/views/qtquick-connection-view.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-connection-view.qdoc
@@ -37,11 +37,6 @@
custom properties that would not otherwise exist for a particular
\l{Component Types}{component type}.
- \if defined(qtcreator)
- In addition, application developers can use the \uicontrol Backends view
- to access QObject objects implemented in C++ from QML files.
- \endif
-
\section1 Summary of the Connections View Tabs
\table
@@ -64,11 +59,6 @@
\li Add custom properties that would not otherwise exist for a
particular preset component or your own custom component.
\li \l{Specifying Custom Properties}
- \if defined(qtcreator)
- \row
- \li \uicontrol Backends
- \li Access QObject objects implemented in C++ from QML files.
- \li \l{Managing C++ Backend Objects}
- \endif
+
\endtable
*/
diff --git a/doc/qtdesignstudio/src/views/qtquick-designer.qdoc b/doc/qtdesignstudio/src/views/qtquick-designer.qdoc
index a324c6f5626..cc18d924417 100644
--- a/doc/qtdesignstudio/src/views/qtquick-designer.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-designer.qdoc
@@ -9,13 +9,9 @@
/*!
\page creator-using-qt-quick-designer.html
- \if defined(qtdesignstudio)
+
\previouspage creator-modes.html
\nextpage qtquick-form-editor.html
- \else
- \previouspage quick-projects.html
- \nextpage quick-uis.html
- \endif
\title Design Views
@@ -151,7 +147,6 @@
\li Keyboard Shortcut
\li Read More
- \if defined(qtdesignstudio)
\row
\li \inlineimage icons/home.png
\li \uicontrol {Home}: opens the welcome page.
@@ -168,7 +163,6 @@
make to the UI are instantly visible to you in the preview.
\li \key Alt+P (\key Opt+P on \macos)
\li \l{Validating with Target Hardware}
- \endif
\row
\li Currently open file
diff --git a/doc/qtdesignstudio/src/views/qtquick-properties.qdoc b/doc/qtdesignstudio/src/views/qtquick-properties.qdoc
index 8ce14eba6bf..fc8ba92e93f 100644
--- a/doc/qtdesignstudio/src/views/qtquick-properties.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-properties.qdoc
@@ -214,7 +214,6 @@
use of solid color fills or images. Consider using gradients only for
static components in a UI.
- \if defined(qtdesignstudio)
\section2 Setting Gradient Properties
\image qtquick-designer-gradient-types.png "Available gradient types"
@@ -262,7 +261,6 @@
in the \uicontrol Angle field.
\image qtquick-designer-gradient-properties-conical.png "Conical gradient properties"
- \endif
\section2 Selecting Web Gradients
diff --git a/doc/qtdesignstudio/src/views/qtquick-states.qdoc b/doc/qtdesignstudio/src/views/qtquick-states.qdoc
index 6b55e5e59f0..60e3c3f86b7 100644
--- a/doc/qtdesignstudio/src/views/qtquick-states.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-states.qdoc
@@ -3,13 +3,8 @@
/*!
\page quick-states.html
- \if defined(qtdesignstudio)
\previouspage quick-dynamic-properties.html
\nextpage creator-live-preview.html
- \else
- \previouspage quick-connections-backend.html
- \nextpage exporting-3d-assets.html
- \endif
\title Working with States
@@ -32,13 +27,11 @@
> \uicontrol {Qt Quick Controls} > \uicontrol Controls has predefined
\e normal and \e down states.
- \if defined(qtdesignstudio)
This also applies to the custom button component that you can create
by using a \l{Creating Custom Controls}{wizard template}. For more
information about editing the states within the button component and
hiding and showing buttons to create several screens, see
\l{Log In UI - Components} and \l{Log In UI - States}.
- \endif
To add motion to a screen, you can change the position of a component
instance in the \uicontrol {2D} view and then add animation to the change
@@ -122,11 +115,9 @@
when: control.pressed || control.checked && !control.hovered
\endcode
- \if defined(qtdesignstudio)
If you are not familiar with writing expressions, you can use preset
\l{Logic Helpers}{logic helpers} from \uicontrol Components
> \uicontrol {Qt Quick Studio Logic Helper}.
- \endif
\section1 Using States
@@ -169,10 +160,6 @@
select \uicontrol Default.
\endlist
- \if defined(qtcreator)
- \include qtquick-states-scxml.qdocinc scxml state machines
- \endif
-
\section1 State Groups
With state groups, you can change the state of certain components
diff --git a/doc/qtdesignstudio/src/views/qtquick-text-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-text-editor.qdoc
index aaaf254d1e6..75e84be9c45 100644
--- a/doc/qtdesignstudio/src/views/qtquick-text-editor.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-text-editor.qdoc
@@ -4,11 +4,7 @@
/*!
\page qtquick-text-editor.html
\previouspage qtquick-curve-editor.html
- \if defined(qtdesignstudio)
\nextpage creator-projects-view.html
- \else
- \nextpage quick-uis.html
- \endif
\title Code
diff --git a/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc b/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc
index 1fcf4ef9088..81947261841 100644
--- a/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-timeline-view.qdoc
@@ -46,10 +46,7 @@
\youtube V3Po15bNErw
- \if defined(qtdesignstudio)
To try it yourself, follow the \l{Log In UI - Timeline} tutorial.
- \endif
-
For more information about creating timeline animations, see
\l{Creating Timeline Animations}.
diff --git a/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc b/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc
index 12b1fc14633..c6a33f62c70 100644
--- a/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-timeline.qdoc
@@ -250,7 +250,6 @@
create a timeline for the Item, and set the rotation property for the start
and end keyframes.
- \if defined(qtdesignstudio)
\section1 Animating Shapes
You can use the \uicontrol {Qt Quick Studio Components} to animate the
@@ -263,5 +262,5 @@
\li \l Rectangle
\li \l Triangle
\endlist
- \endif
+
*/
diff --git a/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc b/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc
index 3ee43335d69..b21207259e2 100644
--- a/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc
+++ b/doc/qtdesignstudio/src/views/qtquick-transition-editor.qdoc
@@ -114,8 +114,4 @@
To remove the current transition, select the \inlineimage icons/minus.png
(\uicontrol {Remove Transition}) button.
- \if defined(qtcreator)
- For an example of animating transitions between states, see
- \l {Creating a Qt Quick Application}.
- \endif
*/
diff --git a/doc/qtdesignstudio/src/views/studio-workspaces.qdoc b/doc/qtdesignstudio/src/views/studio-workspaces.qdoc
index 8d29b1f74f0..b5f7abf0d34 100644
--- a/doc/qtdesignstudio/src/views/studio-workspaces.qdoc
+++ b/doc/qtdesignstudio/src/views/studio-workspaces.qdoc
@@ -3,11 +3,7 @@
/*!
\page creator-project-managing-workspaces.html
- \if defined(qtdesignstudio)
\previouspage studio-texture-editor.html
- \else
- \previouspage creator-open-documents-view.html
- \endif
\nextpage creator-project-managing-sessions.html
\title Managing Workspaces
diff --git a/qtcreator.qbs b/qtcreator.qbs
index 7f70064e84a..c0779f4af10 100644
--- a/qtcreator.qbs
+++ b/qtcreator.qbs
@@ -5,7 +5,7 @@ import qbs.FileInfo
Project {
name: "Qt Creator"
minimumQbsVersion: "1.19.0"
- property string minimumMacosVersion: "10.14"
+ property string minimumMacosVersion: "10.15"
property bool withAutotests: qbs.buildVariant === "debug"
property path ide_source_tree: path
property pathList additionalPlugins: []
diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFilesDialog.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFilesDialog.qml
index 756176dccaf..24bc01d1abb 100644
--- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFilesDialog.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFilesDialog.qml
@@ -8,7 +8,7 @@ import StudioTheme as StudioTheme
import StudioControls as StudioControls
import AssetsLibraryBackend
-Dialog {
+StudioControls.Dialog {
id: root
title: qsTr("Confirm Delete Files")
anchors.centerIn: parent
diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFolderDialog.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFolderDialog.qml
index 6faef2434a0..1f92c57a753 100644
--- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFolderDialog.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/ConfirmDeleteFolderDialog.qml
@@ -5,9 +5,10 @@ import QtQuick
import QtQuick.Controls
import HelperWidgets as HelperWidgets
import StudioTheme as StudioTheme
+import StudioControls as StudioControls
import AssetsLibraryBackend
-Dialog {
+StudioControls.Dialog {
id: root
title: qsTr("Folder Not Empty")
diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewEffectDialog.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewEffectDialog.qml
index a5a12355871..a78e038f229 100644
--- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewEffectDialog.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewEffectDialog.qml
@@ -8,7 +8,7 @@ import StudioControls as StudioControls
import StudioTheme as StudioTheme
import AssetsLibraryBackend
-Dialog {
+StudioControls.Dialog {
id: root
title: qsTr("Create New Effect")
diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewFolderDialog.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewFolderDialog.qml
index a1afe464916..3426f7965a6 100644
--- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewFolderDialog.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/NewFolderDialog.qml
@@ -8,7 +8,7 @@ import StudioControls as StudioControls
import StudioTheme as StudioTheme
import AssetsLibraryBackend
-Dialog {
+StudioControls.Dialog {
id: root
title: qsTr("Create New Folder")
@@ -86,8 +86,10 @@ Dialog {
text: qsTr("Create")
enabled: folderName.text !== "" && root.createdDirPath.length <= root.__maxPath
onClicked: {
- root.createdDirPath = root.dirPath + '/' + folderName.text
- if (AssetsLibraryBackend.assetsModel.addNewFolder(root.createdDirPath))
+ let dirPathToCreate = root.dirPath + '/' + folderName.text
+ root.createdDirPath = AssetsLibraryBackend.assetsModel.addNewFolder(root.createdDirPath)
+
+ if (root.createdDirPath)
root.accept()
else
creationFailedDialog.open()
diff --git a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/RenameFolderDialog.qml b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/RenameFolderDialog.qml
index 0b9ae302550..16c36de63d2 100644
--- a/share/qtcreator/qmldesigner/assetsLibraryQmlSources/RenameFolderDialog.qml
+++ b/share/qtcreator/qmldesigner/assetsLibraryQmlSources/RenameFolderDialog.qml
@@ -8,7 +8,7 @@ import StudioControls as StudioControls
import StudioTheme as StudioTheme
import AssetsLibraryBackend
-Dialog {
+StudioControls.Dialog {
id: root
title: qsTr("Rename Folder")
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml
index 5bafd1d0526..aadd4b0d991 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterial.qml
@@ -178,6 +178,17 @@ Item {
}
} // Column
+ Timer {
+ id: delayedFinish
+ interval: 200
+
+ onTriggered: {
+ downloadPane.endDownload()
+
+ root.downloadState = "downloaded"
+ }
+ }
+
MultiFileDownloader {
id: downloader
@@ -191,9 +202,7 @@ Item {
}
onFinishedChanged: {
- downloadPane.endDownload()
-
- root.downloadState = "downloaded"
+ delayedFinish.restart()
}
onDownloadCanceled: {
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml
index 2c6a5256f46..975e65e266b 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryMaterialsView.qml
@@ -12,6 +12,7 @@ HelperWidgets.ScrollView {
clip: true
interactive: !ctxMenu.opened && !ContentLibraryBackend.rootView.isDragging
+ && !HelperWidgets.Controller.contextMenuOpened
readonly property int cellWidth: 100
readonly property int cellHeight: 120
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml
index a556aad72ad..3ba94430290 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexture.qml
@@ -147,9 +147,6 @@ Item {
if (root.downloadState !== "" && root.downloadState !== "failed")
return
- if (!ContentLibraryBackend.rootView.markTextureDownloading())
- return
-
progressBar.visible = true
tooltip.visible = false
root.progressText = qsTr("Downloading...")
@@ -223,14 +220,20 @@ Item {
root.progressValue = 0
root.downloadState = ""
-
- ContentLibraryBackend.rootView.markNoTextureDownloading()
}
onDownloadFailed: {
root.downloadState = "failed"
+ }
+ }
+
+ Timer {
+ id: delayedFinish
+ interval: 200
- ContentLibraryBackend.rootView.markNoTextureDownloading()
+ onTriggered: {
+ modelData.setDownloaded()
+ root.downloadState = modelData.isDownloaded() ? "downloaded" : "failed"
}
}
@@ -242,10 +245,7 @@ Item {
alwaysCreateDir: false
clearTargetPathContents: false
onFinishedChanged: {
- modelData.setDownloaded()
- root.downloadState = modelData.isDownloaded() ? "downloaded" : "failed"
-
- ContentLibraryBackend.rootView.markNoTextureDownloading()
+ delayedFinish.restart()
}
}
}
diff --git a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml
index 1c24f9bc43b..7471a22cfb7 100644
--- a/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml
+++ b/share/qtcreator/qmldesigner/contentLibraryQmlSource/ContentLibraryTexturesView.qml
@@ -12,6 +12,7 @@ HelperWidgets.ScrollView {
clip: true
interactive: !ctxMenu.opened && !ContentLibraryBackend.rootView.isDragging
+ && !HelperWidgets.Controller.contextMenuOpened
readonly property int cellWidth: 100
readonly property int cellHeight: 100
diff --git a/share/qtcreator/qmldesigner/designericons.json b/share/qtcreator/qmldesigner/designericons.json
index f695e63b563..ddbfcf5a850 100644
--- a/share/qtcreator/qmldesigner/designericons.json
+++ b/share/qtcreator/qmldesigner/designericons.json
@@ -32,6 +32,9 @@
"ArrangeIcon": {
"iconName": "arrange_small"
},
+ "BackspaceIcon": {
+ "iconName": "backspace_small"
+ },
"CameraIcon": {
"iconName": "camera_small"
},
diff --git a/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsProgressDialog.qml b/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsProgressDialog.qml
new file mode 100644
index 00000000000..18494d5f327
--- /dev/null
+++ b/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsProgressDialog.qml
@@ -0,0 +1,102 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuickDesignerTheme
+import HelperWidgets
+import StudioControls as StudioControls
+import StudioTheme as StudioTheme
+
+Rectangle {
+ id: root
+
+ color: StudioTheme.Values.themePanelBackground
+
+ Connections {
+ target: rootView
+ function onProgress(msg) {
+ progressText.text += progressText.text === "" ? msg : "\n" + msg
+ scrollView.ensureVisible()
+ }
+
+ function onFinished() {
+ cancelButton.text = qsTr("Close")
+ }
+ }
+
+ Column {
+ id: col
+ padding: 5
+ leftPadding: 10
+ spacing: 5
+
+ Text {
+ id: title
+ text: qsTr("Baking lights for 3D view: %1").arg(sceneId)
+ font.bold: true
+ font.pixelSize: StudioTheme.Values.myFontSize
+ color: StudioTheme.Values.themeTextColor
+ }
+
+ Rectangle {
+ id: rect
+ width: root.width - 16
+ height: root.height - title.height - cancelButton.height - 20
+
+ color: StudioTheme.Values.themePanelBackground
+ border.color: StudioTheme.Values.themeControlOutline
+ border.width: StudioTheme.Values.border
+
+ ScrollView {
+ id: scrollView
+
+ anchors.fill: parent
+ anchors.margins: 4
+
+ clip: true
+
+ Behavior on contentY {
+ PropertyAnimation {
+ easing.type: Easing.InOutQuad
+ }
+ }
+
+ Text {
+ id: progressText
+ width: scrollView.width
+ font.pixelSize: StudioTheme.Values.myFontSize
+ color: StudioTheme.Values.themeTextColor
+ }
+
+ function ensureVisible()
+ {
+ let newPos = scrollView.contentHeight - scrollView.height
+ scrollView.contentY = newPos < 0 ? 0 : newPos
+ }
+ }
+
+ }
+
+ Row {
+ spacing: StudioTheme.Values.dialogButtonSpacing
+ height: cancelButton.height
+ anchors.right: rect.right
+
+ Button {
+ id: bakeAgainButton
+ text: qsTr("Bake Again")
+ anchors.margins: StudioTheme.Values.dialogButtonPadding
+ onClicked: rootView.rebake()
+ }
+
+ Button {
+ id: cancelButton
+ text: qsTr("Cancel")
+ anchors.margins: StudioTheme.Values.dialogButtonPadding
+ onClicked: rootView.cancel()
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsSetupDialog.qml b/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsSetupDialog.qml
new file mode 100644
index 00000000000..5924756bedf
--- /dev/null
+++ b/share/qtcreator/qmldesigner/edit3dQmlSource/BakeLightsSetupDialog.qml
@@ -0,0 +1,223 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+import QtQuickDesignerTheme
+import HelperWidgets
+import StudioControls as StudioControls
+import StudioTheme as StudioTheme
+
+Rectangle {
+ id: root
+
+ color: StudioTheme.Values.themePanelBackground
+
+ Column {
+ id: col
+ padding: 5
+ leftPadding: 10
+ spacing: 5
+
+ Text {
+ id: title
+ text: qsTr("Lights baking setup for 3D view: %1").arg(sceneId)
+ font.bold: true
+ font.pixelSize: StudioTheme.Values.myFontSize
+ color: StudioTheme.Values.themeTextColor
+ }
+
+ Rectangle {
+ id: ctrlRect
+ width: root.width - 16
+ height: root.height - title.height - manualCheckBox.height - 20
+
+ color: StudioTheme.Values.themePanelBackground
+ border.color: StudioTheme.Values.themeControlOutline
+ border.width: StudioTheme.Values.border
+
+ ListView {
+ id: listView
+
+ anchors.fill: parent
+ anchors.margins: 4
+
+ clip: true
+ model: bakeModel
+ spacing: 5
+
+ delegate: Row {
+ spacing: 12
+ enabled: !manualCheckBox.checked
+
+ Text {
+ text: displayId
+ color: StudioTheme.Values.themeTextColor
+ width: isTitle ? listView.width : listView.width - 320
+
+ clip: true
+ font.bold: isTitle
+ verticalAlignment: Qt.AlignVCenter
+ horizontalAlignment: Qt.AlignLeft
+ height: bakeModeCombo.height
+ leftPadding: isTitle ? 0 : 8
+
+ ToolTipArea {
+ anchors.fill: parent
+ tooltip: displayId // Useful for long ids
+ }
+ }
+
+ Button {
+ visible: isUnexposed
+ text: qsTr("Expose models and lights")
+ leftPadding: StudioTheme.Values.dialogButtonPadding
+ rightPadding: StudioTheme.Values.dialogButtonPadding
+ height: bakeModeCombo.height
+ onClicked: {
+ rootView.apply()
+ rootView.exposeModelsAndLights(nodeId)
+ }
+ }
+
+ StudioControls.ComboBox {
+ id: bakeModeCombo
+ model: ListModel {
+ ListElement { text: qsTr("Baking Disabled"); value: "Light.BakeModeDisabled" }
+ ListElement { text: qsTr("Bake Indirect"); value: "Light.BakeModeIndirect" }
+ ListElement { text: qsTr("Bake All"); value: "Light.BakeModeAll" }
+ }
+
+ visible: !isModel && !isTitle && !isUnexposed
+ textRole: "text"
+ valueRole: "value"
+ currentIndex: bakeMode === "Light.BakeModeAll"
+ ? 2 : bakeMode === "Light.BakeModeIndirect" ? 1 : 0
+ actionIndicatorVisible: false
+
+ hoverEnabled: true
+ ToolTip.visible: hovered
+ ToolTip.text: qsTr("The baking mode applied to this light.")
+
+ onActivated: bakeMode = currentValue
+ }
+
+ StudioControls.CheckBox {
+ visible: isModel && !isTitle && !isUnexposed
+ checked: inUse
+ text: qsTr("In Use")
+ actionIndicatorVisible: false
+
+ hoverEnabled: true
+ ToolTip.visible: hovered
+ ToolTip.text: qsTr("If checked, this model contributes to baked lighting,\nfor example in form of casting shadows or indirect light.")
+
+ onToggled: inUse = checked
+ }
+
+ StudioControls.CheckBox {
+ visible: isModel && !isTitle && !isUnexposed
+ checked: isEnabled
+ text: qsTr("Enabled")
+ actionIndicatorVisible: false
+
+ hoverEnabled: true
+ ToolTip.visible: hovered
+ ToolTip.text: qsTr("If checked, baked lightmap texture is generated and rendered for this model.")
+
+ onToggled: isEnabled = checked
+ }
+
+ Row {
+ width: resolutionLabel.width + resolutionValue.width + StudioTheme.Values.sectionRowSpacing
+ spacing: StudioTheme.Values.sectionRowSpacing
+ visible: isModel && !isTitle && !isUnexposed
+ Text {
+ id: resolutionLabel
+ text: qsTr("Resolution:")
+ color: enabled ? StudioTheme.Values.themeTextColor
+ : StudioTheme.Values.themeTextColorDisabled
+ verticalAlignment: Qt.AlignVCenter
+ horizontalAlignment: Qt.AlignRight
+ height: resolutionValue.height
+ }
+
+ StudioControls.RealSpinBox {
+ id: resolutionValue
+ realFrom: 128
+ realTo: 128000
+ realValue: resolution
+ realStepSize: 128
+ width: 60
+ actionIndicatorVisible: false
+
+ hoverEnabled: true
+ ToolTip.visible: hovered
+ ToolTip.text: qsTr("Generated lightmap resolution for this model.")
+
+ onRealValueChanged: resolution = realValue
+ }
+ }
+ }
+ }
+ }
+
+ Item {
+ height: manualCheckBox.height
+ width: ctrlRect.width
+
+ StudioControls.CheckBox {
+ id: manualCheckBox
+ checked: rootView.manualMode
+ text: qsTr("Setup baking manually")
+ actionIndicatorVisible: false
+
+ hoverEnabled: true
+ ToolTip.visible: hovered
+ ToolTip.text: qsTr("If checked, baking settings above are not applied on close or bake.\nInstead, user is expected to set baking properties manually.")
+
+ onToggled: rootView.manualMode = checked
+ }
+
+ Row {
+ spacing: StudioTheme.Values.dialogButtonSpacing
+ height: manualCheckBox.height
+ anchors.right: parent.right
+
+ Button {
+ id: cancelButton
+ text: qsTr("Cancel")
+ leftPadding: StudioTheme.Values.dialogButtonPadding
+ rightPadding: StudioTheme.Values.dialogButtonPadding
+ height: manualCheckBox.height
+ onClicked: rootView.cancel()
+ }
+
+ Button {
+ id: applyButton
+ text: qsTr("Apply & Close")
+ leftPadding: StudioTheme.Values.dialogButtonPadding
+ rightPadding: StudioTheme.Values.dialogButtonPadding
+ height: manualCheckBox.height
+ onClicked: {
+ rootView.apply()
+ rootView.cancel()
+ }
+ }
+
+ Button {
+ id: bakeButton
+ text: qsTr("Bake")
+ leftPadding: StudioTheme.Values.dialogButtonPadding
+ rightPadding: StudioTheme.Values.dialogButtonPadding
+ height: manualCheckBox.height
+ onClicked: {
+ rootView.apply()
+ rootView.bakeLights()
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/insight/Main.qml b/share/qtcreator/qmldesigner/insight/Main.qml
new file mode 100644
index 00000000000..3d0cd777753
--- /dev/null
+++ b/share/qtcreator/qmldesigner/insight/Main.qml
@@ -0,0 +1,417 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick
+import QtQuick.Controls
+import QtQuickDesignerTheme 1.0
+import HelperWidgets 2.0 as HelperWidgets
+import StudioControls 1.0 as StudioControls
+import StudioTheme as StudioTheme
+
+Rectangle {
+ id: root
+
+ color: Theme.qmlDesignerBackgroundColorDarkAlternate()
+
+ component Title : Text {
+ color: StudioTheme.Values.themeTextColor
+ font {
+ pixelSize: StudioTheme.Values.baseFontSize
+ bold: true
+ }
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ Layout.fillWidth: true
+ Layout.preferredHeight: 30
+ }
+
+ StudioControls.Dialog {
+ id: renameDialog
+
+ property string name: ""
+
+ title: qsTr("Failed to rename \"" + renameDialog.name + "\".")
+ standardButtons: Dialog.Close
+ x: Math.round((root.width - renameDialog.width) / 2)
+ y: Math.round((root.height - renameDialog.height) / 2)
+ closePolicy: Popup.NoAutoClose
+
+ Text {
+ color: StudioTheme.Values.themeTextColor
+ font.pixelSize: StudioTheme.Values.baseFontSize
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ wrapMode: Text.WordWrap
+ text: qsTr("Can't rename category, name already exists.")
+ anchors.fill: parent
+ }
+ }
+
+ HelperWidgets.ScrollView {
+ clip: true
+ anchors.fill: parent
+
+ Column {
+ id: column
+ width: root.width
+
+ Section {
+ id: trackingSection
+ caption: qsTr("Tracking")
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ property int rowSpacing: 16
+
+ ColumnLayout {
+ spacing: StudioTheme.Values.sectionRowSpacing
+ width: parent.width - StudioTheme.Values.sectionLayoutRightPadding
+
+ Text {
+ wrapMode: Text.WordWrap
+ color: StudioTheme.Values.themeTextColor
+ font.pixelSize: StudioTheme.Values.baseFontSize
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ text: qsTr("With tracking turned on, the application tracks user interactions for all component types in the selected predefined categories.")
+ Layout.fillWidth: true
+ }
+
+ Title { text: qsTr("Tracking") }
+
+ Row {
+ spacing: trackingSection.rowSpacing
+
+ StudioControls.Switch {
+ id: trackingSwitch
+ actionIndicatorVisible: false
+ checked: insightModel.enabled
+
+ onToggled: insightModel.setEnabled(trackingSwitch.checked)
+ }
+
+ Text {
+ color: StudioTheme.Values.themeTextColor
+ text: trackingSwitch.checked ? qsTr("Enabled") : qsTr("Disabled")
+ font.pixelSize: StudioTheme.Values.baseFontSize
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ height: trackingSwitch.height
+ }
+ }
+
+ Title { text: qsTr("Token") }
+
+ Text {
+ wrapMode: Text.WordWrap
+ color: StudioTheme.Values.themeTextColor
+ font.pixelSize: StudioTheme.Values.baseFontSize
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ text: qsTr("Tokens are used to match the data your application sends to your Qt Insight Organization.")
+ Layout.fillWidth: true
+ }
+
+ StudioControls.TextField {
+ id: tokenField
+
+ property string previousToken
+
+ enabled: trackingSwitch.checked
+ actionIndicatorVisible: false
+ translationIndicatorVisible: false
+ placeholderText: qsTr("Add token here")
+ text: insightModel.token
+ Layout.fillWidth: true
+
+ onEditingFinished: {
+ if (tokenField.previousToken === tokenField.text)
+ return
+
+ tokenField.previousToken = tokenField.text
+ insightModel.setToken(tokenField.text)
+ }
+
+ Component.onCompleted: tokenField.previousToken = tokenField.text
+ }
+
+ Title { text: qsTr("Send Cadence") }
+
+ Row {
+ spacing: trackingSection.rowSpacing
+
+ StudioControls.SpinBox {
+ id: cadenceSpinBox
+ enabled: trackingSwitch.checked
+ actionIndicatorVisible: false
+ value: insightModel.minutes
+ onValueModified: insightModel.setMinutes(cadenceSpinBox.value)
+
+ __devicePixelRatio: insightModel.devicePixelRatio()
+
+ onDragStarted: insightModel.hideCursor()
+ onDragEnded: insightModel.restoreCursor()
+ onDragging: insightModel.holdCursorInPlace()
+ }
+
+ Text {
+ color: trackingSwitch.checked ? StudioTheme.Values.themeTextColor
+ : StudioTheme.Values.themeTextColorDisabled
+ text: qsTr("minutes")
+ font.pixelSize: StudioTheme.Values.baseFontSize
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ height: cadenceSpinBox.height
+ }
+ }
+ }
+ }
+
+ Section {
+ id: predefinedSection
+ caption: qsTr("Predefined Categories")
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ ColumnLayout {
+ enabled: trackingSwitch.checked
+ spacing: StudioTheme.Values.sectionRowSpacing
+ width: parent.width - StudioTheme.Values.sectionLayoutRightPadding
+
+ Text {
+ wrapMode: Text.WordWrap
+ color: StudioTheme.Values.themeTextColor
+ font.pixelSize: StudioTheme.Values.baseFontSize
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ text: qsTr("Select the categories to track")
+ Layout.fillWidth: true
+ }
+
+ Column {
+ id: predefinedTable
+
+ property int centerColumnWidth: predefinedTable.width
+ - selectAll.width
+ - 2 * predefinedTable.rowSpacing
+
+ readonly property int columnSpacing: 2
+ readonly property int rowSpacing: 8
+
+ Layout.fillWidth: true
+ spacing: predefinedTable.columnSpacing
+
+ Row {
+ spacing: predefinedTable.rowSpacing
+
+ StudioControls.CheckBox {
+ id: selectAll
+ actionIndicatorVisible: false
+ tristate: true
+ checkState: insightModel.predefinedSelectState
+ onClicked: insightModel.selectAllPredefined()
+ }
+
+ Text {
+ color: trackingSwitch.checked ? StudioTheme.Values.themeTextColor
+ : StudioTheme.Values.themeTextColorDisabled
+ font {
+ pixelSize: StudioTheme.Values.baseFontSize
+ bold: true
+ }
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ text: qsTr("Select all")
+ width: predefinedTable.centerColumnWidth
+ height: StudioTheme.Values.height
+ }
+ }
+
+ Item { width: 1; height: 4}
+
+ Repeater {
+ model: insightModel
+ delegate: Row {
+ id: predefinedDelegate
+
+ required property int index
+
+ required property string categoryName
+ required property string categoryColor
+ required property string categoryType
+ required property bool categoryActive
+
+ visible: predefinedDelegate.categoryType === "predefined"
+ spacing: predefinedTable.rowSpacing
+
+ StudioControls.CheckBox {
+ id: predefinedCheckBox
+ actionIndicatorVisible: false
+ checked: predefinedDelegate.categoryActive
+ onToggled: insightModel.setCategoryActive(predefinedDelegate.index,
+ predefinedCheckBox.checked)
+ }
+
+ Text {
+ color: trackingSwitch.checked ? StudioTheme.Values.themeTextColor
+ : StudioTheme.Values.themeTextColorDisabled
+ font.pixelSize: StudioTheme.Values.baseFontSize
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ text: predefinedDelegate.categoryName
+ width: predefinedTable.centerColumnWidth
+ height: StudioTheme.Values.height
+ }
+ }
+ }
+ }
+ }
+ }
+
+ Section {
+ id: customSection
+ caption: qsTr("Custom Categories")
+ anchors.left: parent.left
+ anchors.right: parent.right
+
+ ColumnLayout {
+ enabled: trackingSwitch.checked
+ spacing: StudioTheme.Values.sectionRowSpacing
+ width: parent.width - StudioTheme.Values.sectionLayoutRightPadding
+
+ Text {
+ wrapMode: Text.WordWrap
+ color: StudioTheme.Values.themeTextColor
+ font.pixelSize: StudioTheme.Values.baseFontSize
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ text: qsTr("Manage your own categories")
+ Layout.fillWidth: true
+ }
+
+ Column {
+ id: customTable
+
+ property int centerColumnWidth: predefinedTable.centerColumnWidth
+ - StudioTheme.Values.height
+ - predefinedTable.rowSpacing
+
+ Layout.fillWidth: true
+ spacing: predefinedTable.columnSpacing
+
+ Row {
+ spacing: predefinedTable.rowSpacing
+
+ StudioControls.CheckBox {
+ id: selectAllCustom
+ actionIndicatorVisible: false
+ tristate: true
+ checkState: insightModel.customSelectState
+ onClicked: insightModel.selectAllCustom()
+ }
+
+ Text {
+ color: trackingSwitch.checked ? StudioTheme.Values.themeTextColor
+ : StudioTheme.Values.themeTextColorDisabled
+ font {
+ pixelSize: StudioTheme.Values.baseFontSize
+ bold: true
+ }
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ text: qsTr("Select all")
+ width: predefinedTable.centerColumnWidth
+ height: StudioTheme.Values.height
+ }
+ }
+
+ Item { width: 1; height: 4}
+
+ Repeater {
+ id: customRepeater
+ model: insightModel
+
+ delegate: Row {
+ id: customDelegate
+
+ required property int index
+
+ required property string categoryName
+ required property string categoryColor
+ required property string categoryType
+ required property bool categoryActive
+
+ visible: customDelegate.categoryType === "custom"
+ spacing: predefinedTable.rowSpacing
+
+ StudioControls.CheckBox {
+ id: customCheckBox
+ actionIndicatorVisible: false
+ checked: customDelegate.categoryActive
+ onToggled: insightModel.setCategoryActive(customDelegate.index,
+ customCheckBox.checked)
+ }
+
+ StudioControls.TextField {
+ id: categoryName
+
+ property string previousName
+
+ actionIndicatorVisible: false
+ translationIndicatorVisible: false
+ text: customDelegate.categoryName
+ width: customTable.centerColumnWidth
+ height: StudioTheme.Values.height
+ onEditingFinished: {
+ if (categoryName.text === categoryName.previousName)
+ return
+
+ var result = insightModel.renameCategory(customDelegate.index,
+ categoryName.text)
+
+ if (!result) {
+ renameDialog.name = categoryName.text
+ categoryName.text = categoryName.previousName
+ renameDialog.open()
+ }
+ }
+
+ Component.onCompleted: categoryName.previousName = categoryName.text
+ }
+
+ StudioControls.AbstractButton {
+ id: removeButton
+ buttonIcon: StudioTheme.Constants.closeCross
+ onClicked: insightModel.removeCateogry(customDelegate.index)
+ }
+ }
+ }
+
+ Item { width: 1; height: 4}
+
+ Row {
+ spacing: StudioTheme.Values.checkBoxSpacing
+
+ StudioControls.AbstractButton {
+ id: plusButton
+ buttonIcon: StudioTheme.Constants.plus
+ onClicked: insightModel.addCategory()
+ }
+
+ Text {
+ color: trackingSwitch.checked ? StudioTheme.Values.themeTextColor
+ : StudioTheme.Values.themeTextColorDisabled
+ font.pixelSize: StudioTheme.Values.baseFontSize
+ horizontalAlignment: Text.AlignLeft
+ verticalAlignment: Text.AlignVCenter
+ text: qsTr("Add new Category")
+ width: predefinedTable.centerColumnWidth
+ height: StudioTheme.Values.height
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml
index 620feb3b113..f0031999fa5 100644
--- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml
+++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowser.qml
@@ -334,7 +334,7 @@ Item {
{
// commit rename upon changing selection
if (root.currMaterialItem)
- root.currMaterialItem.commitRename();
+ root.currMaterialItem.forceFinishEditing();
root.currMaterialItem = materialRepeater.itemAt(materialBrowserModel.selectedIndex);
@@ -609,6 +609,7 @@ Item {
clip: true
visible: root.enableUiElements
interactive: !ctxMenu.opened && !ctxMenuTextures.opened && !rootView.isDragging
+ && !HelperWidgets.Controller.contextMenuOpened
Behavior on contentY {
id: contentYBehavior
@@ -770,7 +771,7 @@ Item {
model: materialBrowserTexturesModel
delegate: TextureItem {
width: root.cellWidth
- height: root.cellWidth
+ height: root.cellHeight
onShowContextMenu: {
ctxMenuTextures.popupMenu(model)
diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserItemName.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserItemName.qml
new file mode 100644
index 00000000000..800217bac55
--- /dev/null
+++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialBrowserItemName.qml
@@ -0,0 +1,68 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+import QtQuick 2.15
+import QtQuick.Layouts 1.15
+import QtQuickDesignerTheme 1.0
+import HelperWidgets 2.0
+import StudioTheme 1.0 as StudioTheme
+import MaterialBrowserBackend
+
+TextInput {
+ id: root
+
+ clip: true
+ readOnly: true
+ selectByMouse: !root.readOnly
+
+ horizontalAlignment: TextInput.AlignHCenter
+
+ font.pixelSize: StudioTheme.Values.myFontSize
+
+ color: StudioTheme.Values.themeTextColor
+ selectionColor: StudioTheme.Values.themeTextSelectionColor
+ selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor
+
+ // allow only alphanumeric characters, underscores, no space at start, and 1 space between words
+ validator: RegExpValidator { regExp: /^(\w+\s)*\w+$/ }
+
+ signal renamed(string newName)
+ signal clicked()
+
+ function startRename()
+ {
+ root.readOnly = false
+ root.selectAll()
+ root.forceActiveFocus()
+ root.ensureVisible(root.text.length)
+ mouseArea.enabled = false
+ }
+
+ function commitRename()
+ {
+ if (root.readOnly)
+ return;
+
+ root.renamed(root.text)
+ }
+
+ onEditingFinished: root.commitRename()
+
+ onActiveFocusChanged: {
+ if (!activeFocus) {
+ root.readOnly = true
+ mouseArea.enabled = true
+ ensureVisible(0)
+ }
+ }
+
+ Component.onCompleted: ensureVisible(0)
+
+ MouseArea {
+ id: mouseArea
+ anchors.fill: parent
+
+ onClicked: root.clicked()
+ onDoubleClicked: root.startRename()
+ }
+}
diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml
index abf3717e20a..86fec0936da 100644
--- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml
+++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/MaterialItem.qml
@@ -19,22 +19,9 @@ Rectangle {
img.source = "image://materialBrowser/" + materialInternalId
}
- function startRename()
+ function forceFinishEditing()
{
- matName.readOnly = false
- matName.selectAll()
- matName.forceActiveFocus()
- matName.ensureVisible(matName.text.length)
- nameMouseArea.enabled = false
- }
-
- function commitRename()
- {
- if (matName.readOnly)
- return;
-
- MaterialBrowserBackend.materialBrowserModel.renameMaterial(index, matName.text);
- mouseArea.forceActiveFocus()
+ matName.commitRename()
}
border.width: MaterialBrowserBackend.materialBrowserModel.selectedIndex === index ? MaterialBrowserBackend.rootView.materialSectionFocused ? 3 : 1 : 0
@@ -106,50 +93,21 @@ Rectangle {
e.accepted = true;
}
- TextInput {
+ MaterialBrowserItemName {
id: matName
text: materialName
-
width: img.width
- clip: true
anchors.horizontalCenter: parent.horizontalCenter
- horizontalAlignment: TextInput.AlignHCenter
-
- font.pixelSize: StudioTheme.Values.myFontSize
-
- readOnly: true
- selectByMouse: !matName.readOnly
- color: StudioTheme.Values.themeTextColor
- selectionColor: StudioTheme.Values.themeTextSelectionColor
- selectedTextColor: StudioTheme.Values.themeTextSelectedTextColor
-
- // allow only alphanumeric characters, underscores, no space at start, and 1 space between words
- validator: RegExpValidator { regExp: /^(\w+\s)*\w+$/ }
-
- onEditingFinished: root.commitRename()
-
- onActiveFocusChanged: {
- if (!activeFocus) {
- matName.readOnly = true
- nameMouseArea.enabled = true
- ensureVisible(0)
- }
+ onRenamed: (newName) => {
+ MaterialBrowserBackend.materialBrowserModel.renameMaterial(index, newName);
+ mouseArea.forceActiveFocus()
}
- Component.onCompleted: ensureVisible(0)
-
- MouseArea {
- id: nameMouseArea
-
- anchors.fill: parent
-
- onClicked: {
- MaterialBrowserBackend.materialBrowserModel.selectMaterial(index)
- MaterialBrowserBackend.rootView.focusMaterialSection(true)
- }
- onDoubleClicked: root.startRename()
+ onClicked: {
+ MaterialBrowserBackend.materialBrowserModel.selectMaterial(index)
+ MaterialBrowserBackend.rootView.focusMaterialSection(true)
}
}
}
diff --git a/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml b/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml
index 99970bc2661..b0a5e138099 100644
--- a/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml
+++ b/share/qtcreator/qmldesigner/materialBrowserQmlSource/TextureItem.qml
@@ -23,6 +23,11 @@ Rectangle {
signal showContextMenu()
+ function forceFinishEditing()
+ {
+ txtId.commitRename()
+ }
+
MouseArea {
id: mouseArea
@@ -59,13 +64,43 @@ Rectangle {
}
}
- Image {
- source: "image://materialBrowserTex/" + textureSource
- asynchronous: true
- width: root.width - 10
- height: root.height - 10
- anchors.centerIn: parent
- smooth: true
- fillMode: Image.PreserveAspectFit
+ Column {
+ anchors.fill: parent
+ spacing: 1
+
+ Item { width: 1; height: 5 } // spacer
+ Image {
+ id: img
+ source: "image://materialBrowserTex/" + textureSource
+ asynchronous: true
+ width: root.width - 10
+ height: img.width
+ anchors.horizontalCenter: parent.horizontalCenter
+ smooth: true
+ fillMode: Image.PreserveAspectFit
+ }
+
+ // Eat keys so they are not passed to parent while editing name
+ Keys.onPressed: (e) => {
+ e.accepted = true;
+ }
+
+ MaterialBrowserItemName {
+ id: txtId
+
+ text: textureId
+ width: img.width
+ anchors.horizontalCenter: parent.horizontalCenter
+
+ onRenamed: (newId) => {
+ MaterialBrowserBackend.materialBrowserTexturesModel.setTextureId(index, newId);
+ mouseArea.forceActiveFocus()
+ }
+
+ onClicked: {
+ MaterialBrowserBackend.materialBrowserTexturesModel.selectTexture(index)
+ MaterialBrowserBackend.rootView.focusMaterialSection(false)
+ }
+ }
}
}
diff --git a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml
index 9b49a036fe0..cdc6f51900b 100644
--- a/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml
+++ b/share/qtcreator/qmldesigner/newprojectdialog/imports/NewProjectDialog/Details.qml
@@ -402,6 +402,7 @@ Item {
ListElement { name: "Qt 6.2" }
ListElement { name: "Qt 6.3" }
ListElement { name: "Qt 6.4" }
+ ListElement { name: "Qt 6.5" }
}
onActivated: (index) => {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQml/TimerSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQml/TimerSpecifics.qml
index 9ff90a2b9fa..8be28295d67 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQml/TimerSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQml/TimerSpecifics.qml
@@ -92,14 +92,17 @@ Column {
PropertyLabel {
text: qsTr("Triggered on start")
tooltip: qsTr("Sets the timer to trigger when started.")
+ blockedByTemplate: !triggeredOnStartComboBox.enabled
}
SecondColumnLayout {
CheckBox {
+ id: triggeredOnStartComboBox
text: backendValues.triggeredOnStart.valueToString
implicitWidth: StudioTheme.Values.twoControlColumnWidth
+ StudioTheme.Values.actionIndicatorWidth
backendValue: backendValues.triggeredOnStart
+ enabled: backendValues.triggeredOnStart.isAvailable
}
ExpandingSpacer {}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TextAreaSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TextAreaSpecifics.qml
index 766e2b78aa5..d6b0c76c57e 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TextAreaSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TextAreaSpecifics.qml
@@ -16,6 +16,8 @@ Column {
showVerticalAlignment: true
}
+ TextInputSection {}
+
TextExtrasSection {
showWrapMode: true
showFormatProperty: true
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TextFieldSpecifics.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TextFieldSpecifics.qml
index d7286272309..b0aa6fbfc59 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TextFieldSpecifics.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/Controls/TextFieldSpecifics.qml
@@ -14,11 +14,21 @@ Column {
caption: qsTr("Text Field")
}
- CharacterSection {}
+ CharacterSection {
+ showVerticalAlignment: true
+ }
- TextExtrasSection {}
+ TextInputSection {
+ isTextInput: true
+ }
- FontExtrasSection {}
+ TextExtrasSection {
+ showWrapMode: true
+ }
+
+ FontExtrasSection {
+ showStyle: false
+ }
PaddingSection {}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml
index 1820af7958b..4db5a98c225 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComboBox.qml
@@ -1,7 +1,7 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
+import QtQuick
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
@@ -10,8 +10,8 @@ StudioControls.ComboBox {
property variant backendValue
- labelColor: edit && !colorLogic.errorState ? StudioTheme.Values.themeTextColor
- : colorLogic.textColor
+ labelColor: comboBox.edit && !colorLogic.errorState ? StudioTheme.Values.themeTextColor
+ : colorLogic.textColor
property string scope: "Qt"
enum ValueType { String, Integer, Enum }
@@ -74,7 +74,6 @@ StudioControls.ComboBox {
comboBox.backendValue.commitDrop(dropArea.dropData)
comboBox.hasActiveHoverDrag = false
}
-
}
ExtendedFunctionLogic {
@@ -102,6 +101,16 @@ StudioControls.ComboBox {
if (comboBox.manualMapping) {
comboBox.valueFromBackendChanged()
+ } else if (comboBox.valueRole && comboBox.textRole !== comboBox.valueRole) {
+ switch (comboBox.valueType) {
+ case ComboBox.ValueType.Enum:
+ comboBox.currentIndex = comboBox.indexOfValue(comboBox.backendValue.enumeration)
+ break
+ case ComboBox.ValueType.String:
+ case ComboBox.ValueType.Integer:
+ default:
+ comboBox.currentIndex = comboBox.indexOfValue(comboBox.backendValue.value)
+ }
} else {
switch (comboBox.valueType) {
case ComboBox.ValueType.String:
@@ -143,18 +152,14 @@ StudioControls.ComboBox {
}
onAccepted: {
- if (!comboBox.__isCompleted)
+ if (!comboBox.__isCompleted || comboBox.backendValue === undefined || comboBox.manualMapping)
return
let inputText = comboBox.editText
- let inputValue = inputText;
+ let inputValue = inputText
let index = comboBox.find(inputText)
- if (index !== -1) {
- let modelIdx = comboBox.model.index(index)
- inputValue = comboBox.valueRole
- ? comboBox.model.data(modelIdx, comboBox.valueRole)
- : comboBox.textAt(index)
- }
+ if (index !== -1)
+ inputValue = comboBox.valueRole ? comboBox.valueAt(index) : comboBox.textAt(index)
comboBox.backendValue.value = inputValue
@@ -162,37 +167,38 @@ StudioControls.ComboBox {
}
onCompressedActivated: {
- if (!comboBox.__isCompleted)
- return
-
- if (comboBox.backendValue === undefined)
- return
-
- if (comboBox.manualMapping)
+ if (!comboBox.__isCompleted || comboBox.backendValue === undefined || comboBox.manualMapping)
return
if (comboBox.valueRole && comboBox.textRole !== comboBox.valueRole) {
let inputText = comboBox.currentText
let inputValue = comboBox.currentValue
let index = comboBox.find(inputText)
- if (index !== -1) {
- let modelIdx = comboBox.model.index(index)
- inputValue = comboBox.model.data(modelIdx, comboBox.valueRole)
- }
- comboBox.backendValue.value = inputValue
- return
- }
- switch (comboBox.valueType) {
- case ComboBox.ValueType.String:
- comboBox.backendValue.value = comboBox.currentText
- break
- case ComboBox.ValueType.Integer:
- comboBox.backendValue.value = comboBox.currentIndex
- break
- case ComboBox.ValueType.Enum:
- default:
- comboBox.backendValue.setEnumeration(comboBox.scope, comboBox.currentText)
+ if (index !== -1)
+ inputValue = comboBox.valueAt(index)
+
+ switch (comboBox.valueType) {
+ case ComboBox.ValueType.Enum:
+ comboBox.backendValue.setEnumeration(comboBox.scope, inputValue)
+ break
+ case ComboBox.ValueType.String:
+ case ComboBox.ValueType.Integer:
+ default:
+ comboBox.backendValue.value = inputValue
+ }
+ } else {
+ switch (comboBox.valueType) {
+ case ComboBox.ValueType.String:
+ comboBox.backendValue.value = comboBox.currentText
+ break
+ case ComboBox.ValueType.Integer:
+ comboBox.backendValue.value = comboBox.currentIndex
+ break
+ case ComboBox.ValueType.Enum:
+ default:
+ comboBox.backendValue.setEnumeration(comboBox.scope, comboBox.currentText)
+ }
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentButton.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentButton.qml
index 6c7b1ceae8b..12c003af638 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentButton.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentButton.qml
@@ -27,7 +27,7 @@ Column {
AbstractButton {
implicitWidth: 180
- buttonIcon: qsTr("Edit Base Component")
+ buttonIcon: qsTr("Edit Component")
iconFont: StudioTheme.Constants.font
onClicked: goIntoComponent()
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml
index 839c656d8a1..49809cb9d97 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ComponentSection.qml
@@ -174,7 +174,29 @@ Section {
}
PropertyLabel {
- text: qsTr("Name")
+ visible: root.showState
+ text: qsTr("State")
+ tooltip: qsTr("Sets the state of the component.")
+ }
+
+ SecondColumnLayout {
+ visible: root.showState
+
+ ComboBox {
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ width: implicitWidth
+ editable: true
+ backendValue: backendValues.state
+ model: allStateNames
+ valueType: ComboBox.String
+ }
+
+ ExpandingSpacer {}
+ }
+
+ PropertyLabel {
+ text: annotationEditor.hasAuxData ? qsTr("Annotation") : ""
tooltip: qsTr("Adds a note with a title to explain the component.")
}
@@ -226,6 +248,7 @@ Section {
visible: !annotationEditor.hasAuxData
buttonIcon: qsTr("Add Annotation")
iconFont: StudioTheme.Constants.font
+ tooltip: qsTr("Adds a note with a title to explain the component.")
onClicked: annotationEditor.showWidget()
onHoveredChanged: annotationEditor.checkAux()
}
@@ -252,27 +275,5 @@ Section {
onCanceled: hideWidget()
}
}
-
- PropertyLabel {
- visible: root.showState
- text: qsTr("State")
- tooltip: qsTr("Sets the state of the component.")
- }
-
- SecondColumnLayout {
- visible: root.showState
-
- ComboBox {
- implicitWidth: StudioTheme.Values.singleControlColumnWidth
- + StudioTheme.Values.actionIndicatorWidth
- width: implicitWidth
- editable: true
- backendValue: backendValues.state
- model: allStateNames
- valueType: ComboBox.String
- }
-
- ExpandingSpacer {}
- }
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Controller.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Controller.qml
index 7b9be3890e2..1825a5e8fff 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Controller.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Controller.qml
@@ -9,6 +9,8 @@ QtObject {
property Item mainScrollView
+ property bool contextMenuOpened: false
+
signal collapseAll(string category)
signal expandAll(string category)
signal closeContextMenu()
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml
index 7b0ed94191a..b8792c71ea6 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/EditableListView.qml
@@ -1,8 +1,9 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-import QtQuick 2.15
-import QtQuick.Layouts 1.15
+import QtQuick
+import QtQuick.Layouts
+import HelperWidgets 2.0 as HelperWidgets
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
@@ -23,11 +24,12 @@ Item {
property real __actionIndicatorWidth: StudioTheme.Values.squareComponentWidth
property real __actionIndicatorHeight: StudioTheme.Values.height
property string typeFilter: "QtQuick3D.Material"
- property string textRole: "IdAndNameRole"
- property string valueRole: "IdRole"
+ property string textRole: "idAndName"
+ property string valueRole: "id"
property int activatedReason: ComboBox.ActivatedReason.Other
property bool delegateHover: false
+ property bool allowDuplicates: true
property string extraButtonIcon: "" // setting this will show an extra button
property string extraButtonToolTip: ""
@@ -40,11 +42,19 @@ Item {
Layout.preferredWidth: StudioTheme.Values.height * 10
Layout.preferredHeight: myColumn.height
+ HelperWidgets.ItemFilterModel {
+ id: itemFilterModel
+ typeFilter: root.typeFilter
+ modelNodeBackendProperty: modelNodeBackend
+ selectedItems: root.allowDuplicates ? [] : root.model
+ }
+
Component {
id: myDelegate
Row {
property alias comboBox: itemFilterComboBox
+
ListViewComboBox {
id: itemFilterComboBox
@@ -54,7 +64,7 @@ Item {
validator: RegExpValidator { regExp: /(^[a-z_]\w*|^[A-Z]\w*\.{1}([a-z_]\w*\.?)+)/ }
actionIndicatorVisible: false
- typeFilter: root.typeFilter
+ model: itemFilterModel
initialModelData: modelData
textRole: root.textRole
valueRole: root.valueRole
@@ -96,7 +106,7 @@ Item {
tooltip: root.extraButtonToolTip
onClicked: root.extraButtonClicked(index)
visible: root.extraButtonIcon !== ""
- enabled: root.model[index]
+ enabled: root.model[index] ?? false
}
IconIndicator {
@@ -188,7 +198,7 @@ Item {
visible: myRepeater.count === 0
validator: RegExpValidator { regExp: /(^[a-z_]\w*|^[A-Z]\w*\.{1}([a-z_]\w*\.?)+)/ }
actionIndicatorVisible: false
- typeFilter: root.typeFilter
+ model: itemFilterModel
textRole: root.textRole
valueRole: root.valueRole
implicitWidth: StudioTheme.Values.singleControlColumnWidth
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/InsightSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/InsightSection.qml
index 5a4c6f48a84..b23f8ff95d3 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/InsightSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/InsightSection.qml
@@ -8,7 +8,7 @@ import StudioTheme 1.0 as StudioTheme
Section {
id: root
- caption: qsTr("Analytics")
+ caption: qsTr("Insight")
anchors.left: parent.left
anchors.right: parent.right
@@ -84,5 +84,24 @@ Section {
ExpandingSpacer {}
}
+
+ PropertyLabel {
+ text: qsTr("Object name")
+ tooltip: qsTr("Sets the object name of the component.")
+ }
+
+ SecondColumnLayout {
+ LineEdit {
+ implicitWidth: StudioTheme.Values.singleControlColumnWidth
+ + StudioTheme.Values.actionIndicatorWidth
+ width: StudioTheme.Values.singleControlColumnWidth
+ backendValue: backendValues.objectName
+ text: backendValues.objectName.value
+ showTranslateCheckBox: false
+ enabled: !modelNodeBackend.multiSelection
+ }
+
+ ExpandingSpacer {}
+ }
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ItemFilterComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ItemFilterComboBox.qml
index 2f749271d77..316207e5f53 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ItemFilterComboBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ItemFilterComboBox.qml
@@ -1,7 +1,7 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-import QtQuick 2.15
+import QtQuick
import HelperWidgets 2.0 as HelperWidgets
HelperWidgets.ComboBox {
@@ -13,7 +13,7 @@ HelperWidgets.ComboBox {
editable: true
model: comboBox.addDefaultItem(itemFilterModel.itemModel)
- validator: RegExpValidator { regExp: /(^$|^[a-z_]\w*)/ }
+ validator: RegularExpressionValidator { regularExpression: /(^$|^[a-z_]\w*)/ }
HelperWidgets.ItemFilterModel {
id: itemFilterModel
@@ -32,17 +32,18 @@ HelperWidgets.ComboBox {
comboBox.setCurrentText(comboBox.textValue)
}
onModelChanged: comboBox.setCurrentText(comboBox.textValue)
- onCompressedActivated: function(index, reason) { comboBox.handleActivate(index) }
- Component.onCompleted: comboBox.setCurrentText(comboBox.textValue)
-
onEditTextChanged: comboBox.dirty = true
onFocusChanged: {
if (comboBox.dirty)
comboBox.handleActivate(comboBox.currentIndex)
}
- function handleActivate(index)
- {
+ onCompressedActivated: function(index, reason) { comboBox.handleActivate(index) }
+ onAccepted: comboBox.setCurrentText(comboBox.editText)
+
+ Component.onCompleted: comboBox.setCurrentText(comboBox.textValue)
+
+ function handleActivate(index) {
if (!comboBox.__isCompleted || comboBox.backendValue === undefined)
return
@@ -52,8 +53,7 @@ HelperWidgets.ComboBox {
comboBox.block = false
}
- function setCurrentText(text)
- {
+ function setCurrentText(text) {
if (!comboBox.__isCompleted || comboBox.backendValue === undefined)
return
@@ -78,8 +78,7 @@ HelperWidgets.ComboBox {
comboBox.dirty = false
}
- function addDefaultItem(arr)
- {
+ function addDefaultItem(arr) {
var copy = arr.slice()
copy.unshift(comboBox.defaultItem)
return copy
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml
index 0512b0861be..1f8dbbb3d41 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ListViewComboBox.qml
@@ -1,27 +1,19 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
-import QtQuick 2.15
+import QtQuick
import HelperWidgets 2.0 as HelperWidgets
import StudioControls 1.0 as StudioControls
StudioControls.ComboBox {
id: root
- property alias typeFilter: itemFilterModel.typeFilter
-
property var initialModelData
property bool __isCompleted: false
editable: true
- model: itemFilterModel
- textRole: "IdRole"
- valueRole: "IdRole"
-
- HelperWidgets.ItemFilterModel {
- id: itemFilterModel
- modelNodeBackendProperty: modelNodeBackend
- }
+ textRole: "id"
+ valueRole: "id"
Component.onCompleted: {
root.__isCompleted = true
@@ -42,9 +34,7 @@ StudioControls.ComboBox {
currentSelectedDataIndex = root.find(root.initialModelData)
} else {
for (let i = 0; i < root.count; ++i) {
- let movingModelIndex = root.model.index(i)
- let movingModelValueData = root.model.data(movingModelIndex, root.valueRole)
- if (movingModelValueData === root.initialModelData) {
+ if (root.valueAt(i) === root.initialModelData) {
currentSelectedDataIndex = i
break
}
@@ -55,14 +45,6 @@ StudioControls.ComboBox {
root.editText = root.initialModelData
}
- function currentData(role = root.valueRole) {
- if (root.currentIndex !== -1) {
- let currentModelIndex = root.model.index(root.currentIndex)
- return root.model.data(currentModelIndex, role)
- }
- return root.editText
- }
-
function availableValue() {
if (root.currentIndex !== -1 && root.currentValue !== "")
return root.currentValue
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml
index 5317d909e88..17a62874c25 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/PropertyEditorPane.qml
@@ -34,6 +34,8 @@ Rectangle {
clip: true
anchors.fill: parent
+ interactive: !Controller.contextMenuOpened
+
Column {
id: mainColumn
y: -1
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
index b965e8becdb..1cee92847fc 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/Section.qml
@@ -86,8 +86,8 @@ Item {
enabled: section.dropEnabled
anchors.fill: parent
- onEntered: (drag)=> section.dropEnter(drag)
- onDropped: (drag)=> section.drop(drag)
+ onEntered: (drag) => section.dropEnter(drag)
+ onDropped: (drag) => section.drop(drag)
onExited: section.dropExit()
}
@@ -114,6 +114,8 @@ Item {
text: qsTr("Collapse All")
onTriggered: Controller.collapseAll(section.category)
}
+
+ onOpenedChanged: Controller.contextMenuOpened = contextMenu.opened
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/TextInputSection.qml
index b76666f7bc5..737c742b33e 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/QtQuick/TextInputSection.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/TextInputSection.qml
@@ -7,7 +7,7 @@ import HelperWidgets 2.0
import StudioTheme 1.0 as StudioTheme
Section {
- id: textInputSection
+ id: root
anchors.left: parent.left
anchors.right: parent.right
caption: qsTr("Text Input")
@@ -46,7 +46,7 @@ Section {
+ StudioTheme.Values.actionIndicatorWidth
width: implicitWidth
backendValue: backendValues.mouseSelectionMode
- scope: "TextInput"
+ scope: root.isTextInput ? "TextInput" : "TextEdit"
model: ["SelectCharacters", "SelectWords"]
}
@@ -54,13 +54,13 @@ Section {
}
PropertyLabel {
- visible: textInputSection.isTextInput
+ visible: root.isTextInput
text: qsTr("Input mask")
tooltip: qsTr("Sets the allowed characters.")
}
SecondColumnLayout {
- visible: textInputSection.isTextInput
+ visible: root.isTextInput
LineEdit {
backendValue: backendValues.inputMask
@@ -74,13 +74,13 @@ Section {
}
PropertyLabel {
- visible: textInputSection.isTextInput
+ visible: root.isTextInput
text: qsTr("Echo mode")
tooltip: qsTr("Sets the visibility mode.")
}
SecondColumnLayout {
- visible: textInputSection.isTextInput
+ visible: root.isTextInput
ComboBox {
implicitWidth: StudioTheme.Values.singleControlColumnWidth
@@ -95,13 +95,13 @@ Section {
}
PropertyLabel {
- visible: textInputSection.isTextInput
+ visible: root.isTextInput
text: qsTr("Password character")
tooltip: qsTr("Sets which character to display when passwords are entered.")
}
SecondColumnLayout {
- visible: textInputSection.isTextInput
+ visible: root.isTextInput
LineEdit {
backendValue: backendValues.passwordCharacter
@@ -115,13 +115,13 @@ Section {
}
PropertyLabel {
- visible: !textInputSection.isTextInput
+ visible: !root.isTextInput
text: qsTr("Tab stop distance")
tooltip: qsTr("Default distance between tab stops in device units.")
}
SecondColumnLayout {
- visible: !textInputSection.isTextInput
+ visible: !root.isTextInput
SpinBox {
implicitWidth: StudioTheme.Values.twoControlColumnWidth
@@ -139,13 +139,13 @@ Section {
}
PropertyLabel {
- visible: !textInputSection.isTextInput
+ visible: !root.isTextInput
text: qsTr("Text margin")
tooltip: qsTr("Margin around the text in the Text Edit in pixels.")
}
SecondColumnLayout {
- visible: !textInputSection.isTextInput
+ visible: !root.isTextInput
SpinBox {
implicitWidth: StudioTheme.Values.twoControlColumnWidth
@@ -163,13 +163,13 @@ Section {
}
PropertyLabel {
- visible: textInputSection.isTextInput
+ visible: root.isTextInput
text: qsTr("Maximum length")
tooltip: qsTr("Sets the maximum length of the text.")
}
SecondColumnLayout {
- visible: textInputSection.isTextInput
+ visible: root.isTextInput
SpinBox {
implicitWidth: StudioTheme.Values.singleControlColumnWidth
@@ -216,13 +216,13 @@ Section {
FlagItem { backendValue: backendValues.activeFocusOnPress }
PropertyLabel {
- visible: textInputSection.isTextInput
+ visible: root.isTextInput
text: qsTr("Auto scroll")
tooltip: qsTr("Toggles if the text scrolls when it exceeds its boundary.")
}
FlagItem {
- visible: textInputSection.isTextInput
+ visible: root.isTextInput
backendValue: backendValues.autoScroll
}
@@ -248,12 +248,12 @@ Section {
FlagItem { backendValue: backendValues.selectByMouse }
PropertyLabel {
- visible: !textInputSection.isTextInput
+ visible: !root.isTextInput
text: qsTr("Select by keyboard")
}
FlagItem {
- visible: !textInputSection.isTextInput
+ visible: !root.isTextInput
backendValue: backendValues.selectByKeyboard
}
}
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir
index ca1411a4d6e..9c19a45e2ef 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir
@@ -67,6 +67,7 @@ Spacer 2.0 Spacer.qml
SpinBox 2.0 SpinBox.qml
StandardTextSection 2.0 StandardTextSection.qml
TextExtrasSection 2.0 TextExtrasSection.qml
+TextInputSection 2.0 TextInputSection.qml
ToolTipArea 2.0 ToolTipArea.qml
UrlChooser 2.0 UrlChooser.qml
VerticalScrollBar 2.0 VerticalScrollBar.qml
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml
index aba99f75ffa..2f219a411da 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml
@@ -121,7 +121,7 @@ T.SpinBox {
height: control.spinBoxIndicatorVisible ? control.__spinBoxIndicatorHeight : 0
realEnabled: (control.realFrom < control.realTo) ? (control.realValue < control.realTo)
- : (control.realValue > control.realTo)
+ : (control.realValue > control.realTo)
}
down.indicator: RealSpinBoxIndicator {
@@ -138,7 +138,7 @@ T.SpinBox {
height: control.spinBoxIndicatorVisible ? control.__spinBoxIndicatorHeight : 0
realEnabled: (control.realFrom < control.realTo) ? (control.realValue > control.realFrom)
- : (control.realValue < control.realFrom)
+ : (control.realValue < control.realFrom)
}
contentItem: RealSpinBoxInput {
@@ -284,26 +284,26 @@ T.SpinBox {
control.setRealValue(control.realValue) // sanitize and clamp realValue
spinBoxInput.text = control.textFromValue(control.realValue, control.locale)
control.value = 0 // Without setting value back to 0, it can happen that one of
- // the indicator will be disabled due to range logic.
+ // the indicator will be disabled due to range logic.
}
onRealValueModified: myTimer.restart()
onFocusChanged: {
- if (control.focus) {
+ if (control.focus)
control.dirty = false
- } else {
- // Make sure displayed value is correct after focus loss, as onEditingFinished
- // doesn't trigger when value is something validator doesn't accept.
- spinBoxInput.text = control.textFromValue(control.realValue, control.locale)
-
- if (control.dirty)
- spinBoxInput.handleEditingFinished()
- }
}
onDisplayTextChanged: spinBoxInput.text = control.displayText
onActiveFocusChanged: {
if (control.activeFocus) { // QTBUG-75862 && mySpinBox.focusReason === Qt.TabFocusReason)
control.preFocusText = spinBoxInput.text
spinBoxInput.selectAll()
+ } else {
+ // Make sure displayed value is correct after focus loss, as onEditingFinished
+ // doesn't trigger when value is something validator doesn't accept.
+ if (spinBoxInput.text === "")
+ spinBoxInput.text = control.textFromValue(control.realValue, control.locale)
+
+ if (control.dirty)
+ spinBoxInput.handleEditingFinished()
}
}
@@ -373,8 +373,8 @@ T.SpinBox {
value = Math.round(value)
control.realValue = control.clamp(value,
- control.validator.bottom,
- control.validator.top)
+ control.validator.bottom,
+ control.validator.top)
}
function realDecrease() {
diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml
index 1dddfec0b4f..3210559a688 100644
--- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml
+++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/TopLevelComboBox.qml
@@ -152,7 +152,10 @@ T.ComboBox {
contentItem: Text {
leftPadding: itemDelegateIconArea.width
- text: modelData
+ text: control.textRole ? (Array.isArray(control.model)
+ ? modelData[control.textRole]
+ : model[control.textRole])
+ : modelData
color: {
if (!itemDelegate.enabled)
return control.style.text.disabled
diff --git a/share/qtcreator/qmldesigner/qt4mcu/metadata.qml b/share/qtcreator/qmldesigner/qt4mcu/metadata.qml
index c5ff67fb0b1..d4da42cc0a1 100644
--- a/share/qtcreator/qmldesigner/qt4mcu/metadata.qml
+++ b/share/qtcreator/qmldesigner/qt4mcu/metadata.qml
@@ -5,7 +5,7 @@
Metadata {
id: metadataFile
- defaultVersion: v22
+ defaultVersion: v24
VersionData {
id: v14
@@ -48,4 +48,16 @@ Metadata {
name: "Qt for MCUs 2.2"
path: "qul-22.qml"
}
+
+ VersionData {
+ id: v23
+ name: "Qt for MCUs 2.3"
+ path: "qul-23.qml"
+ }
+
+ VersionData {
+ id: v24
+ name: "Qt for MCUs 2.4"
+ path: "qul-24.qml"
+ }
}
diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-14.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-14.qml
index 376f83d2261..2fedac684d1 100644
--- a/share/qtcreator/qmldesigner/qt4mcu/qul-14.qml
+++ b/share/qtcreator/qmldesigner/qt4mcu/qul-14.qml
@@ -4,21 +4,23 @@
VersionData {
name: "Qt for MCUs 1.4"
- bannedItems: ["QtQuick.AnimatedImage",
- "QtQuick.FocusScope",
- "QtQuick.TextInput",
- "QtQuick.TextEdit",
+ bannedItems: [
+ "QtQuick.AnimatedImage",
+ "QtQuick.AnimatedSprite",
"QtQuick.Flow",
+ "QtQuick.FocusScope",
"QtQuick.Grid",
"QtQuick.GridView",
"QtQuick.PathView",
+ "QtQuick.TextEdit",
+ "QtQuick.TextInput",
"QtQuick.Loader",
"QtQuick.Controls",
"QtQuick.Controls.BusyIndicator",
"QtQuick.Controls.ButtonGroup",
"QtQuick.Controls.CheckDelegate",
- "QtQuick.Controls.Container",
"QtQuick.Controls.ComboBox",
+ "QtQuick.Controls.Container",
"QtQuick.Controls.DelayButton",
"QtQuick.Controls.Frame",
"QtQuick.Controls.GroupBox",
@@ -35,18 +37,21 @@ VersionData {
"QtQuick.Controls.StackView",
"QtQuick.Controls.SwipeDelegate",
"QtQuick.Controls.SwitchDelegate",
- "QtQuick.Controls.ToolBar",
- "QtQuick.Controls.ToolButton",
"QtQuick.Controls.TabBar",
"QtQuick.Controls.TabButton",
"QtQuick.Controls.TextArea",
"QtQuick.Controls.TextField",
+ "QtQuick.Controls.ToolBar",
+ "QtQuick.Controls.ToolButton",
"QtQuick.Controls.ToolSeparator",
- "QtQuick.Controls.Tumbler"]
+ "QtQuick.Controls.Tumbler"
+ ]
- allowedImports: ["QtQuick",
+ allowedImports: [
+ "QtQuick",
"QtQuick.Controls",
- "QtQuick.Timeline"]
+ "QtQuick.Timeline"
+ ]
bannedImports: ["FlowView"]
@@ -58,6 +63,10 @@ VersionData {
"strikeout", "underline", "styleName"]
}
+ QtQml.Timer {
+ bannedProperties: ["triggeredOnStart"]
+ }
+
QtQuick.Item {
bannedProperties: ["layer", "opacity", "smooth", "antialiasing",
"baselineOffset", "focus", "activeFocusOnTab",
diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-17.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-17.qml
index 3a39626e745..95e10ad2e2d 100644
--- a/share/qtcreator/qmldesigner/qt4mcu/qul-17.qml
+++ b/share/qtcreator/qmldesigner/qt4mcu/qul-17.qml
@@ -4,21 +4,23 @@
VersionData {
name: "Qt for MCUs 1.7"
- bannedItems: ["QtQuick.AnimatedImage",
- "QtQuick.FocusScope",
- "QtQuick.TextInput",
- "QtQuick.TextEdit",
+ bannedItems: [
+ "QtQuick.AnimatedImage",
+ "QtQuick.AnimatedSprite",
"QtQuick.Flow",
+ "QtQuick.FocusScope",
"QtQuick.Grid",
"QtQuick.GridView",
"QtQuick.PathView",
+ "QtQuick.TextEdit",
+ "QtQuick.TextInput",
"QtQuick.Loader",
"QtQuick.Controls",
"QtQuick.Controls.BusyIndicator",
"QtQuick.Controls.ButtonGroup",
"QtQuick.Controls.CheckDelegate",
- "QtQuick.Controls.Container",
"QtQuick.Controls.ComboBox",
+ "QtQuick.Controls.Container",
"QtQuick.Controls.DelayButton",
"QtQuick.Controls.Frame",
"QtQuick.Controls.GroupBox",
@@ -35,20 +37,23 @@ VersionData {
"QtQuick.Controls.StackView",
"QtQuick.Controls.SwipeDelegate",
"QtQuick.Controls.SwitchDelegate",
- "QtQuick.Controls.ToolBar",
- "QtQuick.Controls.ToolButton",
"QtQuick.Controls.TabBar",
"QtQuick.Controls.TabButton",
"QtQuick.Controls.TextArea",
"QtQuick.Controls.TextField",
+ "QtQuick.Controls.ToolBar",
+ "QtQuick.Controls.ToolButton",
"QtQuick.Controls.ToolSeparator",
- "QtQuick.Controls.Tumbler"]
+ "QtQuick.Controls.Tumbler"
+ ]
- allowedImports: ["QtQuick",
+ allowedImports: [
+ "QtQuick",
"QtQuick.Controls",
"QtQuick.Timeline",
"QtQuickUltralite.Extras",
- "QtQuickUltralite.Layers"]
+ "QtQuickUltralite.Layers"
+ ]
bannedImports: ["FlowView"]
@@ -60,6 +65,10 @@ VersionData {
"strikeout", "underline", "styleName"]
}
+ QtQml.Timer {
+ bannedProperties: ["triggeredOnStart"]
+ }
+
QtQuick.Item {
bannedProperties: ["layer", "opacity", "smooth", "antialiasing",
"baselineOffset", "focus", "activeFocusOnTab",
diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-18.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-18.qml
index 2d501265e2d..5e3a76277cf 100644
--- a/share/qtcreator/qmldesigner/qt4mcu/qul-18.qml
+++ b/share/qtcreator/qmldesigner/qt4mcu/qul-18.qml
@@ -4,21 +4,23 @@
VersionData {
name: "Qt for MCUs 1.8"
- bannedItems: ["QtQuick.AnimatedImage",
- "QtQuick.FocusScope",
- "QtQuick.TextInput",
- "QtQuick.TextEdit",
+ bannedItems: [
+ "QtQuick.AnimatedImage",
+ "QtQuick.AnimatedSprite",
"QtQuick.Flow",
+ "QtQuick.FocusScope",
"QtQuick.Grid",
"QtQuick.GridView",
- "QtQuick.PathView",
"QtQuick.Loader",
+ "QtQuick.PathView",
+ "QtQuick.TextEdit",
+ "QtQuick.TextInput",
"QtQuick.Controls",
"QtQuick.Controls.BusyIndicator",
"QtQuick.Controls.ButtonGroup",
"QtQuick.Controls.CheckDelegate",
- "QtQuick.Controls.Container",
"QtQuick.Controls.ComboBox",
+ "QtQuick.Controls.Container",
"QtQuick.Controls.DelayButton",
"QtQuick.Controls.Frame",
"QtQuick.Controls.GroupBox",
@@ -35,25 +37,28 @@ VersionData {
"QtQuick.Controls.StackView",
"QtQuick.Controls.SwipeDelegate",
"QtQuick.Controls.SwitchDelegate",
- "QtQuick.Controls.ToolBar",
- "QtQuick.Controls.ToolButton",
"QtQuick.Controls.TabBar",
"QtQuick.Controls.TabButton",
"QtQuick.Controls.TextArea",
"QtQuick.Controls.TextField",
+ "QtQuick.Controls.ToolBar",
+ "QtQuick.Controls.ToolButton",
"QtQuick.Controls.ToolSeparator",
"QtQuick.Controls.Tumbler",
"QtQuick.Shapes.ConicalGradient",
"QtQuick.Shapes.LinearGradient",
"QtQuick.Shapes.RadialGradient",
- "QtQuick.Shapes.ShapeGradient"]
+ "QtQuick.Shapes.ShapeGradient"
+ ]
- allowedImports: ["QtQuick",
- "QtQuick.Shapes",
+ allowedImports: [
+ "QtQuick",
"QtQuick.Controls",
+ "QtQuick.Shapes",
"QtQuick.Timeline",
"QtQuickUltralite.Extras",
- "QtQuickUltralite.Layers"]
+ "QtQuickUltralite.Layers"
+ ]
bannedImports: ["FlowView"]
@@ -65,6 +70,10 @@ VersionData {
"strikeout", "underline", "styleName"]
}
+ QtQml.Timer {
+ bannedProperties: ["triggeredOnStart"]
+ }
+
QtQuick.Item {
bannedProperties: ["layer", "opacity", "smooth", "antialiasing",
"baselineOffset", "focus", "activeFocusOnTab",
diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-19.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-19.qml
index 249e27768c2..8f8cb78921f 100644
--- a/share/qtcreator/qmldesigner/qt4mcu/qul-19.qml
+++ b/share/qtcreator/qmldesigner/qt4mcu/qul-19.qml
@@ -4,21 +4,23 @@
VersionData {
name: "Qt for MCUs 1.9"
- bannedItems: ["QtQuick.AnimatedImage",
- "QtQuick.FocusScope",
- "QtQuick.TextInput",
- "QtQuick.TextEdit",
+ bannedItems: [
+ "QtQuick.AnimatedImage",
+ "QtQuick.AnimatedSprite",
"QtQuick.Flow",
+ "QtQuick.FocusScope",
"QtQuick.Grid",
"QtQuick.GridView",
- "QtQuick.PathView",
"QtQuick.Loader",
+ "QtQuick.PathView",
+ "QtQuick.TextEdit",
+ "QtQuick.TextInput",
"QtQuick.Controls",
"QtQuick.Controls.BusyIndicator",
"QtQuick.Controls.ButtonGroup",
"QtQuick.Controls.CheckDelegate",
- "QtQuick.Controls.Container",
"QtQuick.Controls.ComboBox",
+ "QtQuick.Controls.Container",
"QtQuick.Controls.DelayButton",
"QtQuick.Controls.Frame",
"QtQuick.Controls.GroupBox",
@@ -35,25 +37,28 @@ VersionData {
"QtQuick.Controls.StackView",
"QtQuick.Controls.SwipeDelegate",
"QtQuick.Controls.SwitchDelegate",
- "QtQuick.Controls.ToolBar",
- "QtQuick.Controls.ToolButton",
"QtQuick.Controls.TabBar",
"QtQuick.Controls.TabButton",
"QtQuick.Controls.TextArea",
"QtQuick.Controls.TextField",
+ "QtQuick.Controls.ToolBar",
+ "QtQuick.Controls.ToolButton",
"QtQuick.Controls.ToolSeparator",
"QtQuick.Controls.Tumbler",
"QtQuick.Shapes.ConicalGradient",
"QtQuick.Shapes.LinearGradient",
"QtQuick.Shapes.RadialGradient",
- "QtQuick.Shapes.ShapeGradient"]
+ "QtQuick.Shapes.ShapeGradient"
+ ]
- allowedImports: ["QtQuick",
- "QtQuick.Shapes",
+ allowedImports: [
+ "QtQuick",
"QtQuick.Controls",
+ "QtQuick.Shapes",
"QtQuick.Timeline",
"QtQuickUltralite.Extras",
- "QtQuickUltralite.Layers"]
+ "QtQuickUltralite.Layers"
+ ]
bannedImports: ["FlowView"]
@@ -65,6 +70,10 @@ VersionData {
"strikeout", "underline", "styleName"]
}
+ QtQml.Timer {
+ bannedProperties: ["triggeredOnStart"]
+ }
+
QtQuick.Item {
bannedProperties: ["layer", "opacity", "smooth", "antialiasing",
"baselineOffset", "focus", "activeFocusOnTab",
diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-20.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-20.qml
index 143d167b930..07bee0e403e 100644
--- a/share/qtcreator/qmldesigner/qt4mcu/qul-20.qml
+++ b/share/qtcreator/qmldesigner/qt4mcu/qul-20.qml
@@ -4,21 +4,23 @@
VersionData {
name: "Qt for MCUs 2.0"
- bannedItems: ["QtQuick.AnimatedImage",
- "QtQuick.FocusScope",
- "QtQuick.TextInput",
- "QtQuick.TextEdit",
+ bannedItems: [
+ "QtQuick.AnimatedImage",
+ "QtQuick.AnimatedSprite",
"QtQuick.Flow",
+ "QtQuick.FocusScope",
"QtQuick.Grid",
"QtQuick.GridView",
- "QtQuick.PathView",
"QtQuick.Loader",
+ "QtQuick.PathView",
+ "QtQuick.TextEdit",
+ "QtQuick.TextInput",
"QtQuick.Controls",
"QtQuick.Controls.BusyIndicator",
"QtQuick.Controls.ButtonGroup",
"QtQuick.Controls.CheckDelegate",
- "QtQuick.Controls.Container",
"QtQuick.Controls.ComboBox",
+ "QtQuick.Controls.Container",
"QtQuick.Controls.DelayButton",
"QtQuick.Controls.Frame",
"QtQuick.Controls.GroupBox",
@@ -35,25 +37,28 @@ VersionData {
"QtQuick.Controls.StackView",
"QtQuick.Controls.SwipeDelegate",
"QtQuick.Controls.SwitchDelegate",
- "QtQuick.Controls.ToolBar",
- "QtQuick.Controls.ToolButton",
"QtQuick.Controls.TabBar",
"QtQuick.Controls.TabButton",
"QtQuick.Controls.TextArea",
"QtQuick.Controls.TextField",
+ "QtQuick.Controls.ToolBar",
+ "QtQuick.Controls.ToolButton",
"QtQuick.Controls.ToolSeparator",
"QtQuick.Controls.Tumbler",
"QtQuick.Shapes.ConicalGradient",
"QtQuick.Shapes.LinearGradient",
"QtQuick.Shapes.RadialGradient",
- "QtQuick.Shapes.ShapeGradient"]
+ "QtQuick.Shapes.ShapeGradient"
+ ]
- allowedImports: ["QtQuick",
- "QtQuick.Shapes",
+ allowedImports: [
+ "QtQuick",
"QtQuick.Controls",
+ "QtQuick.Shapes",
"QtQuick.Timeline",
"QtQuickUltralite.Extras",
- "QtQuickUltralite.Layers"]
+ "QtQuickUltralite.Layers"
+ ]
bannedImports: ["FlowView"]
@@ -65,6 +70,10 @@ VersionData {
"strikeout", "underline", "styleName"]
}
+ QtQml.Timer {
+ bannedProperties: ["triggeredOnStart"]
+ }
+
QtQuick.Item {
bannedProperties: ["layer", "opacity", "smooth", "antialiasing",
"baselineOffset", "focus", "activeFocusOnTab",
diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-21.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-21.qml
index 1d2663b8a52..5f7de7a71f6 100644
--- a/share/qtcreator/qmldesigner/qt4mcu/qul-21.qml
+++ b/share/qtcreator/qmldesigner/qt4mcu/qul-21.qml
@@ -1,27 +1,26 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-//differences from 2.0:
-//text.elide is introduced in QUL
-
VersionData {
name: "Qt for MCUs 2.1"
- bannedItems: ["QtQuick.AnimatedImage",
- "QtQuick.FocusScope",
- "QtQuick.TextInput",
- "QtQuick.TextEdit",
+ bannedItems: [
+ "QtQuick.AnimatedImage",
+ "QtQuick.AnimatedSprite",
"QtQuick.Flow",
+ "QtQuick.FocusScope",
"QtQuick.Grid",
"QtQuick.GridView",
- "QtQuick.PathView",
"QtQuick.Loader",
+ "QtQuick.PathView",
+ "QtQuick.TextEdit",
+ "QtQuick.TextInput",
"QtQuick.Controls",
"QtQuick.Controls.BusyIndicator",
"QtQuick.Controls.ButtonGroup",
"QtQuick.Controls.CheckDelegate",
- "QtQuick.Controls.Container",
"QtQuick.Controls.ComboBox",
+ "QtQuick.Controls.Container",
"QtQuick.Controls.DelayButton",
"QtQuick.Controls.Frame",
"QtQuick.Controls.GroupBox",
@@ -38,25 +37,28 @@ VersionData {
"QtQuick.Controls.StackView",
"QtQuick.Controls.SwipeDelegate",
"QtQuick.Controls.SwitchDelegate",
- "QtQuick.Controls.ToolBar",
- "QtQuick.Controls.ToolButton",
"QtQuick.Controls.TabBar",
"QtQuick.Controls.TabButton",
"QtQuick.Controls.TextArea",
"QtQuick.Controls.TextField",
+ "QtQuick.Controls.ToolBar",
+ "QtQuick.Controls.ToolButton",
"QtQuick.Controls.ToolSeparator",
"QtQuick.Controls.Tumbler",
"QtQuick.Shapes.ConicalGradient",
"QtQuick.Shapes.LinearGradient",
"QtQuick.Shapes.RadialGradient",
- "QtQuick.Shapes.ShapeGradient"]
+ "QtQuick.Shapes.ShapeGradient"
+ ]
- allowedImports: ["QtQuick",
- "QtQuick.Shapes",
+ allowedImports: [
+ "QtQuick",
"QtQuick.Controls",
+ "QtQuick.Shapes",
"QtQuick.Timeline",
"QtQuickUltralite.Extras",
- "QtQuickUltralite.Layers"]
+ "QtQuickUltralite.Layers"
+ ]
bannedImports: ["FlowView"]
@@ -68,6 +70,10 @@ VersionData {
"strikeout", "underline", "styleName"]
}
+ QtQml.Timer {
+ bannedProperties: ["triggeredOnStart"]
+ }
+
QtQuick.Item {
bannedProperties: ["layer", "opacity", "smooth", "antialiasing",
"baselineOffset", "focus", "activeFocusOnTab",
diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-22.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-22.qml
index 8dbf0e0f120..b5c5c924b81 100644
--- a/share/qtcreator/qmldesigner/qt4mcu/qul-22.qml
+++ b/share/qtcreator/qmldesigner/qt4mcu/qul-22.qml
@@ -1,28 +1,26 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-//differences from 2.0:
-//2.1: + text.elide
-//2.2: + text.wrapMode
-
VersionData {
name: "Qt for MCUs 2.2"
- bannedItems: ["QtQuick.AnimatedImage",
- "QtQuick.FocusScope",
- "QtQuick.TextInput",
- "QtQuick.TextEdit",
+ bannedItems: [
+ "QtQuick.AnimatedImage",
+ "QtQuick.AnimatedSprite",
"QtQuick.Flow",
+ "QtQuick.FocusScope",
"QtQuick.Grid",
"QtQuick.GridView",
- "QtQuick.PathView",
"QtQuick.Loader",
+ "QtQuick.PathView",
+ "QtQuick.TextEdit",
+ "QtQuick.TextInput",
"QtQuick.Controls",
"QtQuick.Controls.BusyIndicator",
"QtQuick.Controls.ButtonGroup",
"QtQuick.Controls.CheckDelegate",
- "QtQuick.Controls.Container",
"QtQuick.Controls.ComboBox",
+ "QtQuick.Controls.Container",
"QtQuick.Controls.DelayButton",
"QtQuick.Controls.Frame",
"QtQuick.Controls.GroupBox",
@@ -39,25 +37,28 @@ VersionData {
"QtQuick.Controls.StackView",
"QtQuick.Controls.SwipeDelegate",
"QtQuick.Controls.SwitchDelegate",
- "QtQuick.Controls.ToolBar",
- "QtQuick.Controls.ToolButton",
"QtQuick.Controls.TabBar",
"QtQuick.Controls.TabButton",
"QtQuick.Controls.TextArea",
"QtQuick.Controls.TextField",
+ "QtQuick.Controls.ToolBar",
+ "QtQuick.Controls.ToolButton",
"QtQuick.Controls.ToolSeparator",
"QtQuick.Controls.Tumbler",
"QtQuick.Shapes.ConicalGradient",
"QtQuick.Shapes.LinearGradient",
"QtQuick.Shapes.RadialGradient",
- "QtQuick.Shapes.ShapeGradient"]
+ "QtQuick.Shapes.ShapeGradient"
+ ]
- allowedImports: ["QtQuick",
- "QtQuick.Shapes",
+ allowedImports: [
+ "QtQuick",
"QtQuick.Controls",
+ "QtQuick.Shapes",
"QtQuick.Timeline",
"QtQuickUltralite.Extras",
- "QtQuickUltralite.Layers"]
+ "QtQuickUltralite.Layers"
+ ]
bannedImports: ["FlowView"]
@@ -69,6 +70,10 @@ VersionData {
"strikeout", "underline", "styleName"]
}
+ QtQml.Timer {
+ bannedProperties: ["triggeredOnStart"]
+ }
+
QtQuick.Item {
bannedProperties: ["layer", "opacity", "smooth", "antialiasing",
"baselineOffset", "focus", "activeFocusOnTab",
diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-23.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-23.qml
new file mode 100644
index 00000000000..0c55d7db3a4
--- /dev/null
+++ b/share/qtcreator/qmldesigner/qt4mcu/qul-23.qml
@@ -0,0 +1,211 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+VersionData {
+ name: "Qt for MCUs 2.3"
+
+ bannedItems: [
+ "QtQuick.AnimatedImage",
+ "QtQuick.AnimatedSprite",
+ "QtQuick.Flow",
+ "QtQuick.FocusScope",
+ "QtQuick.Grid",
+ "QtQuick.GridView",
+ "QtQuick.PathView",
+ "QtQuick.TextEdit",
+ "QtQuick.TextInput",
+ "QtQuick.Controls",
+ "QtQuick.Controls.BusyIndicator",
+ "QtQuick.Controls.ButtonGroup",
+ "QtQuick.Controls.CheckDelegate",
+ "QtQuick.Controls.ComboBox",
+ "QtQuick.Controls.Container",
+ "QtQuick.Controls.DelayButton",
+ "QtQuick.Controls.Frame",
+ "QtQuick.Controls.GroupBox",
+ "QtQuick.Controls.ItemDelegate",
+ "QtQuick.Controls.Label",
+ "QtQuick.Controls.Page",
+ "QtQuick.Controls.PageIndicator",
+ "QtQuick.Controls.Pane",
+ "QtQuick.Controls.RadioDelegate",
+ "QtQuick.Controls.RangeSlider",
+ "QtQuick.Controls.RoundButton",
+ "QtQuick.Controls.ScrollView",
+ "QtQuick.Controls.SpinBox",
+ "QtQuick.Controls.StackView",
+ "QtQuick.Controls.SwipeDelegate",
+ "QtQuick.Controls.SwitchDelegate",
+ "QtQuick.Controls.TabBar",
+ "QtQuick.Controls.TabButton",
+ "QtQuick.Controls.TextArea",
+ "QtQuick.Controls.TextField",
+ "QtQuick.Controls.ToolBar",
+ "QtQuick.Controls.ToolButton",
+ "QtQuick.Controls.ToolSeparator",
+ "QtQuick.Controls.Tumbler",
+ "QtQuick.Shapes.ConicalGradient",
+ "QtQuick.Shapes.LinearGradient",
+ "QtQuick.Shapes.RadialGradient",
+ "QtQuick.Shapes.ShapeGradient"
+ ]
+
+ allowedImports: [
+ "QtQuick",
+ "QtQuick.Controls",
+ "QtQuick.Shapes",
+ "QtQuick.Timeline",
+ "QtQuickUltralite.Extras",
+ "QtQuickUltralite.Layers"
+ ]
+
+ bannedImports: ["FlowView"]
+
+ //ComplexProperty is not a type, it's just a way to handle bigger props
+ ComplexProperty {
+ prefix: "font"
+ bannedProperties: ["wordSpacing", "letterSpacing", "hintingPreference",
+ "kerning", "preferShaping", "capitalization",
+ "strikeout", "underline", "styleName"]
+ }
+
+ QtQml.Timer {
+ bannedProperties: ["triggeredOnStart"]
+ }
+
+ QtQuick.Item {
+ bannedProperties: ["layer", "opacity", "smooth", "antialiasing",
+ "baselineOffset", "focus", "activeFocusOnTab",
+ "rotation", "scale", "transformOrigin"]
+ }
+
+ QtQuick.Rectangle {
+ bannedProperties: ["gradient", "border"]
+ }
+
+ QtQuick.Flickable {
+ bannedProperties: ["boundsMovement", "flickDeceleration",
+ "leftMargin", "rightMargin", "bottomMargin", "topMargin",
+ "originX", "originY", "pixelAligned", "pressDelay", "synchronousDrag"]
+ }
+
+ QtQuick.MouseArea {
+ bannedProperties: ["propagateComposedEvents", "preventStealing", "cursorShape",
+ "scrollGestureEnabled", "drag", "acceptedButtons", "hoverEnabled"]
+ }
+
+ QtQuick.Image {
+ allowChildren: false
+ allowedProperties: ["rotation", "scale", "transformOrigin"]
+ bannedProperties: ["mirror", "mipmap", "cache", "autoTransform", "asynchronous",
+ "sourceSize", "smooth"]
+ }
+
+ QtQuick.BorderImage {
+ bannedProperties: ["asynchronous", "cache", "currentFrame", "frameCount",
+ "horizontalTileMode", "mirror", "progress", "smooth", "sourceSize",
+ "status", "verticalTileMode"]
+ }
+
+ QtQuick.Text {
+ allowChildren: false
+ allowedProperties: ["rotation", "scale", "transformOrigin"]
+ bannedProperties: ["lineHeight", "lineHeightMode", "style",
+ "styleColor", "minimumPointSize", "minimumPixelSize",
+ "fontSizeMode", "renderType", "renderTypeQuality", "textFormat", "maximumLineCount"]
+ }
+
+ QtQuick.Loader {
+ bannedProperties: ["asynchronous", "progress", "sourceComponent", "status"]
+ }
+
+ //Padding is not an actual item, but rather set of properties in Text
+ Padding {
+ bannedProperties: ["bottomPadding", "topPadding", "leftPadding", "rightPadding"]
+ }
+
+ QtQuick.Column {
+ bannedProperties: ["bottomPadding", "leftPadding", "rightPadding", "topPadding"]
+ }
+
+ QtQuick.Row {
+ bannedProperties: ["bottomPadding", "leftPadding", "rightPadding", "topPadding",
+ "effectiveLayoutDirection", "layoutDirection"]
+ }
+
+ QtQuick.ListView {
+ bannedProperties: ["cacheBuffer", "highlightRangeMode", "highlightMoveDuration",
+ "highlightResizeDuration", "preferredHighlightBegin", "layoutDirection",
+ "preferredHighlightEnd", "highlightFollowsCurrentItem", "keyNavigationWraps",
+ "snapMode", "highlightMoveVelocity", "highlightResizeVelocity"]
+ }
+
+ QtQuick.Animation {
+ bannedProperties: ["paused"]
+ }
+
+ //Quick Controls2 Items and properties:
+
+ QtQuick.Controls.Control {
+ bannedProperties: ["focusPolicy", "hoverEnabled", "wheelEnabled"]
+ }
+
+ QtQuick.Controls.AbstractButton {
+ bannedProperties: ["display", "autoExclusive", "icon"]
+ }
+
+ QtQuick.Controls.ProgressBar {
+ bannedProperties: ["indeterminate"]
+ }
+
+ QtQuick.Controls.Slider {
+ bannedProperties: ["live", "snapMode", "touchDragThreshold"]
+ }
+
+ //Path and Shapes related:
+
+ QtQuick.Path {
+ bannedProperties: ["scale", "pathElements"]
+ }
+
+ QtQuick.PathArc {
+ bannedProperties: ["relativeX", "relativeY"]
+ }
+
+ QtQuick.PathLine {
+ bannedProperties: ["relativeX", "relativeY"]
+ }
+
+ QtQuick.PathMove {
+ bannedProperties: ["relativeX", "relativeY"]
+ }
+
+ QtQuick.PathQuad {
+ bannedProperties: ["relativeX", "relativeY",
+ "relativeControlX", "relativeControlY"]
+ }
+
+ QtQuick.PathCubic {
+ bannedProperties: ["relativeX", "relativeY",
+ "relativeControl1X", "relativeControl1Y",
+ "relativeControl2X", "relativeControl2Y"]
+ }
+
+ QtQuick.PathElement {
+ //nothing
+ }
+
+ QtQuick.PathSvg {
+ //nothing
+ }
+
+ QtQuick.Shapes.Shape {
+ bannedProperties: ["asynchronous", "containsMode", "data",
+ "renderType", "status", "vendorExtensionsEnabled"]
+ }
+
+ QtQuick.Shapes.ShapePath {
+ bannedProperties: ["dashOffset", "dashPattern",
+ "fillGradient", "strokeStyle"]
+ }
+}
diff --git a/share/qtcreator/qmldesigner/qt4mcu/qul-24.qml b/share/qtcreator/qmldesigner/qt4mcu/qul-24.qml
new file mode 100644
index 00000000000..f78b00b8c65
--- /dev/null
+++ b/share/qtcreator/qmldesigner/qt4mcu/qul-24.qml
@@ -0,0 +1,210 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+VersionData {
+ name: "Qt for MCUs 2.4"
+
+ bannedItems: [
+ "QtQuick.AnimatedImage",
+ "QtQuick.Flow",
+ "QtQuick.FocusScope",
+ "QtQuick.Grid",
+ "QtQuick.GridView",
+ "QtQuick.PathView",
+ "QtQuick.TextEdit",
+ "QtQuick.TextInput",
+ "QtQuick.Controls",
+ "QtQuick.Controls.BusyIndicator",
+ "QtQuick.Controls.ButtonGroup",
+ "QtQuick.Controls.CheckDelegate",
+ "QtQuick.Controls.ComboBox",
+ "QtQuick.Controls.Container",
+ "QtQuick.Controls.DelayButton",
+ "QtQuick.Controls.Frame",
+ "QtQuick.Controls.GroupBox",
+ "QtQuick.Controls.ItemDelegate",
+ "QtQuick.Controls.Label",
+ "QtQuick.Controls.Page",
+ "QtQuick.Controls.PageIndicator",
+ "QtQuick.Controls.Pane",
+ "QtQuick.Controls.RadioDelegate",
+ "QtQuick.Controls.RangeSlider",
+ "QtQuick.Controls.RoundButton",
+ "QtQuick.Controls.ScrollView",
+ "QtQuick.Controls.SpinBox",
+ "QtQuick.Controls.StackView",
+ "QtQuick.Controls.SwipeDelegate",
+ "QtQuick.Controls.SwitchDelegate",
+ "QtQuick.Controls.TabBar",
+ "QtQuick.Controls.TabButton",
+ "QtQuick.Controls.TextArea",
+ "QtQuick.Controls.TextField",
+ "QtQuick.Controls.ToolBar",
+ "QtQuick.Controls.ToolButton",
+ "QtQuick.Controls.ToolSeparator",
+ "QtQuick.Controls.Tumbler",
+ "QtQuick.Shapes.ConicalGradient",
+ "QtQuick.Shapes.LinearGradient",
+ "QtQuick.Shapes.RadialGradient",
+ "QtQuick.Shapes.ShapeGradient"
+ ]
+
+ allowedImports: [
+ "QtQuick",
+ "QtQuick.Controls",
+ "QtQuick.Shapes",
+ "QtQuick.Timeline",
+ "QtQuickUltralite.Extras",
+ "QtQuickUltralite.Layers"
+ ]
+
+ bannedImports: ["FlowView"]
+
+ //ComplexProperty is not a type, it's just a way to handle bigger props
+ ComplexProperty {
+ prefix: "font"
+ bannedProperties: ["wordSpacing", "letterSpacing", "hintingPreference",
+ "kerning", "preferShaping", "capitalization",
+ "strikeout", "underline", "styleName"]
+ }
+
+ QtQml.Timer {
+ bannedProperties: ["triggeredOnStart"]
+ }
+
+ QtQuick.Item {
+ bannedProperties: ["layer", "opacity", "smooth", "antialiasing",
+ "baselineOffset", "focus", "activeFocusOnTab",
+ "rotation", "scale", "transformOrigin"]
+ }
+
+ QtQuick.Rectangle {
+ bannedProperties: ["gradient", "border"]
+ }
+
+ QtQuick.Flickable {
+ bannedProperties: ["boundsMovement", "flickDeceleration",
+ "leftMargin", "rightMargin", "bottomMargin", "topMargin",
+ "originX", "originY", "pixelAligned", "pressDelay", "synchronousDrag"]
+ }
+
+ QtQuick.MouseArea {
+ bannedProperties: ["propagateComposedEvents", "preventStealing", "cursorShape",
+ "scrollGestureEnabled", "drag", "acceptedButtons", "hoverEnabled"]
+ }
+
+ QtQuick.Image {
+ allowChildren: false
+ allowedProperties: ["rotation", "scale", "transformOrigin"]
+ bannedProperties: ["mirror", "mipmap", "cache", "autoTransform", "asynchronous",
+ "sourceSize", "smooth"]
+ }
+
+ QtQuick.BorderImage {
+ bannedProperties: ["asynchronous", "cache", "currentFrame", "frameCount",
+ "horizontalTileMode", "mirror", "progress", "smooth", "sourceSize",
+ "status", "verticalTileMode"]
+ }
+
+ QtQuick.Text {
+ allowChildren: false
+ allowedProperties: ["rotation", "scale", "transformOrigin"]
+ bannedProperties: ["lineHeight", "lineHeightMode", "style",
+ "styleColor", "minimumPointSize", "minimumPixelSize",
+ "fontSizeMode", "renderType", "renderTypeQuality", "textFormat", "maximumLineCount"]
+ }
+
+ QtQuick.Loader {
+ bannedProperties: ["asynchronous", "progress", "status"]
+ }
+
+ //Padding is not an actual item, but rather set of properties in Text
+ Padding {
+ bannedProperties: ["bottomPadding", "topPadding", "leftPadding", "rightPadding"]
+ }
+
+ QtQuick.Column {
+ bannedProperties: ["bottomPadding", "leftPadding", "rightPadding", "topPadding"]
+ }
+
+ QtQuick.Row {
+ bannedProperties: ["bottomPadding", "leftPadding", "rightPadding", "topPadding",
+ "effectiveLayoutDirection", "layoutDirection"]
+ }
+
+ QtQuick.ListView {
+ bannedProperties: ["cacheBuffer", "highlightRangeMode", "highlightMoveDuration",
+ "highlightResizeDuration", "preferredHighlightBegin", "layoutDirection",
+ "preferredHighlightEnd", "highlightFollowsCurrentItem", "keyNavigationWraps",
+ "snapMode", "highlightMoveVelocity", "highlightResizeVelocity"]
+ }
+
+ QtQuick.Animation {
+ bannedProperties: ["paused"]
+ }
+
+ //Quick Controls2 Items and properties:
+
+ QtQuick.Controls.Control {
+ bannedProperties: ["focusPolicy", "hoverEnabled", "wheelEnabled"]
+ }
+
+ QtQuick.Controls.AbstractButton {
+ bannedProperties: ["display", "autoExclusive", "icon"]
+ }
+
+ QtQuick.Controls.ProgressBar {
+ bannedProperties: ["indeterminate"]
+ }
+
+ QtQuick.Controls.Slider {
+ bannedProperties: ["live", "snapMode", "touchDragThreshold"]
+ }
+
+ //Path and Shapes related:
+
+ QtQuick.Path {
+ bannedProperties: ["scale", "pathElements"]
+ }
+
+ QtQuick.PathArc {
+ bannedProperties: ["relativeX", "relativeY"]
+ }
+
+ QtQuick.PathLine {
+ bannedProperties: ["relativeX", "relativeY"]
+ }
+
+ QtQuick.PathMove {
+ bannedProperties: ["relativeX", "relativeY"]
+ }
+
+ QtQuick.PathQuad {
+ bannedProperties: ["relativeX", "relativeY",
+ "relativeControlX", "relativeControlY"]
+ }
+
+ QtQuick.PathCubic {
+ bannedProperties: ["relativeX", "relativeY",
+ "relativeControl1X", "relativeControl1Y",
+ "relativeControl2X", "relativeControl2Y"]
+ }
+
+ QtQuick.PathElement {
+ //nothing
+ }
+
+ QtQuick.PathSvg {
+ //nothing
+ }
+
+ QtQuick.Shapes.Shape {
+ bannedProperties: ["asynchronous", "containsMode", "data",
+ "renderType", "status", "vendorExtensionsEnabled"]
+ }
+
+ QtQuick.Shapes.ShapePath {
+ bannedProperties: ["dashOffset", "dashPattern",
+ "fillGradient", "strokeStyle"]
+ }
+}
diff --git a/share/qtcreator/qmldesigner/statusbar/Main.qml b/share/qtcreator/qmldesigner/statusbar/Main.qml
index db1a125e10f..16b687abc00 100644
--- a/share/qtcreator/qmldesigner/statusbar/Main.qml
+++ b/share/qtcreator/qmldesigner/statusbar/Main.qml
@@ -6,6 +6,7 @@ import QtQuick.Controls
import StudioControls 1.0 as StudioControls
import StudioTheme 1.0 as StudioTheme
import "../toolbar"
+import HelperWidgets 2.0
import ToolBar 1.0
@@ -35,6 +36,7 @@ Item {
buttonIcon: StudioTheme.Constants.settings_medium
onClicked: backend.triggerProjectSettings()
enabled: backend.isInDesignMode || (backend.isInEditMode && backend.projectOpened)
+ tooltip: qsTr("Set runtime configuration for the project.")
}
Text {
@@ -45,6 +47,10 @@ Item {
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
+ ToolTipArea {
+ anchors.fill: parent
+ tooltip: qsTr("Choose a predefined kit for the runtime configuration of the project.")
+ }
}
StudioControls.TopLevelComboBox {
@@ -67,6 +73,10 @@ Item {
horizontalAlignment: Text.AlignRight
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
+ ToolTipArea {
+ anchors.fill: parent
+ tooltip: qsTr("Choose a style for the Qt Quick Controls of the project.")
+ }
}
StudioControls.TopLevelComboBox {
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/app_mcu.qmlproject b/share/qtcreator/qmldesigner/studio_templates/projects/app_mcu.qmlproject
index bbf848151fe..55204175faa 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/app_mcu.qmlproject
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/app_mcu.qmlproject
@@ -52,6 +52,10 @@ Project {
}
qtForMCUs: true
+ qt6Project: true
+
+ qdsVersion: "4.1"
+ quickVersion: "6.5"
/* List of plugin directories passed to QML runtime */
importPaths: [ "imports" ]
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json
index 84690258ea3..3e26a5f0f20 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-3d/wizard.json
@@ -238,7 +238,7 @@
"type": "ComboBox",
"data":
{
- "index": 2,
+ "index": 4,
"items":
[
{
@@ -272,6 +272,14 @@
'TargetQuickVersion': '6.4',
'TargetQuick3DVersion': '6.4'
})"
+ },
+ {
+ "trKey": "Qt 6.5",
+ "value":
+ "({
+ 'TargetQuickVersion': '6.5',
+ 'TargetQuick3DVersion': '6.5'
+ })"
}
]
}
@@ -304,6 +312,10 @@
"target": "%{ProjectDirectory}/qmlcomponents"
},
{
+ "source": "../common/insight.tpl",
+ "target": "%{ProjectDirectory}/insight"
+ },
+ {
"source": "../common/main.qml",
"target": "%{ProjectDirectory}/main.qml"
},
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Constants.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Constants.qml.tpl
index 524cbd0905c..ad50e39e9ac 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Constants.qml.tpl
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Constants.qml.tpl
@@ -1,5 +1,5 @@
pragma Singleton
-import QtQuick 2.15
+import QtQuick 6.5
QtObject {
readonly property int width: %{ScreenWidth}
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Screen01.ui.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Screen01.ui.qml.tpl
index 600031122e8..4a70ce692b6 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Screen01.ui.qml.tpl
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/Screen01.ui.qml.tpl
@@ -5,7 +5,7 @@ this file manually, you might introduce QML code that is not supported by Qt Des
Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files.
*/
-import QtQuick 2.15
+import QtQuick 6.5
import Constants 1.0
Rectangle {
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/main.qml.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/main.qml.tpl
index 4ea0b24a38c..e25113c67f9 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/main.qml.tpl
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/application-mcu/main.qml.tpl
@@ -1,4 +1,4 @@
-import QtQuick 2.15
+import QtQuick 6.5
import Constants 1.0
Item {
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json
index 85f248f957b..ea5f9ef671b 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/application/wizard.json
@@ -238,7 +238,7 @@
"type": "ComboBox",
"data":
{
- "index": 1,
+ "index": 4,
"items":
[
{
@@ -268,6 +268,13 @@
"({
'TargetQuickVersion': '6.4'
})"
+ },
+ {
+ "trKey": "Qt 6.5",
+ "value":
+ "({
+ 'TargetQuickVersion': '6.5'
+ })"
}
]
}
@@ -300,6 +307,10 @@
"target": "%{ProjectDirectory}/qmlcomponents"
},
{
+ "source": "../common/insight.tpl",
+ "target": "%{ProjectDirectory}/insight"
+ },
+ {
"source": "../common/main.qml",
"target": "%{ProjectDirectory}/main.qml"
},
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl
index 18aec1a93e2..ef31652b0eb 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/CMakeLists.main.txt.tpl
@@ -1,5 +1,6 @@
cmake_minimum_required(VERSION 3.21.1)
+option(LINK_INSIGHT "Link Qt Insight Tracker library" ON)
option(BUILD_QDS_COMPONENTS "Build design studio components" ON)
project(%{ProjectName}App LANGUAGES CXX)
@@ -33,6 +34,10 @@ endif()
include(${CMAKE_CURRENT_SOURCE_DIR}/qmlmodules)
+if (LINK_INSIGHT)
+ include(${CMAKE_CURRENT_SOURCE_DIR}/insight)
+endif ()
+
install(TARGETS %{ProjectName}App
BUNDLE DESTINATION .
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl
index d598f361c10..9cfbab9228b 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/app.qmlproject.tpl
@@ -60,6 +60,10 @@ Project {
}
Files {
+ filter: "*.qsb"
+ }
+
+ Files {
filter: "*.mesh"
directory: "asset_imports"
}
@@ -101,7 +105,7 @@ Project {
/* Required for deployment */
targetDirectory: "/opt/%{ProjectName}"
- qdsVersion: "4.0"
+ qdsVersion: "4.1"
quickVersion: "%{QtQuickVersion}"
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/insight.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/insight.tpl
new file mode 100644
index 00000000000..8245e31f0d9
--- /dev/null
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/insight.tpl
@@ -0,0 +1,19 @@
+### This file is automatically generated by Qt Design Studio.
+### Do not change
+
+if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/qtinsight.conf)
+ if (QT_VERSION GREATER_EQUAL 6.5.0)
+ find_package(Qt6 REQUIRED COMPONENTS InsightTracker)
+
+ qt_add_resources(${CMAKE_PROJECT_NAME} "configuration"
+ PREFIX "/"
+ FILES
+ qtinsight.conf
+ )
+ target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE
+ Qt6::InsightTracker
+ )
+ else()
+ message(WARNING "You need Qt 6.5.0 or newer to build the application.")
+ endif()
+endif()
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/common/qmlcomponents.tpl b/share/qtcreator/qmldesigner/studio_templates/projects/common/qmlcomponents.tpl
index 50f3db973cb..5e2d5923b1e 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/common/qmlcomponents.tpl
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/common/qmlcomponents.tpl
@@ -8,7 +8,7 @@ set(QT_QML_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/qml")
include(FetchContent)
FetchContent_Declare(
ds
- GIT_TAG qds-4.0
+ GIT_TAG qds-4.1
GIT_REPOSITORY https://code.qt.io/qt-labs/qtquickdesigner-components.git
)
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json
index 92cbd476cdf..58fb3f30ef7 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/desktop-launcher/wizard.json
@@ -236,7 +236,7 @@
"type": "ComboBox",
"data":
{
- "index": 1,
+ "index": 4,
"items":
[
{
@@ -266,6 +266,13 @@
"({
'TargetQuickVersion': '6.4'
})"
+ },
+ {
+ "trKey": "Qt 6.5",
+ "value":
+ "({
+ 'TargetQuickVersion': '6.5'
+ })"
}
]
}
@@ -298,6 +305,10 @@
"target": "%{ProjectDirectory}/qmlcomponents"
},
{
+ "source": "../common/insight.tpl",
+ "target": "%{ProjectDirectory}/insight"
+ },
+ {
"source": "../common/main.qml",
"target": "%{ProjectDirectory}/main.qml"
},
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json
index 9b3fe1be77a..d79059a6a5a 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-scroll/wizard.json
@@ -195,7 +195,7 @@
"type": "ComboBox",
"data":
{
- "index": 1,
+ "index": 4,
"items":
[
{
@@ -225,6 +225,13 @@
"({
'TargetQuickVersion': '6.4'
})"
+ },
+ {
+ "trKey": "Qt 6.5",
+ "value":
+ "({
+ 'TargetQuickVersion': '6.5'
+ })"
}
]
}
@@ -257,6 +264,10 @@
"target": "%{ProjectDirectory}/qmlcomponents"
},
{
+ "source": "../common/insight.tpl",
+ "target": "%{ProjectDirectory}/insight"
+ },
+ {
"source": "../common/main.qml",
"target": "%{ProjectDirectory}/main.qml"
},
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json
index a10fe57da6c..cd837cf5688 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-stack/wizard.json
@@ -193,7 +193,7 @@
"type": "ComboBox",
"data":
{
- "index": 1,
+ "index": 4,
"items":
[
{
@@ -223,6 +223,13 @@
"({
'TargetQuickVersion': '6.4'
})"
+ },
+ {
+ "trKey": "Qt 6.5",
+ "value":
+ "({
+ 'TargetQuickVersion': '6.5'
+ })"
}
]
}
@@ -254,6 +261,10 @@
"target": "%{ProjectDirectory}/qmlcomponents"
},
{
+ "source": "../common/insight.tpl",
+ "target": "%{ProjectDirectory}/insight"
+ },
+ {
"source": "../common/main.qml",
"target": "%{ProjectDirectory}/main.qml"
},
diff --git a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json
index 77c31a7d3bf..abef03752e2 100644
--- a/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json
+++ b/share/qtcreator/qmldesigner/studio_templates/projects/mobile-swipe/wizard.json
@@ -193,7 +193,7 @@
"type": "ComboBox",
"data":
{
- "index": 1,
+ "index": 4,
"items":
[
{
@@ -223,6 +223,13 @@
"({
'TargetQuickVersion': '6.4'
})"
+ },
+ {
+ "trKey": "Qt 6.5",
+ "value":
+ "({
+ 'TargetQuickVersion': '6.5'
+ })"
}
]
}
@@ -254,6 +261,10 @@
"target": "%{ProjectDirectory}/qmlcomponents"
},
{
+ "source": "../common/insight.tpl",
+ "target": "%{ProjectDirectory}/insight"
+ },
+ {
"source": "../common/main.qml",
"target": "%{ProjectDirectory}/main.qml"
},
diff --git a/share/qtcreator/qmldesigner/toolbar/CrumbleBread.qml b/share/qtcreator/qmldesigner/toolbar/CrumbleBread.qml
index 538c1356429..19142de882e 100644
--- a/share/qtcreator/qmldesigner/toolbar/CrumbleBread.qml
+++ b/share/qtcreator/qmldesigner/toolbar/CrumbleBread.qml
@@ -120,9 +120,18 @@ Item {
font.pixelSize: 12
font.family: "SF Pro"
- ToolTip.text: root.tooltip
- ToolTip.visible: mouseArea.containsMouse
- ToolTip.delay: 1000
+ ToolTip {
+ id: toolTipBox
+ text: root.tooltip
+ visible: mouseArea.containsMouse
+ delay: 1000
+
+ MouseArea {
+ anchors.fill: parent
+ anchors.margins: -toolTipBox.padding
+ onClicked: (mouseEvent) => mouseArea.clicked(mouseEvent)
+ }
+ }
}
MouseArea {
diff --git a/share/qtcreator/qmldesigner/toolbar/Main.qml b/share/qtcreator/qmldesigner/toolbar/Main.qml
index 3daf50c14b8..ebed433e724 100644
--- a/share/qtcreator/qmldesigner/toolbar/Main.qml
+++ b/share/qtcreator/qmldesigner/toolbar/Main.qml
@@ -237,28 +237,32 @@ Rectangle {
anchors.verticalCenter: parent.verticalCenter
anchors.right: annotations.left
anchors.rightMargin: 10
- model: backend.workspaces
+ visible: !root.flyoutEnabled
+ model: WorkspaceModel {
+ id: workspaceModel
+ }
+ textRole: "displayName"
+ valueRole: "fileName"
suffix: qsTr(" Workspace")
- property int currentWorkspaceIndex: workspaces.find(backend.currentWorkspace)
- onCurrentWorkspaceIndexChanged: workspaces.currentIndex = workspaces.currentWorkspaceIndex
- visible: !root.flyoutEnabled
+ property int currentWorkspaceIndex: workspaces.indexOfValue(backend.currentWorkspace)
- onActivated: backend.setCurrentWorkspace(workspaces.currentText)
+ onCurrentWorkspaceIndexChanged: workspaces.currentIndex = workspaces.currentWorkspaceIndex
+ onActivated: backend.setCurrentWorkspace(workspaces.currentValue)
}
ToolbarButton {
id: annotations
visible: false
+ enabled: backend.isInDesignMode
anchors.verticalCenter: parent.verticalCenter
anchors.right: shareButton.left
anchors.rightMargin: 10
+ width: 0
tooltip: qsTr("Edit Annotations")
buttonIcon: StudioTheme.Constants.annotations_large
- //visible: !root.flyoutEnabled
onClicked: backend.editGlobalAnnoation()
- width: 0
}
ToolbarButton {
@@ -391,10 +395,12 @@ Rectangle {
style: StudioTheme.Values.statusbarControlStyle
width: row.width
maximumPopupHeight: 400
- model: backend.workspaces
- currentIndex: workspacesFlyout.find(backend.currentWorkspace)
+ model: workspaceModel
+ textRole: "displayName"
+ valueRole: "fileName"
+ currentIndex: workspacesFlyout.indexOfValue(backend.currentWorkspace)
- onCompressedActivated: backend.setCurrentWorkspace(workspacesFlyout.currentText)
+ onCompressedActivated: backend.setCurrentWorkspace(workspacesFlyout.currentValue)
}
}
}
diff --git a/share/qtcreator/qmldesigner/workspacePresets/Advanced-3D.wrk b/share/qtcreator/qmldesigner/workspacePresets/Advanced-3D.wrk
index 2336c94ffae..24eace89b8c 100644
--- a/share/qtcreator/qmldesigner/workspacePresets/Advanced-3D.wrk
+++ b/share/qtcreator/qmldesigner/workspacePresets/Advanced-3D.wrk
@@ -1 +1,74 @@
-<?xml version="1.0" encoding="UTF-8"?><QtAdvancedDockingSystem version="1" userVersion="0" containers="1"><container floating="false"><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="3"><splitter orientation="Vertical" count="3"><area tabs="2" current="Navigator"><widget name="Navigator" closed="false"/><widget name="DebugView" closed="true"/></area><area tabs="3" current="ContentLibrary"><widget name="ContentLibrary" closed="false"/><widget name="Components" closed="false"/><widget name="Assets" closed="true"/></area><area tabs="3" current="OpenDocuments"><widget name="Projects" closed="true"/><widget name="FileSystem" closed="true"/><widget name="OpenDocuments" closed="true"/></area><sizes>622 527 0</sizes></splitter><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="3"><splitter orientation="Vertical" count="2"><area tabs="1" current="Editor3D"><widget name="Editor3D" closed="false"/></area><area tabs="1" current="FormEditor"><widget name="FormEditor" closed="false"/></area><sizes>620 529</sizes></splitter><area tabs="1" current="TextEditor"><widget name="TextEditor" closed="true"/></area><splitter orientation="Vertical" count="2"><area tabs="1" current="MaterialBrowser"><widget name="MaterialBrowser" closed="false"/></area><area tabs="3" current="MaterialEditor"><widget name="MaterialEditor" closed="false"/><widget name="TextureEditor" closed="false"/><widget name="Properties" closed="false"/></area><sizes>575 574</sizes></splitter><sizes>1233 0 533</sizes></splitter><splitter orientation="Horizontal" count="2"><area tabs="3" current="Timelines"><widget name="TransitionEditor" closed="true"/><widget name="CurveEditorId" closed="true"/><widget name="Timelines" closed="true"/></area><area tabs="1" current="OutputPane"><widget name="OutputPane" closed="true"/></area><sizes>0 0</sizes></splitter><sizes>1150 0</sizes></splitter><area tabs="1" current="ConnectionView"><widget name="ConnectionView" closed="true"/></area><sizes>536 1767 0</sizes></splitter><area tabs="1" current="StatesEditor"><widget name="StatesEditor" closed="true"/></area><sizes>1150 0</sizes></splitter></container></QtAdvancedDockingSystem>
+<?xml version="1.0" encoding="UTF-8"?>
+<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="3D Advanced">
+ <container floating="false">
+ <splitter orientation="Vertical" count="2">
+ <splitter orientation="Horizontal" count="3">
+ <splitter orientation="Vertical" count="3">
+ <area tabs="2" current="Navigator">
+ <widget name="Navigator" closed="false"/>
+ <widget name="DebugView" closed="true"/>
+ </area>
+ <area tabs="3" current="ContentLibrary">
+ <widget name="ContentLibrary" closed="false"/>
+ <widget name="Components" closed="false"/>
+ <widget name="Assets" closed="true"/>
+ </area>
+ <area tabs="3" current="OpenDocuments">
+ <widget name="Projects" closed="true"/>
+ <widget name="FileSystem" closed="true"/>
+ <widget name="OpenDocuments" closed="true"/>
+ </area>
+ <sizes>622 527 0</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <splitter orientation="Horizontal" count="3">
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="Editor3D">
+ <widget name="Editor3D" closed="false"/>
+ </area>
+ <area tabs="1" current="FormEditor">
+ <widget name="FormEditor" closed="false"/>
+ </area>
+ <sizes>620 529</sizes>
+ </splitter>
+ <area tabs="1" current="TextEditor">
+ <widget name="TextEditor" closed="true"/>
+ </area>
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="MaterialBrowser">
+ <widget name="MaterialBrowser" closed="false"/>
+ </area>
+ <area tabs="3" current="MaterialEditor">
+ <widget name="MaterialEditor" closed="false"/>
+ <widget name="TextureEditor" closed="false"/>
+ <widget name="Properties" closed="false"/>
+ </area>
+ <sizes>575 574</sizes>
+ </splitter>
+ <sizes>1233 0 533</sizes>
+ </splitter>
+ <splitter orientation="Horizontal" count="2">
+ <area tabs="3" current="Timelines">
+ <widget name="TransitionEditor" closed="true"/>
+ <widget name="CurveEditorId" closed="true"/>
+ <widget name="Timelines" closed="true"/>
+ </area>
+ <area tabs="1" current="OutputPane">
+ <widget name="OutputPane" closed="true"/>
+ </area>
+ <sizes>0 0</sizes>
+ </splitter>
+ <sizes>1150 0</sizes>
+ </splitter>
+ <area tabs="1" current="ConnectionView">
+ <widget name="ConnectionView" closed="true"/>
+ </area>
+ <sizes>536 1767 0</sizes>
+ </splitter>
+ <area tabs="1" current="StatesEditor">
+ <widget name="StatesEditor" closed="true"/>
+ </area>
+ <sizes>1150 0</sizes>
+ </splitter>
+ </container>
+</QtAdvancedDockingSystem>
diff --git a/share/qtcreator/qmldesigner/workspacePresets/Animation-2D.wrk b/share/qtcreator/qmldesigner/workspacePresets/Animation-2D.wrk
index e5c5d40bc03..346856dd507 100644
--- a/share/qtcreator/qmldesigner/workspacePresets/Animation-2D.wrk
+++ b/share/qtcreator/qmldesigner/workspacePresets/Animation-2D.wrk
@@ -1 +1,75 @@
-<?xml version="1.0" encoding="UTF-8"?><QtAdvancedDockingSystem version="1" userVersion="0" containers="1"><container floating="false"><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="3"><splitter orientation="Vertical" count="3"><area tabs="2" current="Navigator"><widget name="Navigator" closed="false"/><widget name="Projects" closed="false"/></area><area tabs="2" current="OpenDocuments"><widget name="FileSystem" closed="true"/><widget name="OpenDocuments" closed="true"/></area><area tabs="2" current="Components"><widget name="Components" closed="false"/><widget name="Assets" closed="false"/></area><sizes>346 0 365</sizes></splitter><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="2"><splitter orientation="Vertical" count="2"><area tabs="1" current="FormEditor"><widget name="FormEditor" closed="false"/></area><area tabs="1" current="Editor3D"><widget name="Editor3D" closed="true"/></area><sizes>712 0</sizes></splitter><splitter orientation="Vertical" count="2"><area tabs="1" current="TextEditor"><widget name="TextEditor" closed="true"/></area><area tabs="1" current="OutputPane"><widget name="OutputPane" closed="true"/></area><sizes>0 0</sizes></splitter><sizes>914 0</sizes></splitter><splitter orientation="Horizontal" count="2"><area tabs="1" current=""><widget name="StatesEditor" closed="true"/></area><area tabs="1" current=""><widget name="TransitionEditor" closed="true"/></area><sizes>0 0</sizes></splitter><sizes>712 0</sizes></splitter><splitter orientation="Vertical" count="3"><area tabs="1" current="Properties"><widget name="Properties" closed="false"/></area><area tabs="1" current="TranslationsView"><widget name="TranslationsView" closed="true"/></area><area tabs="1" current="ConnectionView"><widget name="ConnectionView" closed="true"/></area><sizes>712 0 0</sizes></splitter><sizes>310 914 406</sizes></splitter><area tabs="2" current="Timelines"><widget name="Timelines" closed="false"/><widget name="CurveEditorId" closed="false"/></area><sizes>712 255</sizes></splitter></container></QtAdvancedDockingSystem>
+<?xml version="1.0" encoding="UTF-8"?>
+<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="2D Animation">
+ <container floating="false">
+ <splitter orientation="Vertical" count="2">
+ <splitter orientation="Horizontal" count="3">
+ <splitter orientation="Vertical" count="3">
+ <area tabs="2" current="Navigator">
+ <widget name="Navigator" closed="false"/>
+ <widget name="Projects" closed="false"/>
+ </area>
+ <area tabs="2" current="OpenDocuments">
+ <widget name="FileSystem" closed="true"/>
+ <widget name="OpenDocuments" closed="true"/>
+ </area>
+ <area tabs="2" current="Components">
+ <widget name="Components" closed="false"/>
+ <widget name="Assets" closed="false"/>
+ </area>
+ <sizes>346 0 365</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <splitter orientation="Horizontal" count="2">
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="FormEditor">
+ <widget name="FormEditor" closed="false"/>
+ </area>
+ <area tabs="1" current="Editor3D">
+ <widget name="Editor3D" closed="true"/>
+ </area>
+ <sizes>712 0</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="TextEditor">
+ <widget name="TextEditor" closed="true"/>
+ </area>
+ <area tabs="1" current="OutputPane">
+ <widget name="OutputPane" closed="true"/>
+ </area>
+ <sizes>0 0</sizes>
+ </splitter>
+ <sizes>914 0</sizes>
+ </splitter>
+ <splitter orientation="Horizontal" count="2">
+ <area tabs="1" current="">
+ <widget name="StatesEditor" closed="true"/>
+ </area>
+ <area tabs="1" current="">
+ <widget name="TransitionEditor" closed="true"/>
+ </area>
+ <sizes>0 0</sizes>
+ </splitter>
+ <sizes>712 0</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="3">
+ <area tabs="1" current="Properties">
+ <widget name="Properties" closed="false"/>
+ </area>
+ <area tabs="1" current="TranslationsView">
+ <widget name="TranslationsView" closed="true"/>
+ </area>
+ <area tabs="1" current="ConnectionView">
+ <widget name="ConnectionView" closed="true"/>
+ </area>
+ <sizes>712 0 0</sizes>
+ </splitter>
+ <sizes>310 914 406</sizes>
+ </splitter>
+ <area tabs="2" current="Timelines">
+ <widget name="Timelines" closed="false"/>
+ <widget name="CurveEditorId" closed="false"/>
+ </area>
+ <sizes>712 255</sizes>
+ </splitter>
+ </container>
+</QtAdvancedDockingSystem>
diff --git a/share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk b/share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk
index 7282eb1a637..8f1d59119cd 100644
--- a/share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk
+++ b/share/qtcreator/qmldesigner/workspacePresets/Animation-3D.wrk
@@ -1 +1,60 @@
-<?xml version="1.0" encoding="UTF-8"?><QtAdvancedDockingSystem version="1" userVersion="0" containers="1"><container floating="false"><splitter orientation="Horizontal" count="2"><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="3"><area tabs="4" current="Components"><widget name="Components" closed="false"/><widget name="Assets" closed="false"/><widget name="MaterialBrowser" closed="false"/><widget name="ContentLibrary" closed="false"/></area><area tabs="2" current="Editor3D"><widget name="Editor3D" closed="false"/><widget name="FormEditor" closed="false"/></area><area tabs="1" current="TranslationsView"><widget name="TranslationsView" closed="true"/></area><sizes>688 2515 0</sizes></splitter><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="2"><area tabs="3" current="StatesEditor"><widget name="StatesEditor" closed="false"/><widget name="TransitionEditor" closed="false"/><widget name="CurveEditorId" closed="false"/></area><area tabs="1" current="Timelines"><widget name="Timelines" closed="false"/></area><sizes>1604 1599</sizes></splitter><area tabs="3" current="OutputPane"><widget name="OutputPane" closed="false"/><widget name="TextEditor" closed="false"/><widget name="ConnectionView" closed="true"/></area><sizes>544 42</sizes></splitter><sizes>1426 587</sizes></splitter><splitter orientation="Vertical" count="2"><area tabs="4" current="Navigator"><widget name="Navigator" closed="false"/><widget name="Projects" closed="false"/><widget name="FileSystem" closed="false"/><widget name="OpenDocuments" closed="true"/></area><area tabs="3" current="Properties"><widget name="Properties" closed="false"/><widget name="MaterialEditor" closed="false"/><widget name="TextureEditor" closed="false"/></area><sizes>994 1019</sizes></splitter><sizes>3204 635</sizes></splitter></container></QtAdvancedDockingSystem>
+<?xml version="1.0" encoding="UTF-8"?>
+<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="3D Animation">
+ <container floating="false">
+ <splitter orientation="Horizontal" count="2">
+ <splitter orientation="Vertical" count="2">
+ <splitter orientation="Horizontal" count="3">
+ <area tabs="4" current="Components">
+ <widget name="Components" closed="false"/>
+ <widget name="Assets" closed="false"/>
+ <widget name="MaterialBrowser" closed="false"/>
+ <widget name="ContentLibrary" closed="false"/>
+ </area>
+ <area tabs="2" current="Editor3D">
+ <widget name="Editor3D" closed="false"/>
+ <widget name="FormEditor" closed="false"/>
+ </area>
+ <area tabs="1" current="TranslationsView">
+ <widget name="TranslationsView" closed="true"/>
+ </area>
+ <sizes>688 2515 0</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <splitter orientation="Horizontal" count="2">
+ <area tabs="3" current="StatesEditor">
+ <widget name="StatesEditor" closed="false"/>
+ <widget name="TransitionEditor" closed="false"/>
+ <widget name="CurveEditorId" closed="false"/>
+ </area>
+ <area tabs="1" current="Timelines">
+ <widget name="Timelines" closed="false"/>
+ </area>
+ <sizes>1604 1599</sizes>
+ </splitter>
+ <area tabs="3" current="OutputPane">
+ <widget name="OutputPane" closed="false"/>
+ <widget name="TextEditor" closed="false"/>
+ <widget name="ConnectionView" closed="true"/>
+ </area>
+ <sizes>544 42</sizes>
+ </splitter>
+ <sizes>1426 587</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <area tabs="4" current="Navigator">
+ <widget name="Navigator" closed="false"/>
+ <widget name="Projects" closed="false"/>
+ <widget name="FileSystem" closed="false"/>
+ <widget name="OpenDocuments" closed="true"/>
+ </area>
+ <area tabs="3" current="Properties">
+ <widget name="Properties" closed="false"/>
+ <widget name="MaterialEditor" closed="false"/>
+ <widget name="TextureEditor" closed="false"/>
+ </area>
+ <sizes>994 1019</sizes>
+ </splitter>
+ <sizes>3204 635</sizes>
+ </splitter>
+ </container>
+</QtAdvancedDockingSystem>
diff --git a/share/qtcreator/qmldesigner/workspacePresets/Basic.wrk b/share/qtcreator/qmldesigner/workspacePresets/Basic.wrk
index 82556f540a6..b1edb18677f 100644
--- a/share/qtcreator/qmldesigner/workspacePresets/Basic.wrk
+++ b/share/qtcreator/qmldesigner/workspacePresets/Basic.wrk
@@ -1 +1,70 @@
-<?xml version="1.0" encoding="UTF-8"?><QtAdvancedDockingSystem version="1" userVersion="0" containers="1"><container floating="false"><splitter orientation="Horizontal" count="3"><splitter orientation="Vertical" count="3"><area tabs="2" current="Navigator"><widget name="Navigator" closed="false"/><widget name="Projects" closed="false"/></area><area tabs="2" current="FileSystem"><widget name="FileSystem" closed="true"/><widget name="OpenDocuments" closed="true"/></area><area tabs="2" current="Components"><widget name="Components" closed="false"/><widget name="Assets" closed="false"/></area><sizes>481 0 486</sizes></splitter><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="2"><splitter orientation="Vertical" count="2"><area tabs="1" current="FormEditor"><widget name="FormEditor" closed="false"/></area><area tabs="1" current="Editor3D"><widget name="Editor3D" closed="true"/></area><sizes>968 0</sizes></splitter><splitter orientation="Vertical" count="2"><area tabs="1" current="TextEditor"><widget name="TextEditor" closed="true"/></area><area tabs="1" current="OutputPane"><widget name="OutputPane" closed="true"/></area><sizes>968 0</sizes></splitter><sizes>919 0</sizes></splitter><splitter orientation="Horizontal" count="2"><area tabs="2" current="Timelines"><widget name="StatesEditor" closed="true"/><widget name="Timelines" closed="true"/></area><area tabs="2" current="TransitionEditor"><widget name="CurveEditorId" closed="true"/><widget name="TransitionEditor" closed="true"/></area><sizes>0 919</sizes></splitter><sizes>968 0</sizes></splitter><splitter orientation="Vertical" count="3"><area tabs="1" current="Properties"><widget name="Properties" closed="false"/></area><area tabs="1" current="TranslationsView"><widget name="TranslationsView" closed="true"/></area><area tabs="1" current="ConnectionView"><widget name="ConnectionView" closed="true"/></area><sizes>968 0 0</sizes></splitter><sizes>312 919 408</sizes></splitter></container></QtAdvancedDockingSystem>
+<?xml version="1.0" encoding="UTF-8"?>
+<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="Default">
+ <container floating="false">
+ <splitter orientation="Horizontal" count="3">
+ <splitter orientation="Vertical" count="3">
+ <area tabs="2" current="Navigator">
+ <widget name="Navigator" closed="false"/>
+ <widget name="Projects" closed="false"/>
+ </area>
+ <area tabs="2" current="FileSystem">
+ <widget name="FileSystem" closed="true"/>
+ <widget name="OpenDocuments" closed="true"/>
+ </area>
+ <area tabs="2" current="Components">
+ <widget name="Components" closed="false"/>
+ <widget name="Assets" closed="false"/>
+ </area>
+ <sizes>481 0 486</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <splitter orientation="Horizontal" count="2">
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="FormEditor">
+ <widget name="FormEditor" closed="false"/>
+ </area>
+ <area tabs="1" current="Editor3D">
+ <widget name="Editor3D" closed="true"/>
+ </area>
+ <sizes>968 0</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="TextEditor">
+ <widget name="TextEditor" closed="true"/>
+ </area>
+ <area tabs="1" current="OutputPane">
+ <widget name="OutputPane" closed="true"/>
+ </area>
+ <sizes>968 0</sizes>
+ </splitter>
+ <sizes>919 0</sizes>
+ </splitter>
+ <splitter orientation="Horizontal" count="2">
+ <area tabs="2" current="Timelines">
+ <widget name="StatesEditor" closed="true"/>
+ <widget name="Timelines" closed="true"/>
+ </area>
+ <area tabs="2" current="TransitionEditor">
+ <widget name="CurveEditorId" closed="true"/>
+ <widget name="TransitionEditor" closed="true"/>
+ </area>
+ <sizes>0 919</sizes>
+ </splitter>
+ <sizes>968 0</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="3">
+ <area tabs="1" current="Properties">
+ <widget name="Properties" closed="false"/>
+ </area>
+ <area tabs="1" current="TranslationsView">
+ <widget name="TranslationsView" closed="true"/>
+ </area>
+ <area tabs="1" current="ConnectionView">
+ <widget name="ConnectionView" closed="true"/>
+ </area>
+ <sizes>968 0 0</sizes>
+ </splitter>
+ <sizes>312 919 408</sizes>
+ </splitter>
+ </container>
+</QtAdvancedDockingSystem>
diff --git a/share/qtcreator/qmldesigner/workspacePresets/Code.wrk b/share/qtcreator/qmldesigner/workspacePresets/Code.wrk
index c2510cb7dc2..82f734432fc 100644
--- a/share/qtcreator/qmldesigner/workspacePresets/Code.wrk
+++ b/share/qtcreator/qmldesigner/workspacePresets/Code.wrk
@@ -1 +1,70 @@
-<?xml version="1.0" encoding="UTF-8"?><QtAdvancedDockingSystem version="1" userVersion="0" containers="1"><container floating="false"><splitter orientation="Horizontal" count="3"><splitter orientation="Vertical" count="3"><area tabs="2" current="Navigator"><widget name="Navigator" closed="false"/><widget name="Projects" closed="false"/></area><area tabs="2" current="OpenDocuments"><widget name="FileSystem" closed="true"/><widget name="OpenDocuments" closed="true"/></area><area tabs="2" current="Components"><widget name="Components" closed="false"/><widget name="Assets" closed="false"/></area><sizes>541 0 426</sizes></splitter><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="2"><splitter orientation="Vertical" count="2"><area tabs="1" current="FormEditor"><widget name="FormEditor" closed="false"/></area><area tabs="1" current="Editor3D"><widget name="Editor3D" closed="true"/></area><sizes>707 0</sizes></splitter><splitter orientation="Vertical" count="2"><area tabs="1" current="TextEditor"><widget name="TextEditor" closed="false"/></area><area tabs="1" current="OutputPane"><widget name="OutputPane" closed="false"/></area><sizes>488 218</sizes></splitter><sizes>601 448</sizes></splitter><splitter orientation="Horizontal" count="2"><area tabs="2" current="StatesEditor"><widget name="StatesEditor" closed="false"/><widget name="Timelines" closed="true"/></area><area tabs="2" current="TransitionEditor"><widget name="CurveEditorId" closed="true"/><widget name="TransitionEditor" closed="true"/></area><sizes>1050 0</sizes></splitter><sizes>707 260</sizes></splitter><splitter orientation="Vertical" count="3"><area tabs="1" current="Properties"><widget name="Properties" closed="false"/></area><area tabs="1" current="TranslationsView"><widget name="TranslationsView" closed="true"/></area><area tabs="1" current="ConnectionView"><widget name="ConnectionView" closed="false"/></area><sizes>541 0 426</sizes></splitter><sizes>274 1050 315</sizes></splitter></container></QtAdvancedDockingSystem>
+<?xml version="1.0" encoding="UTF-8"?>
+<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="Code">
+ <container floating="false">
+ <splitter orientation="Horizontal" count="3">
+ <splitter orientation="Vertical" count="3">
+ <area tabs="2" current="Navigator">
+ <widget name="Navigator" closed="false"/>
+ <widget name="Projects" closed="false"/>
+ </area>
+ <area tabs="2" current="OpenDocuments">
+ <widget name="FileSystem" closed="true"/>
+ <widget name="OpenDocuments" closed="true"/>
+ </area>
+ <area tabs="2" current="Components">
+ <widget name="Components" closed="false"/>
+ <widget name="Assets" closed="false"/>
+ </area>
+ <sizes>541 0 426</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <splitter orientation="Horizontal" count="2">
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="FormEditor">
+ <widget name="FormEditor" closed="false"/>
+ </area>
+ <area tabs="1" current="Editor3D">
+ <widget name="Editor3D" closed="true"/>
+ </area>
+ <sizes>707 0</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="TextEditor">
+ <widget name="TextEditor" closed="false"/>
+ </area>
+ <area tabs="1" current="OutputPane">
+ <widget name="OutputPane" closed="false"/>
+ </area>
+ <sizes>488 218</sizes>
+ </splitter>
+ <sizes>601 448</sizes>
+ </splitter>
+ <splitter orientation="Horizontal" count="2">
+ <area tabs="2" current="StatesEditor">
+ <widget name="StatesEditor" closed="false"/>
+ <widget name="Timelines" closed="true"/>
+ </area>
+ <area tabs="2" current="TransitionEditor">
+ <widget name="CurveEditorId" closed="true"/>
+ <widget name="TransitionEditor" closed="true"/>
+ </area>
+ <sizes>1050 0</sizes>
+ </splitter>
+ <sizes>707 260</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="3">
+ <area tabs="1" current="Properties">
+ <widget name="Properties" closed="false"/>
+ </area>
+ <area tabs="1" current="TranslationsView">
+ <widget name="TranslationsView" closed="true"/>
+ </area>
+ <area tabs="1" current="ConnectionView">
+ <widget name="ConnectionView" closed="false"/>
+ </area>
+ <sizes>541 0 426</sizes>
+ </splitter>
+ <sizes>274 1050 315</sizes>
+ </splitter>
+ </container>
+</QtAdvancedDockingSystem>
diff --git a/share/qtcreator/qmldesigner/workspacePresets/Essentials-3D.wrk b/share/qtcreator/qmldesigner/workspacePresets/Essentials-3D.wrk
index 4ed1c599c3c..74215ffd456 100644
--- a/share/qtcreator/qmldesigner/workspacePresets/Essentials-3D.wrk
+++ b/share/qtcreator/qmldesigner/workspacePresets/Essentials-3D.wrk
@@ -1 +1,62 @@
-<?xml version="1.0" encoding="UTF-8"?><QtAdvancedDockingSystem version="1" userVersion="0" containers="1"><container floating="false"><splitter orientation="Horizontal" count="3"><splitter orientation="Vertical" count="3"><area tabs="2" current="Navigator"><widget name="Navigator" closed="false"/><widget name="DebugView" closed="false"/></area><area tabs="2" current="Assets"><widget name="Assets" closed="false"/><widget name="Components" closed="false"/></area><area tabs="3" current="Projects"><widget name="Projects" closed="false"/><widget name="FileSystem" closed="false"/><widget name="OpenDocuments" closed="false"/></area><sizes>355 428 404</sizes></splitter><splitter orientation="Vertical" count="4"><splitter orientation="Horizontal" count="2"><area tabs="2" current="FormEditor"><widget name="FormEditor" closed="false"/><widget name="TextEditor" closed="false"/></area><area tabs="1" current="MaterialEditor"><widget name="MaterialEditor" closed="false"/></area><sizes>678 678</sizes></splitter><splitter orientation="Horizontal" count="2"><area tabs="1" current="Editor3D"><widget name="Editor3D" closed="false"/></area><area tabs="1" current="MaterialBrowser"><widget name="MaterialBrowser" closed="false"/></area><sizes>678 678</sizes></splitter><area tabs="2" current="Timelines"><widget name="StatesEditor" closed="true"/><widget name="Timelines" closed="true"/></area><area tabs="1" current="OutputPane"><widget name="OutputPane" closed="true"/></area><sizes>641 547 0 0</sizes></splitter><splitter orientation="Vertical" count="2"><area tabs="1" current="Properties"><widget name="Properties" closed="false"/></area><area tabs="1" current="ConnectionView"><widget name="ConnectionView" closed="false"/></area><sizes>831 357</sizes></splitter><sizes>453 1357 453</sizes></splitter></container></QtAdvancedDockingSystem>
+<?xml version="1.0" encoding="UTF-8"?>
+<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="3D Essentials">
+ <container floating="false">
+ <splitter orientation="Horizontal" count="3">
+ <splitter orientation="Vertical" count="3">
+ <area tabs="2" current="Navigator">
+ <widget name="Navigator" closed="false"/>
+ <widget name="DebugView" closed="false"/>
+ </area>
+ <area tabs="2" current="Assets">
+ <widget name="Assets" closed="false"/>
+ <widget name="Components" closed="false"/>
+ </area>
+ <area tabs="3" current="Projects">
+ <widget name="Projects" closed="false"/>
+ <widget name="FileSystem" closed="false"/>
+ <widget name="OpenDocuments" closed="false"/>
+ </area>
+ <sizes>355 428 404</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="4">
+ <splitter orientation="Horizontal" count="2">
+ <area tabs="2" current="FormEditor">
+ <widget name="FormEditor" closed="false"/>
+ <widget name="TextEditor" closed="false"/>
+ </area>
+ <area tabs="1" current="MaterialEditor">
+ <widget name="MaterialEditor" closed="false"/>
+ </area>
+ <sizes>678 678</sizes>
+ </splitter>
+ <splitter orientation="Horizontal" count="2">
+ <area tabs="1" current="Editor3D">
+ <widget name="Editor3D" closed="false"/>
+ </area>
+ <area tabs="1" current="MaterialBrowser">
+ <widget name="MaterialBrowser" closed="false"/>
+ </area>
+ <sizes>678 678</sizes>
+ </splitter>
+ <area tabs="2" current="Timelines">
+ <widget name="StatesEditor" closed="true"/>
+ <widget name="Timelines" closed="true"/>
+ </area>
+ <area tabs="1" current="OutputPane">
+ <widget name="OutputPane" closed="true"/>
+ </area>
+ <sizes>641 547 0 0</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="Properties">
+ <widget name="Properties" closed="false"/>
+ </area>
+ <area tabs="1" current="ConnectionView">
+ <widget name="ConnectionView" closed="false"/>
+ </area>
+ <sizes>831 357</sizes>
+ </splitter>
+ <sizes>453 1357 453</sizes>
+ </splitter>
+ </container>
+</QtAdvancedDockingSystem>
diff --git a/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk b/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk
index 2bdbc74f22c..e11f39ec940 100644
--- a/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk
+++ b/share/qtcreator/qmldesigner/workspacePresets/Essentials.wrk
@@ -1,47 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
-<QtAdvancedDockingSystem version="1" containers="1">
- <container floating="false">
- <splitter orientation="Horizontal" count="3">
- <splitter orientation="Vertical" count="3">
- <area tabs="3" current="Components">
- <widget name="Components" closed="false"/>
- <widget name="Assets" closed="false"/>
- <widget name="DebugView" closed="false"/>
- </area>
- <area tabs="3" current="Projects">
- <widget name="Projects" closed="false"/>
- <widget name="FileSystem" closed="false"/>
- <widget name="OpenDocuments" closed="false"/>
- </area>
- <area tabs="1" current="Navigator">
- <widget name="Navigator" closed="false"/>
- </area>
- <sizes>6000 1500 2500</sizes>
- </splitter>
- <splitter orientation="Vertical" count="3">
- <area tabs="2" current="FormEditor">
- <widget name="FormEditor" closed="false"/>
- <widget name="TextEditor" closed="false"/>
- </area>
- <area tabs="2" current="StatesEditor">
- <widget name="StatesEditor" closed="false"/>
- <widget name="Timelines" closed="false"/>
- </area>
- <area tabs="1" current="OutputPane">
- <widget name="OutputPane" closed="true"/>
- </area>
- <sizes>7000 1500 1500</sizes>
- </splitter>
- <splitter orientation="Vertical" count="2">
- <area tabs="1" current="Properties">
- <widget name="Properties" closed="false"/>
- </area>
- <area tabs="1" current="ConnectionView">
- <widget name="ConnectionView" closed="false"/>
- </area>
- <sizes>7000 3000</sizes>
- </splitter>
- <sizes>2000 6000 2000</sizes>
- </splitter>
- </container>
+<QtAdvancedDockingSystem version="1" containers="1" displayName="Essentials">
+ <container floating="false">
+ <splitter orientation="Horizontal" count="3">
+ <splitter orientation="Vertical" count="3">
+ <area tabs="3" current="Components">
+ <widget name="Components" closed="false"/>
+ <widget name="Assets" closed="false"/>
+ <widget name="DebugView" closed="false"/>
+ </area>
+ <area tabs="3" current="Projects">
+ <widget name="Projects" closed="false"/>
+ <widget name="FileSystem" closed="false"/>
+ <widget name="OpenDocuments" closed="false"/>
+ </area>
+ <area tabs="1" current="Navigator">
+ <widget name="Navigator" closed="false"/>
+ </area>
+ <sizes>6000 1500 2500</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="3">
+ <area tabs="2" current="FormEditor">
+ <widget name="FormEditor" closed="false"/>
+ <widget name="TextEditor" closed="false"/>
+ </area>
+ <area tabs="2" current="StatesEditor">
+ <widget name="StatesEditor" closed="false"/>
+ <widget name="Timelines" closed="false"/>
+ </area>
+ <area tabs="1" current="OutputPane">
+ <widget name="OutputPane" closed="true"/>
+ </area>
+ <sizes>7000 1500 1500</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="Properties">
+ <widget name="Properties" closed="false"/>
+ </area>
+ <area tabs="1" current="ConnectionView">
+ <widget name="ConnectionView" closed="false"/>
+ </area>
+ <sizes>7000 3000</sizes>
+ </splitter>
+ <sizes>2000 6000 2000</sizes>
+ </splitter>
+ </container>
</QtAdvancedDockingSystem>
diff --git a/share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk b/share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk
index e7ac0763b17..5e973366629 100644
--- a/share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk
+++ b/share/qtcreator/qmldesigner/workspacePresets/UX-Design.wrk
@@ -1 +1,75 @@
-<?xml version="1.0" encoding="UTF-8"?><QtAdvancedDockingSystem version="1" userVersion="0" containers="1"><container floating="false"><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="3"><splitter orientation="Vertical" count="3"><area tabs="2" current="Navigator"><widget name="Navigator" closed="false"/><widget name="Projects" closed="false"/></area><area tabs="2" current="OpenDocuments"><widget name="FileSystem" closed="true"/><widget name="OpenDocuments" closed="true"/></area><area tabs="2" current="Components"><widget name="Components" closed="false"/><widget name="Assets" closed="false"/></area><sizes>439 0 433</sizes></splitter><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="2"><splitter orientation="Vertical" count="2"><area tabs="1" current="FormEditor"><widget name="FormEditor" closed="false"/></area><area tabs="1" current="Editor3D"><widget name="Editor3D" closed="true"/></area><sizes>873 0</sizes></splitter><splitter orientation="Vertical" count="2"><area tabs="1" current="TextEditor"><widget name="TextEditor" closed="true"/></area><area tabs="1" current="OutputPane"><widget name="OutputPane" closed="true"/></area><sizes>0 0</sizes></splitter><sizes>1291 0</sizes></splitter><splitter orientation="Horizontal" count="2"><area tabs="1" current=""><widget name="Timelines" closed="true"/></area><area tabs="2" current="TransitionEditor"><widget name="CurveEditorId" closed="true"/><widget name="TransitionEditor" closed="true"/></area><sizes>1291 0</sizes></splitter><sizes>873 0</sizes></splitter><splitter orientation="Vertical" count="3"><area tabs="1" current="Properties"><widget name="Properties" closed="false"/></area><area tabs="1" current="TranslationsView"><widget name="TranslationsView" closed="true"/></area><area tabs="1" current="ConnectionView"><widget name="ConnectionView" closed="false"/></area><sizes>637 0 235</sizes></splitter><sizes>438 1291 573</sizes></splitter><area tabs="1" current="StatesEditor"><widget name="StatesEditor" closed="false"/></area><sizes>873 276</sizes></splitter></container></QtAdvancedDockingSystem>
+<?xml version="1.0" encoding="UTF-8"?>
+<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="Design">
+ <container floating="false">
+ <splitter orientation="Vertical" count="2">
+ <splitter orientation="Horizontal" count="3">
+ <splitter orientation="Vertical" count="3">
+ <area tabs="2" current="Navigator">
+ <widget name="Navigator" closed="false"/>
+ <widget name="Projects" closed="false"/>
+ </area>
+ <area tabs="2" current="OpenDocuments">
+ <widget name="FileSystem" closed="true"/>
+ <widget name="OpenDocuments" closed="true"/>
+ </area>
+ <area tabs="2" current="Components">
+ <widget name="Components" closed="false"/>
+ <widget name="Assets" closed="false"/>
+ </area>
+ <sizes>439 0 433</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <splitter orientation="Horizontal" count="2">
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="FormEditor">
+ <widget name="FormEditor" closed="false"/>
+ </area>
+ <area tabs="1" current="Editor3D">
+ <widget name="Editor3D" closed="true"/>
+ </area>
+ <sizes>873 0</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="TextEditor">
+ <widget name="TextEditor" closed="true"/>
+ </area>
+ <area tabs="1" current="OutputPane">
+ <widget name="OutputPane" closed="true"/>
+ </area>
+ <sizes>0 0</sizes>
+ </splitter>
+ <sizes>1291 0</sizes>
+ </splitter>
+ <splitter orientation="Horizontal" count="2">
+ <area tabs="1" current="">
+ <widget name="Timelines" closed="true"/>
+ </area>
+ <area tabs="2" current="TransitionEditor">
+ <widget name="CurveEditorId" closed="true"/>
+ <widget name="TransitionEditor" closed="true"/>
+ </area>
+ <sizes>1291 0</sizes>
+ </splitter>
+ <sizes>873 0</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="3">
+ <area tabs="1" current="Properties">
+ <widget name="Properties" closed="false"/>
+ </area>
+ <area tabs="1" current="TranslationsView">
+ <widget name="TranslationsView" closed="true"/>
+ </area>
+ <area tabs="1" current="ConnectionView">
+ <widget name="ConnectionView" closed="false"/>
+ </area>
+ <sizes>637 0 235</sizes>
+ </splitter>
+ <sizes>438 1291 573</sizes>
+ </splitter>
+ <area tabs="1" current="StatesEditor">
+ <widget name="StatesEditor" closed="false"/>
+ </area>
+ <sizes>873 276</sizes>
+ </splitter>
+ </container>
+</QtAdvancedDockingSystem>
diff --git a/share/qtcreator/qmldesigner/workspacePresets/Views-All.wrk b/share/qtcreator/qmldesigner/workspacePresets/Views-All.wrk
index 7a2639e9550..47b47b213b1 100644
--- a/share/qtcreator/qmldesigner/workspacePresets/Views-All.wrk
+++ b/share/qtcreator/qmldesigner/workspacePresets/Views-All.wrk
@@ -1 +1,70 @@
-<?xml version="1.0" encoding="UTF-8"?><QtAdvancedDockingSystem version="1" userVersion="0" containers="1"><container floating="false"><splitter orientation="Horizontal" count="3"><splitter orientation="Vertical" count="3"><area tabs="2" current="Navigator"><widget name="Navigator" closed="false"/><widget name="Projects" closed="false"/></area><area tabs="2" current="FileSystem"><widget name="FileSystem" closed="false"/><widget name="OpenDocuments" closed="false"/></area><area tabs="2" current="Components"><widget name="Components" closed="false"/><widget name="Assets" closed="false"/></area><sizes>343 353 270</sizes></splitter><splitter orientation="Vertical" count="2"><splitter orientation="Horizontal" count="2"><splitter orientation="Vertical" count="2"><area tabs="1" current="FormEditor"><widget name="FormEditor" closed="false"/></area><area tabs="1" current="Editor3D"><widget name="Editor3D" closed="false"/></area><sizes>353 353</sizes></splitter><splitter orientation="Vertical" count="2"><area tabs="1" current="TextEditor"><widget name="TextEditor" closed="false"/></area><area tabs="1" current="OutputPane"><widget name="OutputPane" closed="false"/></area><sizes>353 353</sizes></splitter><sizes>448 465</sizes></splitter><splitter orientation="Horizontal" count="2"><area tabs="2" current="StatesEditor"><widget name="StatesEditor" closed="false"/><widget name="Timelines" closed="false"/></area><area tabs="2" current="CurveEditorId"><widget name="CurveEditorId" closed="false"/><widget name="TransitionEditor" closed="false"/></area><sizes>457 456</sizes></splitter><sizes>707 260</sizes></splitter><splitter orientation="Vertical" count="3"><area tabs="1" current="Properties"><widget name="Properties" closed="false"/></area><area tabs="1" current="TranslationsView"><widget name="TranslationsView" closed="false"/></area><area tabs="1" current="ConnectionView"><widget name="ConnectionView" closed="false"/></area><sizes>343 353 270</sizes></splitter><sizes>310 914 406</sizes></splitter></container></QtAdvancedDockingSystem>
+<?xml version="1.0" encoding="UTF-8"?>
+<QtAdvancedDockingSystem version="1" userVersion="0" containers="1" displayName="All Views">
+ <container floating="false">
+ <splitter orientation="Horizontal" count="3">
+ <splitter orientation="Vertical" count="3">
+ <area tabs="2" current="Navigator">
+ <widget name="Navigator" closed="false"/>
+ <widget name="Projects" closed="false"/>
+ </area>
+ <area tabs="2" current="FileSystem">
+ <widget name="FileSystem" closed="false"/>
+ <widget name="OpenDocuments" closed="false"/>
+ </area>
+ <area tabs="2" current="Components">
+ <widget name="Components" closed="false"/>
+ <widget name="Assets" closed="false"/>
+ </area>
+ <sizes>343 353 270</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <splitter orientation="Horizontal" count="2">
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="FormEditor">
+ <widget name="FormEditor" closed="false"/>
+ </area>
+ <area tabs="1" current="Editor3D">
+ <widget name="Editor3D" closed="false"/>
+ </area>
+ <sizes>353 353</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="2">
+ <area tabs="1" current="TextEditor">
+ <widget name="TextEditor" closed="false"/>
+ </area>
+ <area tabs="1" current="OutputPane">
+ <widget name="OutputPane" closed="false"/>
+ </area>
+ <sizes>353 353</sizes>
+ </splitter>
+ <sizes>448 465</sizes>
+ </splitter>
+ <splitter orientation="Horizontal" count="2">
+ <area tabs="2" current="StatesEditor">
+ <widget name="StatesEditor" closed="false"/>
+ <widget name="Timelines" closed="false"/>
+ </area>
+ <area tabs="2" current="CurveEditorId">
+ <widget name="CurveEditorId" closed="false"/>
+ <widget name="TransitionEditor" closed="false"/>
+ </area>
+ <sizes>457 456</sizes>
+ </splitter>
+ <sizes>707 260</sizes>
+ </splitter>
+ <splitter orientation="Vertical" count="3">
+ <area tabs="1" current="Properties">
+ <widget name="Properties" closed="false"/>
+ </area>
+ <area tabs="1" current="TranslationsView">
+ <widget name="TranslationsView" closed="false"/>
+ </area>
+ <area tabs="1" current="ConnectionView">
+ <widget name="ConnectionView" closed="false"/>
+ </area>
+ <sizes>343 353 270</sizes>
+ </splitter>
+ <sizes>310 914 406</sizes>
+ </splitter>
+ </container>
+</QtAdvancedDockingSystem>
diff --git a/share/qtcreator/qmldesigner/workspacePresets/order.json b/share/qtcreator/qmldesigner/workspacePresets/order.json
new file mode 100644
index 00000000000..d22d9d3fcc3
--- /dev/null
+++ b/share/qtcreator/qmldesigner/workspacePresets/order.json
@@ -0,0 +1,11 @@
+[
+ "Basic.wrk",
+ "UX-Design.wrk",
+ "Essentials.wrk",
+ "Animation-2D.wrk",
+ "Essentials-3D.wrk",
+ "Animation-3D.wrk",
+ "Advanced-3D.wrk",
+ "Code.wrk",
+ "Views-All.wrk"
+]
diff --git a/src/libs/3rdparty/sqlite/sqlite3.c b/src/libs/3rdparty/sqlite/sqlite3.c
index b47891c3817..dd3b5c57570 100644
--- a/src/libs/3rdparty/sqlite/sqlite3.c
+++ b/src/libs/3rdparty/sqlite/sqlite3.c
@@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
-** version 3.41.0. By combining all the individual C code files into this
+** version 3.42.0. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@@ -123,6 +123,10 @@
#define SQLITE_4_BYTE_ALIGNED_MALLOC
#endif /* defined(_MSC_VER) && !defined(_WIN64) */
+#if !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800
+#define HAVE_LOG2 0
+#endif /* !defined(HAVE_LOG2) && defined(_MSC_VER) && _MSC_VER<1800 */
+
#endif /* SQLITE_MSVC_H */
/************** End of msvc.h ************************************************/
@@ -452,9 +456,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.41.0"
-#define SQLITE_VERSION_NUMBER 3041000
-#define SQLITE_SOURCE_ID "2023-02-21 18:09:37 05941c2a04037fc3ed2ffae11f5d2260706f89431f463518740f72ada350866d"
+#define SQLITE_VERSION "3.42.0"
+#define SQLITE_VERSION_NUMBER 3042000
+#define SQLITE_SOURCE_ID "2023-05-16 12:36:15 831d0fb2836b71c9bc51067c49fee4b8f18047814f2ff22d817d25195cf350b0"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -1961,20 +1965,23 @@ SQLITE_API int sqlite3_os_end(void);
** must ensure that no other SQLite interfaces are invoked by other
** threads while sqlite3_config() is running.</b>
**
-** The sqlite3_config() interface
-** may only be invoked prior to library initialization using
-** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
-** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
-** [sqlite3_shutdown()] then it will return SQLITE_MISUSE.
-** Note, however, that ^sqlite3_config() can be called as part of the
-** implementation of an application-defined [sqlite3_os_init()].
-**
** The first argument to sqlite3_config() is an integer
** [configuration option] that determines
** what property of SQLite is to be configured. Subsequent arguments
** vary depending on the [configuration option]
** in the first argument.
**
+** For most configuration options, the sqlite3_config() interface
+** may only be invoked prior to library initialization using
+** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
+** The exceptional configuration options that may be invoked at any time
+** are called "anytime configuration options".
+** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
+** [sqlite3_shutdown()] with a first argument that is not an anytime
+** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE.
+** Note, however, that ^sqlite3_config() can be called as part of the
+** implementation of an application-defined [sqlite3_os_init()].
+**
** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK].
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
@@ -2082,6 +2089,23 @@ struct sqlite3_mem_methods {
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlite3_config()] interface.
**
+** Most of the configuration options for sqlite3_config()
+** will only work if invoked prior to [sqlite3_initialize()] or after
+** [sqlite3_shutdown()]. The few exceptions to this rule are called
+** "anytime configuration options".
+** ^Calling [sqlite3_config()] with a first argument that is not an
+** anytime configuration option in between calls to [sqlite3_initialize()] and
+** [sqlite3_shutdown()] is a no-op that returns SQLITE_MISUSE.
+**
+** The set of anytime configuration options can change (by insertions
+** and/or deletions) from one release of SQLite to the next.
+** As of SQLite version 3.42.0, the complete set of anytime configuration
+** options is:
+** <ul>
+** <li> SQLITE_CONFIG_LOG
+** <li> SQLITE_CONFIG_PCACHE_HDRSZ
+** </ul>
+**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
** should check the return code from [sqlite3_config()] to make sure that
@@ -2428,28 +2452,28 @@ struct sqlite3_mem_methods {
** compile-time option is not set, then the default maximum is 1073741824.
** </dl>
*/
-#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
-#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
-#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
-#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
-#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
-#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
-#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
-#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
-#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
-#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
-#define SQLITE_CONFIG_PCACHE 14 /* no-op */
-#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
-#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
-#define SQLITE_CONFIG_URI 17 /* int */
-#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
-#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
+#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
+#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
+#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
+#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
+#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
+#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
+#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
+#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
+#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
+#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
+#define SQLITE_CONFIG_PCACHE 14 /* no-op */
+#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
+#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
+#define SQLITE_CONFIG_URI 17 /* int */
+#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
-#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
-#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
+#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
@@ -2684,7 +2708,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
-** <dt>SQLITE_DBCONFIG_DQS_DML</td>
+** <dt>SQLITE_DBCONFIG_DQS_DML</dt>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
@@ -2693,7 +2717,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
-** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
+** <dt>SQLITE_DBCONFIG_DQS_DDL</dt>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
@@ -2702,7 +2726,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
-** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
+** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</dt>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
@@ -2722,7 +2746,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
-** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
+** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</dt>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag. When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
@@ -2731,7 +2755,7 @@ struct sqlite3_mem_methods {
** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
** newly created databases are generally not understandable by SQLite versions
** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
-** is now scarcely any need to generated database files that are compatible
+** is now scarcely any need to generate database files that are compatible
** all the way back to version 3.0.0, and so this setting is of little
** practical use, but is provided so that SQLite can continue to claim the
** ability to generate new database files that are compatible with version
@@ -2742,6 +2766,38 @@ struct sqlite3_mem_methods {
** not considered a bug since SQLite versions 3.3.0 and earlier do not support
** either generated columns or decending indexes.
** </dd>
+**
+** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]]
+** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</dt>
+** <dd>The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in
+** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
+** a flag that enables collection of the sqlite3_stmt_scanstatus_v2()
+** statistics. For statistics to be collected, the flag must be set on
+** the database handle both when the SQL statement is prepared and when it
+** is stepped. The flag is set (collection of statistics is enabled)
+** by default. This option takes two arguments: an integer and a pointer to
+** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the statement scanstatus option. If the second argument
+** is not NULL, then the value of the statement scanstatus setting after
+** processing the first argument is written into the integer that the second
+** argument points to.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]]
+** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</dt>
+** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order
+** in which tables and indexes are scanned so that the scans start at the end
+** and work toward the beginning rather than starting at the beginning and
+** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
+** same as setting [PRAGMA reverse_unordered_selects]. This option takes
+** two arguments which are an integer and a pointer to an integer. The first
+** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
+** reverse scan order flag, respectively. If the second argument is not NULL,
+** then 0 or 1 is written into the integer that the second argument points to
+** depending on if the reverse scan order flag is set after processing the
+** first argument.
+** </dd>
+**
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -2762,7 +2818,9 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
+#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -6507,6 +6565,13 @@ SQLITE_API void sqlite3_activate_cerod(
** of the default VFS is not implemented correctly, or not implemented at
** all, then the behavior of sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
+**
+** If a negative argument is passed to sqlite3_sleep() the results vary by
+** VFS and operating system. Some system treat a negative argument as an
+** instruction to sleep forever. Others understand it to mean do not sleep
+** at all. ^In SQLite version 3.42.0 and later, a negative
+** argument passed into sqlite3_sleep() is changed to zero before it is relayed
+** down into the xSleep method of the VFS.
*/
SQLITE_API int sqlite3_sleep(int);
@@ -8134,9 +8199,9 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** is undefined if the mutex is not currently entered by the
** calling thread or is not currently allocated.
**
-** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
-** sqlite3_mutex_leave() is a NULL pointer, then all three routines
-** behave as no-ops.
+** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(),
+** sqlite3_mutex_leave(), or sqlite3_mutex_free() is a NULL pointer,
+** then any of the four routines behaves as a no-op.
**
** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
*/
@@ -9870,18 +9935,28 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** identify that virtual table as being safe to use from within triggers
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a
** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary.
** </dd>
+**
+** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]<dt>SQLITE_VTAB_USES_ALL_SCHEMAS</dt>
+** <dd>Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
+** instruct the query planner to begin at least a read transaction on
+** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the
+** virtual table is used.
+** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS 2
#define SQLITE_VTAB_DIRECTONLY 3
+#define SQLITE_VTAB_USES_ALL_SCHEMAS 4
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
@@ -11056,16 +11131,20 @@ SQLITE_API int sqlite3session_create(
SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
/*
-** CAPIREF: Conigure a Session Object
+** CAPI3REF: Configure a Session Object
** METHOD: sqlite3_session
**
** This method is used to configure a session object after it has been
-** created. At present the only valid value for the second parameter is
-** [SQLITE_SESSION_OBJCONFIG_SIZE].
+** created. At present the only valid values for the second parameter are
+** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID].
**
-** Arguments for sqlite3session_object_config()
+*/
+SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
+
+/*
+** CAPI3REF: Options for sqlite3session_object_config
**
-** The following values may passed as the the 4th parameter to
+** The following values may passed as the the 2nd parameter to
** sqlite3session_object_config().
**
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
@@ -11081,12 +11160,21 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
+**
+** <dt>SQLITE_SESSION_OBJCONFIG_ROWID <dd>
+** This option is used to set, clear or query the flag that enables
+** collection of data for tables with no explicit PRIMARY KEY.
+**
+** Normally, tables with no explicit PRIMARY KEY are simply ignored
+** by the sessions module. However, if this flag is set, it behaves
+** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted
+** as their leftmost columns.
+**
+** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
+** the first table has been attached to the session object.
*/
-SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
-
-/*
-*/
-#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_ROWID 2
/*
** CAPI3REF: Enable Or Disable A Session Object
@@ -12219,9 +12307,23 @@ SQLITE_API int sqlite3changeset_apply_v2(
** Invert the changeset before applying it. This is equivalent to inverting
** a changeset using sqlite3changeset_invert() before applying it. It is
** an error to specify this flag with a patchset.
+**
+** <dt>SQLITE_CHANGESETAPPLY_IGNORENOOP <dd>
+** Do not invoke the conflict handler callback for any changes that
+** would not actually modify the database even if they were applied.
+** Specifically, this means that the conflict handler is not invoked
+** for:
+** <ul>
+** <li>a delete change if the row being deleted cannot be found,
+** <li>an update change if the modified fields are already set to
+** their new values in the conflicting row, or
+** <li>an insert change if all fields of the conflicting row match
+** the row being inserted.
+** </ul>
*/
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
+#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
/*
** CAPI3REF: Constants Passed To The Conflict Handler
@@ -13518,8 +13620,8 @@ struct fts5_api {
#endif
/*
-** WAL mode depends on atomic aligned 32-bit loads and stores in a few
-** places. The following macros try to make this explicit.
+** A few places in the code require atomic load/store of aligned
+** integer values.
*/
#ifndef __has_extension
# define __has_extension(x) 0 /* compatibility with non-clang compilers */
@@ -13575,15 +13677,22 @@ struct fts5_api {
#endif
/*
-** A macro to hint to the compiler that a function should not be
+** Macros to hint to the compiler that a function should or should not be
** inlined.
*/
#if defined(__GNUC__)
# define SQLITE_NOINLINE __attribute__((noinline))
+# define SQLITE_INLINE __attribute__((always_inline)) inline
#elif defined(_MSC_VER) && _MSC_VER>=1310
# define SQLITE_NOINLINE __declspec(noinline)
+# define SQLITE_INLINE __forceinline
#else
# define SQLITE_NOINLINE
+# define SQLITE_INLINE
+#endif
+#if defined(SQLITE_COVERAGE_TEST) || defined(__STRICT_ANSI__)
+# undef SQLITE_INLINE
+# define SQLITE_INLINE
#endif
/*
@@ -16544,6 +16653,10 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatusCounters(Vdbe*, int, int, int);
SQLITE_PRIVATE void sqlite3VdbePrintOp(FILE*, int, VdbeOp*);
#endif
+#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr);
+#endif
+
#endif /* SQLITE_VDBE_H */
/************** End of vdbe.h ************************************************/
@@ -16592,7 +16705,7 @@ struct PgHdr {
** private to pcache.c and should not be accessed by other modules.
** pCache is grouped with the public elements for efficiency.
*/
- i16 nRef; /* Number of users of this page */
+ i64 nRef; /* Number of users of this page */
PgHdr *pDirtyNext; /* Next element in list of dirty pages */
PgHdr *pDirtyPrev; /* Previous element in list of dirty pages */
/* NB: pDirtyNext and pDirtyPrev are undefined if the
@@ -16673,12 +16786,12 @@ SQLITE_PRIVATE void sqlite3PcacheClearSyncFlags(PCache *);
SQLITE_PRIVATE void sqlite3PcacheClear(PCache*);
/* Return the total number of outstanding page references */
-SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache*);
+SQLITE_PRIVATE i64 sqlite3PcacheRefCount(PCache*);
/* Increment the reference count of an existing page */
SQLITE_PRIVATE void sqlite3PcacheRef(PgHdr*);
-SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr*);
+SQLITE_PRIVATE i64 sqlite3PcachePageRefcount(PgHdr*);
/* Return the total number of pages stored in the cache */
SQLITE_PRIVATE int sqlite3PcachePagecount(PCache*);
@@ -17253,7 +17366,7 @@ struct sqlite3 {
#define SQLITE_NullCallback 0x00000100 /* Invoke the callback once if the */
/* result set is empty */
#define SQLITE_IgnoreChecks 0x00000200 /* Do not enforce check constraints */
-#define SQLITE_ReadUncommit 0x00000400 /* READ UNCOMMITTED in shared-cache */
+#define SQLITE_StmtScanStatus 0x00000400 /* Enable stmt_scanstats() counters */
#define SQLITE_NoCkptOnClose 0x00000800 /* No checkpoint on close()/DETACH */
#define SQLITE_ReverseOrder 0x00001000 /* Reverse unordered SELECTs */
#define SQLITE_RecTriggers 0x00002000 /* Enable recursive triggers */
@@ -17279,6 +17392,7 @@ struct sqlite3 {
/* DELETE, or UPDATE and return */
/* the count using a callback. */
#define SQLITE_CorruptRdOnly HI(0x00002) /* Prohibit writes due to error */
+#define SQLITE_ReadUncommit HI(0x00004) /* READ UNCOMMITTED in shared-cache */
/* Flags used only if debugging */
#ifdef SQLITE_DEBUG
@@ -17335,6 +17449,7 @@ struct sqlite3 {
/* TH3 expects this value ^^^^^^^^^^ See flatten04.test */
#define SQLITE_IndexedExpr 0x01000000 /* Pull exprs from index when able */
#define SQLITE_Coroutines 0x02000000 /* Co-routines for subqueries */
+#define SQLITE_NullUnusedCols 0x04000000 /* NULL unused columns in subqueries */
#define SQLITE_AllOpts 0xffffffff /* All optimizations */
/*
@@ -17806,6 +17921,7 @@ struct VTable {
sqlite3_vtab *pVtab; /* Pointer to vtab instance */
int nRef; /* Number of pointers to this structure */
u8 bConstraint; /* True if constraints are supported */
+ u8 bAllSchemas; /* True if might use any attached schema */
u8 eVtabRisk; /* Riskiness of allowing hacker access */
int iSavepoint; /* Depth of the SAVEPOINT stack */
VTable *pNext; /* Next in linked list (see above) */
@@ -18186,6 +18302,7 @@ struct Index {
** expression, or a reference to a VIRTUAL column */
#ifdef SQLITE_ENABLE_STAT4
int nSample; /* Number of elements in aSample[] */
+ int mxSample; /* Number of slots allocated to aSample[] */
int nSampleCol; /* Size of IndexSample.anEq[] and so on */
tRowcnt *aAvgEq; /* Average nEq values for keys not in aSample */
IndexSample *aSample; /* Samples of the left-most key */
@@ -18837,7 +18954,7 @@ struct NameContext {
#define NC_HasAgg 0x000010 /* One or more aggregate functions seen */
#define NC_IdxExpr 0x000020 /* True if resolving columns of CREATE INDEX */
#define NC_SelfRef 0x00002e /* Combo: PartIdx, isCheck, GenCol, and IdxExpr */
-#define NC_VarSelect 0x000040 /* A correlated subquery has been seen */
+#define NC_Subquery 0x000040 /* A subquery has been seen */
#define NC_UEList 0x000080 /* True if uNC.pEList is used */
#define NC_UAggInfo 0x000100 /* True if uNC.pAggInfo is used */
#define NC_UUpsert 0x000200 /* True if uNC.pUpsert is used */
@@ -19156,6 +19273,7 @@ struct IndexedExpr {
int iIdxCur; /* The index cursor */
int iIdxCol; /* The index column that contains value of pExpr */
u8 bMaybeNullRow; /* True if we need an OP_IfNullRow check */
+ u8 aff; /* Affinity of the pExpr expression */
IndexedExpr *pIENext; /* Next in a list of all indexed expressions */
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
const char *zIdxName; /* Name of index, used only for bytecode comments */
@@ -19208,6 +19326,9 @@ struct Parse {
#if defined(SQLITE_DEBUG) || defined(SQLITE_COVERAGE_TEST)
u8 earlyCleanup; /* OOM inside sqlite3ParserAddCleanup() */
#endif
+#ifdef SQLITE_DEBUG
+ u8 ifNotExists; /* Might be true if IF NOT EXISTS. Assert()s only */
+#endif
int nRangeReg; /* Size of the temporary register block */
int iRangeReg; /* First register in temporary register block */
int nErr; /* Number of errors seen */
@@ -19668,6 +19789,7 @@ struct Walker {
struct CoveringIndexCheck *pCovIdxCk; /* Check for covering index */
SrcItem *pSrcItem; /* A single FROM clause item */
DbFixer *pFix; /* See sqlite3FixSelect() */
+ Mem *aMem; /* See sqlite3BtreeCursorHint() */
} u;
};
@@ -19937,6 +20059,8 @@ SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno);
# define sqlite3Isxdigit(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x08)
# define sqlite3Tolower(x) (sqlite3UpperToLower[(unsigned char)(x)])
# define sqlite3Isquote(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x80)
+# define sqlite3JsonId1(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x42)
+# define sqlite3JsonId2(x) (sqlite3CtypeMap[(unsigned char)(x)]&0x46)
#else
# define sqlite3Toupper(x) toupper((unsigned char)(x))
# define sqlite3Isspace(x) isspace((unsigned char)(x))
@@ -19946,6 +20070,8 @@ SQLITE_PRIVATE int sqlite3CorruptPgnoError(int,Pgno);
# define sqlite3Isxdigit(x) isxdigit((unsigned char)(x))
# define sqlite3Tolower(x) tolower((unsigned char)(x))
# define sqlite3Isquote(x) ((x)=='"'||(x)=='\''||(x)=='['||(x)=='`')
+# define sqlite3JsonId1(x) (sqlite3IsIdChar(x)&&(x)<'0')
+# define sqlite3JsonId2(x) sqlite3IsIdChar(x)
#endif
SQLITE_PRIVATE int sqlite3IsIdChar(u8);
@@ -20139,6 +20265,10 @@ SQLITE_PRIVATE void sqlite3ReleaseTempReg(Parse*,int);
SQLITE_PRIVATE int sqlite3GetTempRange(Parse*,int);
SQLITE_PRIVATE void sqlite3ReleaseTempRange(Parse*,int,int);
SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse*);
+SQLITE_PRIVATE void sqlite3TouchRegister(Parse*,int);
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG)
+SQLITE_PRIVATE int sqlite3FirstAvailableRegister(Parse*,int);
+#endif
#ifdef SQLITE_DEBUG
SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse*,int,int);
#endif
@@ -20289,7 +20419,7 @@ SQLITE_PRIVATE Select *sqlite3SelectNew(Parse*,ExprList*,SrcList*,Expr*,ExprList
Expr*,ExprList*,u32,Expr*);
SQLITE_PRIVATE void sqlite3SelectDelete(sqlite3*, Select*);
SQLITE_PRIVATE Table *sqlite3SrcListLookup(Parse*, SrcList*);
-SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, int);
+SQLITE_PRIVATE int sqlite3IsReadOnly(Parse*, Table*, Trigger*);
SQLITE_PRIVATE void sqlite3OpenTable(Parse*, int iCur, int iDb, Table*, int);
#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
SQLITE_PRIVATE Expr *sqlite3LimitWhere(Parse*,SrcList*,Expr*,ExprList*,Expr*,char*);
@@ -20378,7 +20508,7 @@ SQLITE_PRIVATE int sqlite3ExprIsConstantNotJoin(Expr*);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrFunction(Expr*, u8);
SQLITE_PRIVATE int sqlite3ExprIsConstantOrGroupBy(Parse*, Expr*, ExprList*);
SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr*,int);
-SQLITE_PRIVATE int sqlite3ExprIsTableConstraint(Expr*,const SrcItem*);
+SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint(Expr*,const SrcList*,int);
#ifdef SQLITE_ENABLE_CURSOR_HINTS
SQLITE_PRIVATE int sqlite3ExprContainsSubquery(Expr*);
#endif
@@ -20826,10 +20956,7 @@ SQLITE_PRIVATE int sqlite3VtabCallDestroy(sqlite3*, int, const char *);
SQLITE_PRIVATE int sqlite3VtabBegin(sqlite3 *, VTable *);
SQLITE_PRIVATE FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*);
-#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
- && !defined(SQLITE_OMIT_VIRTUALTABLE)
-SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(sqlite3_index_info*);
-#endif
+SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(Parse*);
SQLITE_PRIVATE sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*);
SQLITE_PRIVATE int sqlite3VdbeParameterIndex(Vdbe*, const char*, int);
SQLITE_PRIVATE int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *);
@@ -21076,6 +21203,12 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void);
SQLITE_PRIVATE sqlite3_uint64 sqlite3Hwtime(void);
#endif
+#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
+# define IS_STMT_SCANSTATUS(db) (db->flags & SQLITE_StmtScanStatus)
+#else
+# define IS_STMT_SCANSTATUS(db) 0
+#endif
+
#endif /* SQLITEINT_H */
/************** End of sqliteInt.h *******************************************/
@@ -22071,7 +22204,7 @@ SQLITE_PRIVATE const unsigned char *sqlite3aGTb = &sqlite3UpperToLower[256+12-OP
** isalnum() 0x06
** isxdigit() 0x08
** toupper() 0x20
-** SQLite identifier character 0x40
+** SQLite identifier character 0x40 $, _, or non-ascii
** Quote character 0x80
**
** Bit 0x20 is set if the mapped character requires translation to upper
@@ -22265,7 +22398,7 @@ SQLITE_PRIVATE SQLITE_WSD struct Sqlite3Config sqlite3Config = {
SQLITE_DEFAULT_SORTERREF_SIZE, /* szSorterRef */
0, /* iPrngSeed */
#ifdef SQLITE_DEBUG
- {0,0,0,0,0,0} /* aTune */
+ {0,0,0,0,0,0}, /* aTune */
#endif
};
@@ -23564,6 +23697,7 @@ struct DateTime {
char validTZ; /* True (1) if tz is valid */
char tzSet; /* Timezone was set explicitly */
char isError; /* An overflow has occurred */
+ char useSubsec; /* Display subsecond precision */
};
@@ -23878,6 +24012,11 @@ static int parseDateOrTime(
}else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8)>0 ){
setRawDateNumber(p, r);
return 0;
+ }else if( (sqlite3StrICmp(zDate,"subsec")==0
+ || sqlite3StrICmp(zDate,"subsecond")==0)
+ && sqlite3NotPureFunc(context) ){
+ p->useSubsec = 1;
+ return setDateTimeToCurrent(context, p);
}
return 1;
}
@@ -24292,8 +24431,22 @@ static int parseModifier(
**
** Move the date backwards to the beginning of the current day,
** or month or year.
+ **
+ ** subsecond
+ ** subsec
+ **
+ ** Show subsecond precision in the output of datetime() and
+ ** unixepoch() and strftime('%s').
*/
- if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
+ if( sqlite3_strnicmp(z, "start of ", 9)!=0 ){
+ if( sqlite3_stricmp(z, "subsec")==0
+ || sqlite3_stricmp(z, "subsecond")==0
+ ){
+ p->useSubsec = 1;
+ rc = 0;
+ }
+ break;
+ }
if( !p->validJD && !p->validYMD && !p->validHMS ) break;
z += 9;
computeYMD(p);
@@ -24491,7 +24644,11 @@ static void unixepochFunc(
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
computeJD(&x);
- sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000);
+ if( x.useSubsec ){
+ sqlite3_result_double(context, (x.iJD - 21086676*(i64)10000000)/1000.0);
+ }else{
+ sqlite3_result_int64(context, x.iJD/1000 - 21086676*(i64)10000);
+ }
}
}
@@ -24507,8 +24664,8 @@ static void datetimeFunc(
){
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
- int Y, s;
- char zBuf[24];
+ int Y, s, n;
+ char zBuf[32];
computeYMD_HMS(&x);
Y = x.Y;
if( Y<0 ) Y = -Y;
@@ -24529,15 +24686,28 @@ static void datetimeFunc(
zBuf[15] = '0' + (x.m/10)%10;
zBuf[16] = '0' + (x.m)%10;
zBuf[17] = ':';
- s = (int)x.s;
- zBuf[18] = '0' + (s/10)%10;
- zBuf[19] = '0' + (s)%10;
- zBuf[20] = 0;
+ if( x.useSubsec ){
+ s = (int)1000.0*x.s;
+ zBuf[18] = '0' + (s/10000)%10;
+ zBuf[19] = '0' + (s/1000)%10;
+ zBuf[20] = '.';
+ zBuf[21] = '0' + (s/100)%10;
+ zBuf[22] = '0' + (s/10)%10;
+ zBuf[23] = '0' + (s)%10;
+ zBuf[24] = 0;
+ n = 24;
+ }else{
+ s = (int)x.s;
+ zBuf[18] = '0' + (s/10)%10;
+ zBuf[19] = '0' + (s)%10;
+ zBuf[20] = 0;
+ n = 20;
+ }
if( x.Y<0 ){
zBuf[0] = '-';
- sqlite3_result_text(context, zBuf, 20, SQLITE_TRANSIENT);
+ sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
}else{
- sqlite3_result_text(context, &zBuf[1], 19, SQLITE_TRANSIENT);
+ sqlite3_result_text(context, &zBuf[1], n-1, SQLITE_TRANSIENT);
}
}
}
@@ -24554,7 +24724,7 @@ static void timeFunc(
){
DateTime x;
if( isDate(context, argc, argv, &x)==0 ){
- int s;
+ int s, n;
char zBuf[16];
computeHMS(&x);
zBuf[0] = '0' + (x.h/10)%10;
@@ -24563,11 +24733,24 @@ static void timeFunc(
zBuf[3] = '0' + (x.m/10)%10;
zBuf[4] = '0' + (x.m)%10;
zBuf[5] = ':';
- s = (int)x.s;
- zBuf[6] = '0' + (s/10)%10;
- zBuf[7] = '0' + (s)%10;
- zBuf[8] = 0;
- sqlite3_result_text(context, zBuf, 8, SQLITE_TRANSIENT);
+ if( x.useSubsec ){
+ s = (int)1000.0*x.s;
+ zBuf[6] = '0' + (s/10000)%10;
+ zBuf[7] = '0' + (s/1000)%10;
+ zBuf[8] = '.';
+ zBuf[9] = '0' + (s/100)%10;
+ zBuf[10] = '0' + (s/10)%10;
+ zBuf[11] = '0' + (s)%10;
+ zBuf[12] = 0;
+ n = 12;
+ }else{
+ s = (int)x.s;
+ zBuf[6] = '0' + (s/10)%10;
+ zBuf[7] = '0' + (s)%10;
+ zBuf[8] = 0;
+ n = 8;
+ }
+ sqlite3_result_text(context, zBuf, n, SQLITE_TRANSIENT);
}
}
@@ -24698,8 +24881,13 @@ static void strftimeFunc(
break;
}
case 's': {
- i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
- sqlite3_str_appendf(&sRes,"%lld",iS);
+ if( x.useSubsec ){
+ sqlite3_str_appendf(&sRes,"%.3f",
+ (x.iJD - 21086676*(i64)10000000)/1000.0);
+ }else{
+ i64 iS = (i64)(x.iJD/1000 - 21086676*(i64)10000);
+ sqlite3_str_appendf(&sRes,"%lld",iS);
+ }
break;
}
case 'S': {
@@ -30070,6 +30258,20 @@ static char et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){
}
#endif /* SQLITE_OMIT_FLOATING_POINT */
+#ifndef SQLITE_OMIT_FLOATING_POINT
+/*
+** "*val" is a u64. *msd is a divisor used to extract the
+** most significant digit of *val. Extract that most significant
+** digit and return it.
+*/
+static char et_getdigit_int(u64 *val, u64 *msd){
+ u64 x = (*val)/(*msd);
+ *val -= x*(*msd);
+ if( *msd>=10 ) *msd /= 10;
+ return '0' + (char)(x & 15);
+}
+#endif /* SQLITE_OMIT_FLOATING_POINT */
+
/*
** Set the StrAccum object to an error mode.
*/
@@ -30162,6 +30364,8 @@ SQLITE_API void sqlite3_str_vappendf(
char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */
sqlite_uint64 longvalue; /* Value for integer types */
LONGDOUBLE_TYPE realvalue; /* Value for real types */
+ sqlite_uint64 msd; /* Divisor to get most-significant-digit
+ ** of longvalue */
const et_info *infop; /* Pointer to the appropriate info structure */
char *zOut; /* Rendering buffer */
int nOut; /* Size of the rendering buffer */
@@ -30468,52 +30672,78 @@ SQLITE_API void sqlite3_str_vappendf(
}else{
prefix = flag_prefix;
}
+ exp = 0;
if( xtype==etGENERIC && precision>0 ) precision--;
testcase( precision>0xfff );
- idx = precision & 0xfff;
- rounder = arRound[idx%10];
- while( idx>=10 ){ rounder *= 1.0e-10; idx -= 10; }
- if( xtype==etFLOAT ){
- double rx = (double)realvalue;
- sqlite3_uint64 u;
- int ex;
- memcpy(&u, &rx, sizeof(u));
- ex = -1023 + (int)((u>>52)&0x7ff);
- if( precision+(ex/3) < 15 ) rounder += realvalue*3e-16;
- realvalue += rounder;
- }
- /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
- exp = 0;
- if( sqlite3IsNaN((double)realvalue) ){
- bufpt = "NaN";
- length = 3;
- break;
- }
- if( realvalue>0.0 ){
- LONGDOUBLE_TYPE scale = 1.0;
- while( realvalue>=1e100*scale && exp<=350 ){ scale *= 1e100;exp+=100;}
- while( realvalue>=1e10*scale && exp<=350 ){ scale *= 1e10; exp+=10; }
- while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; }
- realvalue /= scale;
- while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
- while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
- if( exp>350 ){
- bufpt = buf;
- buf[0] = prefix;
- memcpy(buf+(prefix!=0),"Inf",4);
- length = 3+(prefix!=0);
+ if( realvalue<1.0e+16
+ && realvalue==(LONGDOUBLE_TYPE)(longvalue = (u64)realvalue)
+ ){
+ /* Number is a pure integer that can be represented as u64 */
+ for(msd=1; msd*10<=longvalue; msd *= 10, exp++){}
+ if( exp>precision && xtype!=etFLOAT ){
+ u64 rnd = msd/2;
+ int kk = precision;
+ while( kk-- > 0 ){ rnd /= 10; }
+ longvalue += rnd;
+ }
+ }else{
+ msd = 0;
+ longvalue = 0; /* To prevent a compiler warning */
+ idx = precision & 0xfff;
+ rounder = arRound[idx%10];
+ while( idx>=10 ){ rounder *= 1.0e-10; idx -= 10; }
+ if( xtype==etFLOAT ){
+ double rx = (double)realvalue;
+ sqlite3_uint64 u;
+ int ex;
+ memcpy(&u, &rx, sizeof(u));
+ ex = -1023 + (int)((u>>52)&0x7ff);
+ if( precision+(ex/3) < 15 ) rounder += realvalue*3e-16;
+ realvalue += rounder;
+ }
+ if( sqlite3IsNaN((double)realvalue) ){
+ if( flag_zeropad ){
+ bufpt = "null";
+ length = 4;
+ }else{
+ bufpt = "NaN";
+ length = 3;
+ }
break;
}
+
+ /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */
+ if( ALWAYS(realvalue>0.0) ){
+ LONGDOUBLE_TYPE scale = 1.0;
+ while( realvalue>=1e100*scale && exp<=350){ scale*=1e100;exp+=100;}
+ while( realvalue>=1e10*scale && exp<=350 ){ scale*=1e10; exp+=10; }
+ while( realvalue>=10.0*scale && exp<=350 ){ scale *= 10.0; exp++; }
+ realvalue /= scale;
+ while( realvalue<1e-8 ){ realvalue *= 1e8; exp-=8; }
+ while( realvalue<1.0 ){ realvalue *= 10.0; exp--; }
+ if( exp>350 ){
+ if( flag_zeropad ){
+ realvalue = 9.0;
+ exp = 999;
+ }else{
+ bufpt = buf;
+ buf[0] = prefix;
+ memcpy(buf+(prefix!=0),"Inf",4);
+ length = 3+(prefix!=0);
+ break;
+ }
+ }
+ if( xtype!=etFLOAT ){
+ realvalue += rounder;
+ if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
+ }
+ }
}
- bufpt = buf;
+
/*
** If the field type is etGENERIC, then convert to either etEXP
** or etFLOAT, as appropriate.
*/
- if( xtype!=etFLOAT ){
- realvalue += rounder;
- if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; }
- }
if( xtype==etGENERIC ){
flag_rtz = !flag_alternateform;
if( exp<-4 || exp>precision ){
@@ -30530,16 +30760,18 @@ SQLITE_API void sqlite3_str_vappendf(
}else{
e2 = exp;
}
+ nsd = 16 + flag_altform2*10;
+ bufpt = buf;
{
i64 szBufNeeded; /* Size of a temporary buffer needed */
szBufNeeded = MAX(e2,0)+(i64)precision+(i64)width+15;
+ if( cThousand && e2>0 ) szBufNeeded += (e2+2)/3;
if( szBufNeeded > etBUFSIZE ){
bufpt = zExtra = printfTempBuf(pAccum, szBufNeeded);
if( bufpt==0 ) return;
}
}
zOut = bufpt;
- nsd = 16 + flag_altform2*10;
flag_dp = (precision>0 ?1:0) | flag_alternateform | flag_altform2;
/* The sign in front of the number */
if( prefix ){
@@ -30548,9 +30780,15 @@ SQLITE_API void sqlite3_str_vappendf(
/* Digits prior to the decimal point */
if( e2<0 ){
*(bufpt++) = '0';
+ }else if( msd>0 ){
+ for(; e2>=0; e2--){
+ *(bufpt++) = et_getdigit_int(&longvalue,&msd);
+ if( cThousand && (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
+ }
}else{
for(; e2>=0; e2--){
*(bufpt++) = et_getdigit(&realvalue,&nsd);
+ if( cThousand && (e2%3)==0 && e2>1 ) *(bufpt++) = ',';
}
}
/* The decimal point */
@@ -30564,8 +30802,14 @@ SQLITE_API void sqlite3_str_vappendf(
*(bufpt++) = '0';
}
/* Significant digits after the decimal point */
- while( (precision--)>0 ){
- *(bufpt++) = et_getdigit(&realvalue,&nsd);
+ if( msd>0 ){
+ while( (precision--)>0 ){
+ *(bufpt++) = et_getdigit_int(&longvalue,&msd);
+ }
+ }else{
+ while( (precision--)>0 ){
+ *(bufpt++) = et_getdigit(&realvalue,&nsd);
+ }
}
/* Remove trailing zeros and the "." if no digits follow the "." */
if( flag_rtz && flag_dp ){
@@ -31246,12 +31490,22 @@ SQLITE_API char *sqlite3_vsnprintf(int n, char *zBuf, const char *zFormat, va_li
return zBuf;
}
SQLITE_API char *sqlite3_snprintf(int n, char *zBuf, const char *zFormat, ...){
- char *z;
+ StrAccum acc;
va_list ap;
+ if( n<=0 ) return zBuf;
+#ifdef SQLITE_ENABLE_API_ARMOR
+ if( zBuf==0 || zFormat==0 ) {
+ (void)SQLITE_MISUSE_BKPT;
+ if( zBuf ) zBuf[0] = 0;
+ return zBuf;
+ }
+#endif
+ sqlite3StrAccumInit(&acc, 0, zBuf, n, 0);
va_start(ap,zFormat);
- z = sqlite3_vsnprintf(n, zBuf, zFormat, ap);
+ sqlite3_str_vappendf(&acc, zFormat, ap);
va_end(ap);
- return z;
+ zBuf[acc.nChar] = 0;
+ return zBuf;
}
/*
@@ -34281,13 +34535,15 @@ SQLITE_PRIVATE int sqlite3Int64ToText(i64 v, char *zOut){
}
i = sizeof(zTemp)-2;
zTemp[sizeof(zTemp)-1] = 0;
- do{
- zTemp[i--] = (x%10) + '0';
+ while( 1 /*exit-by-break*/ ){
+ zTemp[i] = (x%10) + '0';
x = x/10;
- }while( x );
- if( v<0 ) zTemp[i--] = '-';
- memcpy(zOut, &zTemp[i+1], sizeof(zTemp)-1-i);
- return sizeof(zTemp)-2-i;
+ if( x==0 ) break;
+ i--;
+ };
+ if( v<0 ) zTemp[--i] = '-';
+ memcpy(zOut, &zTemp[i], sizeof(zTemp)-i);
+ return sizeof(zTemp)-1-i;
}
/*
@@ -34452,7 +34708,9 @@ SQLITE_PRIVATE int sqlite3DecOrHexToI64(const char *z, i64 *pOut){
u = u*16 + sqlite3HexToInt(z[k]);
}
memcpy(pOut, &u, 8);
- return (z[k]==0 && k-i<=16) ? 0 : 2;
+ if( k-i>16 ) return 2;
+ if( z[k]!=0 ) return 1;
+ return 0;
}else
#endif /* SQLITE_OMIT_HEX_INTEGER */
{
@@ -34488,7 +34746,7 @@ SQLITE_PRIVATE int sqlite3GetInt32(const char *zNum, int *pValue){
u32 u = 0;
zNum += 2;
while( zNum[0]=='0' ) zNum++;
- for(i=0; sqlite3Isxdigit(zNum[i]) && i<8; i++){
+ for(i=0; i<8 && sqlite3Isxdigit(zNum[i]); i++){
u = u*16 + sqlite3HexToInt(zNum[i]);
}
if( (u&0x80000000)==0 && sqlite3Isxdigit(zNum[i])==0 ){
@@ -36984,7 +37242,7 @@ SQLITE_PRIVATE int sqlite3KvvfsInit(void){
#endif
/* Use pread() and pwrite() if they are available */
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(__linux__)
# define HAVE_PREAD 1
# define HAVE_PWRITE 1
#endif
@@ -40234,12 +40492,6 @@ static int nfsUnlock(sqlite3_file *id, int eFileLock){
** Seek to the offset passed as the second argument, then read cnt
** bytes into pBuf. Return the number of bytes actually read.
**
-** NB: If you define USE_PREAD or USE_PREAD64, then it might also
-** be necessary to define _XOPEN_SOURCE to be 500. This varies from
-** one system to another. Since SQLite does not define USE_PREAD
-** in any form by default, we will not attempt to define _XOPEN_SOURCE.
-** See tickets #2741 and #2681.
-**
** To avoid stomping the errno value on a failed read the lastErrno value
** is set before returning.
*/
@@ -50266,7 +50518,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -50283,7 +50535,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -50303,7 +50555,7 @@ static int winOpen(
if( isReadWrite ){
int rc2, isRO = 0;
sqlite3BeginBenignMalloc();
- rc2 = winAccess(pVfs, zName, SQLITE_ACCESS_READ, &isRO);
+ rc2 = winAccess(pVfs, zUtf8Name, SQLITE_ACCESS_READ, &isRO);
sqlite3EndBenignMalloc();
if( rc2==SQLITE_OK && isRO ) break;
}
@@ -50526,6 +50778,13 @@ static int winAccess(
OSTRACE(("ACCESS name=%s, flags=%x, pResOut=%p\n",
zFilename, flags, pResOut));
+ if( zFilename==0 ){
+ *pResOut = 0;
+ OSTRACE(("ACCESS name=%s, pResOut=%p, *pResOut=%d, rc=SQLITE_OK\n",
+ zFilename, pResOut, *pResOut));
+ return SQLITE_OK;
+ }
+
zConverted = winConvertFromUtf8Filename(zFilename);
if( zConverted==0 ){
OSTRACE(("ACCESS name=%s, rc=SQLITE_IOERR_NOMEM\n", zFilename));
@@ -52653,7 +52912,7 @@ bitvec_end:
struct PCache {
PgHdr *pDirty, *pDirtyTail; /* List of dirty pages in LRU order */
PgHdr *pSynced; /* Last synced page in dirty page list */
- int nRefSum; /* Sum of ref counts over all pages */
+ i64 nRefSum; /* Sum of ref counts over all pages */
int szCache; /* Configured cache size */
int szSpill; /* Size before spilling occurs */
int szPage; /* Size of every page in this cache */
@@ -52682,11 +52941,15 @@ struct PCache {
PgHdr *pPg;
unsigned char *a;
int j;
- pPg = (PgHdr*)pLower->pExtra;
- printf("%3d: nRef %2d flgs %02x data ", i, pPg->nRef, pPg->flags);
- a = (unsigned char *)pLower->pBuf;
- for(j=0; j<12; j++) printf("%02x", a[j]);
- printf(" ptr %p\n", pPg);
+ if( pLower==0 ){
+ printf("%3d: NULL\n", i);
+ }else{
+ pPg = (PgHdr*)pLower->pExtra;
+ printf("%3d: nRef %2lld flgs %02x data ", i, pPg->nRef, pPg->flags);
+ a = (unsigned char *)pLower->pBuf;
+ for(j=0; j<12; j++) printf("%02x", a[j]);
+ printf(" ptr %p\n", pPg);
+ }
}
static void pcacheDump(PCache *pCache){
int N;
@@ -52699,9 +52962,8 @@ struct PCache {
if( N>sqlite3PcacheMxDump ) N = sqlite3PcacheMxDump;
for(i=1; i<=N; i++){
pLower = sqlite3GlobalConfig.pcache2.xFetch(pCache->pCache, i, 0);
- if( pLower==0 ) continue;
pcachePageTrace(i, pLower);
- if( ((PgHdr*)pLower)->pPage==0 ){
+ if( pLower && ((PgHdr*)pLower)->pPage==0 ){
sqlite3GlobalConfig.pcache2.xUnpin(pCache->pCache, pLower, 0);
}
}
@@ -53427,14 +53689,14 @@ SQLITE_PRIVATE PgHdr *sqlite3PcacheDirtyList(PCache *pCache){
** This is not the total number of pages referenced, but the sum of the
** reference count for all pages.
*/
-SQLITE_PRIVATE int sqlite3PcacheRefCount(PCache *pCache){
+SQLITE_PRIVATE i64 sqlite3PcacheRefCount(PCache *pCache){
return pCache->nRefSum;
}
/*
** Return the number of references to the page supplied as an argument.
*/
-SQLITE_PRIVATE int sqlite3PcachePageRefcount(PgHdr *p){
+SQLITE_PRIVATE i64 sqlite3PcachePageRefcount(PgHdr *p){
return p->nRef;
}
@@ -58089,6 +58351,8 @@ static int pager_truncate(Pager *pPager, Pgno nPage){
int rc = SQLITE_OK;
assert( pPager->eState!=PAGER_ERROR );
assert( pPager->eState!=PAGER_READER );
+ PAGERTRACE(("Truncate %d npage %u\n", PAGERID(pPager), nPage));
+
if( isOpen(pPager->fd)
&& (pPager->eState>=PAGER_WRITER_DBMOD || pPager->eState==PAGER_OPEN)
@@ -61006,6 +61270,10 @@ static int getPageNormal(
if( !isOpen(pPager->fd) || pPager->dbSize<pgno || noContent ){
if( pgno>pPager->mxPgno ){
rc = SQLITE_FULL;
+ if( pgno<=pPager->dbSize ){
+ sqlite3PcacheRelease(pPg);
+ pPg = 0;
+ }
goto pager_acquire_err;
}
if( noContent ){
@@ -61170,10 +61438,12 @@ SQLITE_PRIVATE DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno){
/*
** Release a page reference.
**
-** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be
-** used if we know that the page being released is not the last page.
+** The sqlite3PagerUnref() and sqlite3PagerUnrefNotNull() may only be used
+** if we know that the page being released is not the last reference to page1.
** The btree layer always holds page1 open until the end, so these first
-** to routines can be used to release any page other than BtShared.pPage1.
+** two routines can be used to release any page other than BtShared.pPage1.
+** The assert() at tag-20230419-2 proves that this constraint is always
+** honored.
**
** Use sqlite3PagerUnrefPageOne() to release page1. This latter routine
** checks the total number of outstanding pages and if the number of
@@ -61189,7 +61459,7 @@ SQLITE_PRIVATE void sqlite3PagerUnrefNotNull(DbPage *pPg){
sqlite3PcacheRelease(pPg);
}
/* Do not use this routine to release the last reference to page1 */
- assert( sqlite3PcacheRefCount(pPager->pPCache)>0 );
+ assert( sqlite3PcacheRefCount(pPager->pPCache)>0 ); /* tag-20230419-2 */
}
SQLITE_PRIVATE void sqlite3PagerUnref(DbPage *pPg){
if( pPg ) sqlite3PagerUnrefNotNull(pPg);
@@ -62949,13 +63219,15 @@ SQLITE_PRIVATE int sqlite3PagerWalSupported(Pager *pPager){
*/
static int pagerExclusiveLock(Pager *pPager){
int rc; /* Return code */
+ u8 eOrigLock; /* Original lock */
- assert( pPager->eLock==SHARED_LOCK || pPager->eLock==EXCLUSIVE_LOCK );
+ assert( pPager->eLock>=SHARED_LOCK );
+ eOrigLock = pPager->eLock;
rc = pagerLockDb(pPager, EXCLUSIVE_LOCK);
if( rc!=SQLITE_OK ){
/* If the attempt to grab the exclusive lock failed, release the
** pending lock that may have been obtained instead. */
- pagerUnlockDb(pPager, SHARED_LOCK);
+ pagerUnlockDb(pPager, eOrigLock);
}
return rc;
@@ -63960,19 +64232,40 @@ static void walChecksumBytes(
assert( nByte>=8 );
assert( (nByte&0x00000007)==0 );
assert( nByte<=65536 );
+ assert( nByte%4==0 );
- if( nativeCksum ){
+ if( !nativeCksum ){
+ do {
+ s1 += BYTESWAP32(aData[0]) + s2;
+ s2 += BYTESWAP32(aData[1]) + s1;
+ aData += 2;
+ }while( aData<aEnd );
+ }else if( nByte%64==0 ){
do {
s1 += *aData++ + s2;
s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
}while( aData<aEnd );
}else{
do {
- s1 += BYTESWAP32(aData[0]) + s2;
- s2 += BYTESWAP32(aData[1]) + s1;
- aData += 2;
+ s1 += *aData++ + s2;
+ s2 += *aData++ + s1;
}while( aData<aEnd );
}
+ assert( aData==aEnd );
aOut[0] = s1;
aOut[1] = s2;
@@ -66903,7 +67196,9 @@ SQLITE_PRIVATE int sqlite3WalFrames(
if( rc ) return rc;
}
}
- assert( (int)pWal->szPage==szPage );
+ if( (int)pWal->szPage!=szPage ){
+ return SQLITE_CORRUPT_BKPT; /* TH3 test case: cov1/corrupt155.test */
+ }
/* Setup information needed to write frames into the WAL */
w.pWal = pWal;
@@ -67563,7 +67858,7 @@ SQLITE_PRIVATE sqlite3_file *sqlite3WalFile(Wal *pWal){
** byte are used. The integer consists of all bytes that have bit 8 set and
** the first byte with bit 8 clear. The most significant byte of the integer
** appears first. A variable-length integer may not be more than 9 bytes long.
-** As a special case, all 8 bytes of the 9th byte are used as data. This
+** As a special case, all 8 bits of the 9th byte are used as data. This
** allows a 64-bit integer to be encoded in 9 bytes.
**
** 0x00 becomes 0x00000000
@@ -67947,7 +68242,7 @@ struct BtCursor {
#define BTCF_WriteFlag 0x01 /* True if a write cursor */
#define BTCF_ValidNKey 0x02 /* True if info.nKey is valid */
#define BTCF_ValidOvfl 0x04 /* True if aOverflow is valid */
-#define BTCF_AtLast 0x08 /* Cursor is pointing ot the last entry */
+#define BTCF_AtLast 0x08 /* Cursor is pointing to the last entry */
#define BTCF_Incrblob 0x10 /* True if an incremental I/O handle */
#define BTCF_Multiple 0x20 /* Maybe another cursor on the same btree */
#define BTCF_Pinned 0x40 /* Cursor is busy and cannot be moved */
@@ -68092,8 +68387,9 @@ struct IntegrityCk {
int rc; /* SQLITE_OK, SQLITE_NOMEM, or SQLITE_INTERRUPT */
u32 nStep; /* Number of steps into the integrity_check process */
const char *zPfx; /* Error message prefix */
- Pgno v1; /* Value for first %u substitution in zPfx */
- int v2; /* Value for second %d substitution in zPfx */
+ Pgno v0; /* Value for first %u substitution in zPfx (root page) */
+ Pgno v1; /* Value for second %u substitution in zPfx (current pg) */
+ int v2; /* Value for third %d substitution in zPfx */
StrAccum errMsg; /* Accumulate the error message text here */
u32 *heap; /* Min-heap used for analyzing cell coverage */
sqlite3 *db; /* Database connection running the check */
@@ -68556,8 +68852,8 @@ SQLITE_PRIVATE sqlite3_uint64 sqlite3BtreeSeekCount(Btree *pBt){
int corruptPageError(int lineno, MemPage *p){
char *zMsg;
sqlite3BeginBenignMalloc();
- zMsg = sqlite3_mprintf("database corruption page %d of %s",
- (int)p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
+ zMsg = sqlite3_mprintf("database corruption page %u of %s",
+ p->pgno, sqlite3PagerFilename(p->pBt->pPager, 0)
);
sqlite3EndBenignMalloc();
if( zMsg ){
@@ -69366,8 +69662,25 @@ SQLITE_PRIVATE int sqlite3BtreeCursorRestore(BtCursor *pCur, int *pDifferentRow)
*/
SQLITE_PRIVATE void sqlite3BtreeCursorHint(BtCursor *pCur, int eHintType, ...){
/* Used only by system that substitute their own storage engine */
+#ifdef SQLITE_DEBUG
+ if( ALWAYS(eHintType==BTREE_HINT_RANGE) ){
+ va_list ap;
+ Expr *pExpr;
+ Walker w;
+ memset(&w, 0, sizeof(w));
+ w.xExprCallback = sqlite3CursorRangeHintExprCheck;
+ va_start(ap, eHintType);
+ pExpr = va_arg(ap, Expr*);
+ w.u.aMem = va_arg(ap, Mem*);
+ va_end(ap);
+ assert( pExpr!=0 );
+ assert( w.u.aMem!=0 );
+ sqlite3WalkExpr(&w, pExpr);
+ }
+#endif /* SQLITE_DEBUG */
}
-#endif
+#endif /* SQLITE_ENABLE_CURSOR_HINTS */
+
/*
** Provide flag hints to the cursor.
@@ -69452,7 +69765,7 @@ static void ptrmapPut(BtShared *pBt, Pgno key, u8 eType, Pgno parent, int *pRC){
pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);
if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){
- TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));
+ TRACE(("PTRMAP_UPDATE: %u->(%u,%u)\n", key, eType, parent));
*pRC= rc = sqlite3PagerWrite(pDbPage);
if( rc==SQLITE_OK ){
pPtrmap[offset] = eType;
@@ -69651,27 +69964,31 @@ static void btreeParseCellPtr(
iKey = *pIter;
if( iKey>=0x80 ){
u8 x;
- iKey = ((iKey&0x7f)<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x =*++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x10204000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<7) | ((x = *++pIter) & 0x7f);
+ iKey = (iKey<<7) ^ 0x4000 ^ (x = *++pIter);
if( x>=0x80 ){
- iKey = (iKey<<8) | (*++pIter);
+ iKey = (iKey<<8) ^ 0x8000 ^ (*++pIter);
}
}
}
}
}
+ }else{
+ iKey ^= 0x204000;
}
+ }else{
+ iKey ^= 0x4000;
}
}
pIter++;
@@ -69748,10 +70065,11 @@ static void btreeParseCell(
**
** cellSizePtrNoPayload() => table internal nodes
** cellSizePtrTableLeaf() => table leaf nodes
-** cellSizePtr() => all index nodes & table leaf nodes
+** cellSizePtr() => index internal nodes
+** cellSizeIdxLeaf() => index leaf nodes
*/
static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
- u8 *pIter = pCell + pPage->childPtrSize; /* For looping over bytes of pCell */
+ u8 *pIter = pCell + 4; /* For looping over bytes of pCell */
u8 *pEnd; /* End mark for a varint */
u32 nSize; /* Size value to return */
@@ -69764,6 +70082,49 @@ static u16 cellSizePtr(MemPage *pPage, u8 *pCell){
pPage->xParseCell(pPage, pCell, &debuginfo);
#endif
+ assert( pPage->childPtrSize==4 );
+ nSize = *pIter;
+ if( nSize>=0x80 ){
+ pEnd = &pIter[8];
+ nSize &= 0x7f;
+ do{
+ nSize = (nSize<<7) | (*++pIter & 0x7f);
+ }while( *(pIter)>=0x80 && pIter<pEnd );
+ }
+ pIter++;
+ testcase( nSize==pPage->maxLocal );
+ testcase( nSize==(u32)pPage->maxLocal+1 );
+ if( nSize<=pPage->maxLocal ){
+ nSize += (u32)(pIter - pCell);
+ assert( nSize>4 );
+ }else{
+ int minLocal = pPage->minLocal;
+ nSize = minLocal + (nSize - minLocal) % (pPage->pBt->usableSize - 4);
+ testcase( nSize==pPage->maxLocal );
+ testcase( nSize==(u32)pPage->maxLocal+1 );
+ if( nSize>pPage->maxLocal ){
+ nSize = minLocal;
+ }
+ nSize += 4 + (u16)(pIter - pCell);
+ }
+ assert( nSize==debuginfo.nSize || CORRUPT_DB );
+ return (u16)nSize;
+}
+static u16 cellSizePtrIdxLeaf(MemPage *pPage, u8 *pCell){
+ u8 *pIter = pCell; /* For looping over bytes of pCell */
+ u8 *pEnd; /* End mark for a varint */
+ u32 nSize; /* Size value to return */
+
+#ifdef SQLITE_DEBUG
+ /* The value returned by this function should always be the same as
+ ** the (CellInfo.nSize) value found by doing a full parse of the
+ ** cell. If SQLITE_DEBUG is defined, an assert() at the bottom of
+ ** this function verifies that this invariant is not violated. */
+ CellInfo debuginfo;
+ pPage->xParseCell(pPage, pCell, &debuginfo);
+#endif
+
+ assert( pPage->childPtrSize==0 );
nSize = *pIter;
if( nSize>=0x80 ){
pEnd = &pIter[8];
@@ -70000,10 +70361,10 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
/* These conditions have already been verified in btreeInitPage()
** if PRAGMA cell_size_check=ON.
*/
- if( pc<iCellStart || pc>iCellLast ){
+ if( pc>iCellLast ){
return SQLITE_CORRUPT_PAGE(pPage);
}
- assert( pc>=iCellStart && pc<=iCellLast );
+ assert( pc>=0 && pc<=iCellLast );
size = pPage->xCellSize(pPage, &src[pc]);
cbrk -= size;
if( cbrk<iCellStart || pc+size>usableSize ){
@@ -70118,7 +70479,7 @@ static u8 *pageFindSlot(MemPage *pPg, int nByte, int *pRc){
** allocation is being made in order to insert a new cell, so we will
** also end up needing a new cell pointer.
*/
-static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
+static SQLITE_INLINE int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
const int hdr = pPage->hdrOffset; /* Local cache of pPage->hdrOffset */
u8 * const data = pPage->aData; /* Local cache of pPage->aData */
int top; /* First byte of cell content area */
@@ -70144,13 +70505,14 @@ static int allocateSpace(MemPage *pPage, int nByte, int *pIdx){
** integer, so a value of 0 is used in its place. */
pTmp = &data[hdr+5];
top = get2byte(pTmp);
- assert( top<=(int)pPage->pBt->usableSize ); /* by btreeComputeFreeSpace() */
if( gap>top ){
if( top==0 && pPage->pBt->usableSize==65536 ){
top = 65536;
}else{
return SQLITE_CORRUPT_PAGE(pPage);
}
+ }else if( top>(int)pPage->pBt->usableSize ){
+ return SQLITE_CORRUPT_PAGE(pPage);
}
/* If there is enough space between gap and top for one more cell pointer,
@@ -70233,7 +70595,7 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
assert( CORRUPT_DB || iEnd <= pPage->pBt->usableSize );
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( iSize>=4 ); /* Minimum cell size is 4 */
- assert( iStart<=pPage->pBt->usableSize-4 );
+ assert( CORRUPT_DB || iStart<=pPage->pBt->usableSize-4 );
/* The list of freeblocks must be in ascending order. Find the
** spot on the list where iStart should be inserted.
@@ -70290,6 +70652,11 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}
pTmp = &data[hdr+5];
x = get2byte(pTmp);
+ if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
+ /* Overwrite deleted information with zeros when the secure_delete
+ ** option is enabled */
+ memset(&data[iStart], 0, iSize);
+ }
if( iStart<=x ){
/* The new freeblock is at the beginning of the cell content area,
** so just extend the cell content area rather than create another
@@ -70301,14 +70668,9 @@ static int freeSpace(MemPage *pPage, u16 iStart, u16 iSize){
}else{
/* Insert the new freeblock into the freelist */
put2byte(&data[iPtr], iStart);
+ put2byte(&data[iStart], iFreeBlk);
+ put2byte(&data[iStart+2], iSize);
}
- if( pPage->pBt->btsFlags & BTS_FAST_SECURE ){
- /* Overwrite deleted information with zeros when the secure_delete
- ** option is enabled */
- memset(&data[iStart], 0, iSize);
- }
- put2byte(&data[iStart], iFreeBlk);
- put2byte(&data[iStart+2], iSize);
pPage->nFree += iOrigSize;
return SQLITE_OK;
}
@@ -70345,14 +70707,14 @@ static int decodeFlags(MemPage *pPage, int flagByte){
}else if( flagByte==(PTF_ZERODATA | PTF_LEAF) ){
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
- pPage->xCellSize = cellSizePtr;
+ pPage->xCellSize = cellSizePtrIdxLeaf;
pPage->xParseCell = btreeParseCellPtrIndex;
pPage->maxLocal = pBt->maxLocal;
pPage->minLocal = pBt->minLocal;
}else{
pPage->intKey = 0;
pPage->intKeyLeaf = 0;
- pPage->xCellSize = cellSizePtr;
+ pPage->xCellSize = cellSizePtrIdxLeaf;
pPage->xParseCell = btreeParseCellPtrIndex;
return SQLITE_CORRUPT_PAGE(pPage);
}
@@ -72218,7 +72580,7 @@ static int relocatePage(
if( iDbPage<3 ) return SQLITE_CORRUPT_BKPT;
/* Move page iDbPage from its current location to page number iFreePage */
- TRACE(("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n",
+ TRACE(("AUTOVACUUM: Moving %u to free page %u (ptr page %u type %u)\n",
iDbPage, iFreePage, iPtrPage, eType));
rc = sqlite3PagerMovepage(pPager, pDbPage->pDbPage, iFreePage, isCommit);
if( rc!=SQLITE_OK ){
@@ -74504,7 +74866,8 @@ static SQLITE_NOINLINE int btreeNext(BtCursor *pCur){
pPage = pCur->pPage;
idx = ++pCur->ix;
- if( NEVER(!pPage->isInit) || sqlite3FaultSim(412) ){
+ if( sqlite3FaultSim(412) ) pPage->isInit = 0;
+ if( !pPage->isInit ){
return SQLITE_CORRUPT_BKPT;
}
@@ -74767,7 +75130,7 @@ static int allocateBtreePage(
memcpy(&pPage1->aData[32], &pTrunk->aData[0], 4);
*ppPage = pTrunk;
pTrunk = 0;
- TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
+ TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1));
}else if( k>(u32)(pBt->usableSize/4 - 2) ){
/* Value of k is out of range. Database corruption */
rc = SQLITE_CORRUPT_PGNO(iTrunk);
@@ -74833,7 +75196,7 @@ static int allocateBtreePage(
}
}
pTrunk = 0;
- TRACE(("ALLOCATE: %d trunk - %d free pages left\n", *pPgno, n-1));
+ TRACE(("ALLOCATE: %u trunk - %u free pages left\n", *pPgno, n-1));
#endif
}else if( k>0 ){
/* Extract a leaf from the trunk */
@@ -74878,8 +75241,8 @@ static int allocateBtreePage(
){
int noContent;
*pPgno = iPage;
- TRACE(("ALLOCATE: %d was leaf %d of %d on trunk %d"
- ": %d more free pages\n",
+ TRACE(("ALLOCATE: %u was leaf %u of %u on trunk %u"
+ ": %u more free pages\n",
*pPgno, closest+1, k, pTrunk->pgno, n-1));
rc = sqlite3PagerWrite(pTrunk->pDbPage);
if( rc ) goto end_allocate_page;
@@ -74935,7 +75298,7 @@ static int allocateBtreePage(
** becomes a new pointer-map page, the second is used by the caller.
*/
MemPage *pPg = 0;
- TRACE(("ALLOCATE: %d from end of file (pointer-map page)\n", pBt->nPage));
+ TRACE(("ALLOCATE: %u from end of file (pointer-map page)\n", pBt->nPage));
assert( pBt->nPage!=PENDING_BYTE_PAGE(pBt) );
rc = btreeGetUnusedPage(pBt, pBt->nPage, &pPg, bNoContent);
if( rc==SQLITE_OK ){
@@ -74958,7 +75321,7 @@ static int allocateBtreePage(
releasePage(*ppPage);
*ppPage = 0;
}
- TRACE(("ALLOCATE: %d from end of file\n", *pPgno));
+ TRACE(("ALLOCATE: %u from end of file\n", *pPgno));
}
assert( CORRUPT_DB || *pPgno!=PENDING_BYTE_PAGE(pBt) );
@@ -75086,7 +75449,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
}
rc = btreeSetHasContent(pBt, iPage);
}
- TRACE(("FREE-PAGE: %d leaf on trunk page %d\n",pPage->pgno,pTrunk->pgno));
+ TRACE(("FREE-PAGE: %u leaf on trunk page %u\n",pPage->pgno,pTrunk->pgno));
goto freepage_out;
}
}
@@ -75107,7 +75470,7 @@ static int freePage2(BtShared *pBt, MemPage *pMemPage, Pgno iPage){
put4byte(pPage->aData, iTrunk);
put4byte(&pPage->aData[4], 0);
put4byte(&pPage1->aData[32], iPage);
- TRACE(("FREE-PAGE: %d new trunk page replacing %d\n", pPage->pgno, iTrunk));
+ TRACE(("FREE-PAGE: %u new trunk page replacing %u\n", pPage->pgno, iTrunk));
freepage_out:
if( pPage ){
@@ -75466,6 +75829,14 @@ static void dropCell(MemPage *pPage, int idx, int sz, int *pRC){
** in pTemp or the original pCell) and also record its index.
** Allocating a new entry in pPage->aCell[] implies that
** pPage->nOverflow is incremented.
+**
+** The insertCellFast() routine below works exactly the same as
+** insertCell() except that it lacks the pTemp and iChild parameters
+** which are assumed zero. Other than that, the two routines are the
+** same.
+**
+** Fixes or enhancements to this routine should be reflected in
+** insertCellFast()!
*/
static int insertCell(
MemPage *pPage, /* Page into which we are copying */
@@ -75488,14 +75859,103 @@ static int insertCell(
assert( sqlite3_mutex_held(pPage->pBt->mutex) );
assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
assert( pPage->nFree>=0 );
+ assert( iChild>0 );
if( pPage->nOverflow || sz+2>pPage->nFree ){
if( pTemp ){
memcpy(pTemp, pCell, sz);
pCell = pTemp;
}
- if( iChild ){
- put4byte(pCell, iChild);
+ put4byte(pCell, iChild);
+ j = pPage->nOverflow++;
+ /* Comparison against ArraySize-1 since we hold back one extra slot
+ ** as a contingency. In other words, never need more than 3 overflow
+ ** slots but 4 are allocated, just to be safe. */
+ assert( j < ArraySize(pPage->apOvfl)-1 );
+ pPage->apOvfl[j] = pCell;
+ pPage->aiOvfl[j] = (u16)i;
+
+ /* When multiple overflows occur, they are always sequential and in
+ ** sorted order. This invariants arise because multiple overflows can
+ ** only occur when inserting divider cells into the parent page during
+ ** balancing, and the dividers are adjacent and sorted.
+ */
+ assert( j==0 || pPage->aiOvfl[j-1]<(u16)i ); /* Overflows in sorted order */
+ assert( j==0 || i==pPage->aiOvfl[j-1]+1 ); /* Overflows are sequential */
+ }else{
+ int rc = sqlite3PagerWrite(pPage->pDbPage);
+ if( NEVER(rc!=SQLITE_OK) ){
+ return rc;
+ }
+ assert( sqlite3PagerIswriteable(pPage->pDbPage) );
+ data = pPage->aData;
+ assert( &data[pPage->cellOffset]==pPage->aCellIdx );
+ rc = allocateSpace(pPage, sz, &idx);
+ if( rc ){ return rc; }
+ /* The allocateSpace() routine guarantees the following properties
+ ** if it returns successfully */
+ assert( idx >= 0 );
+ assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
+ assert( idx+sz <= (int)pPage->pBt->usableSize );
+ pPage->nFree -= (u16)(2 + sz);
+ /* In a corrupt database where an entry in the cell index section of
+ ** a btree page has a value of 3 or less, the pCell value might point
+ ** as many as 4 bytes in front of the start of the aData buffer for
+ ** the source page. Make sure this does not cause problems by not
+ ** reading the first 4 bytes */
+ memcpy(&data[idx+4], pCell+4, sz-4);
+ put4byte(&data[idx], iChild);
+ pIns = pPage->aCellIdx + i*2;
+ memmove(pIns+2, pIns, 2*(pPage->nCell - i));
+ put2byte(pIns, idx);
+ pPage->nCell++;
+ /* increment the cell count */
+ if( (++data[pPage->hdrOffset+4])==0 ) data[pPage->hdrOffset+3]++;
+ assert( get2byte(&data[pPage->hdrOffset+3])==pPage->nCell || CORRUPT_DB );
+#ifndef SQLITE_OMIT_AUTOVACUUM
+ if( pPage->pBt->autoVacuum ){
+ int rc2 = SQLITE_OK;
+ /* The cell may contain a pointer to an overflow page. If so, write
+ ** the entry for the overflow page into the pointer map.
+ */
+ ptrmapPutOvflPtr(pPage, pPage, pCell, &rc2);
+ if( rc2 ) return rc2;
}
+#endif
+ }
+ return SQLITE_OK;
+}
+
+/*
+** This variant of insertCell() assumes that the pTemp and iChild
+** parameters are both zero. Use this variant in sqlite3BtreeInsert()
+** for performance improvement, and also so that this variant is only
+** called from that one place, and is thus inlined, and thus runs must
+** faster.
+**
+** Fixes or enhancements to this routine should be reflected into
+** the insertCell() routine.
+*/
+static int insertCellFast(
+ MemPage *pPage, /* Page into which we are copying */
+ int i, /* New cell becomes the i-th cell of the page */
+ u8 *pCell, /* Content of the new cell */
+ int sz /* Bytes of content in pCell */
+){
+ int idx = 0; /* Where to write new cell content in data[] */
+ int j; /* Loop counter */
+ u8 *data; /* The content of the whole page */
+ u8 *pIns; /* The point in pPage->aCellIdx[] where no cell inserted */
+
+ assert( i>=0 && i<=pPage->nCell+pPage->nOverflow );
+ assert( MX_CELL(pPage->pBt)<=10921 );
+ assert( pPage->nCell<=MX_CELL(pPage->pBt) || CORRUPT_DB );
+ assert( pPage->nOverflow<=ArraySize(pPage->apOvfl) );
+ assert( ArraySize(pPage->apOvfl)==ArraySize(pPage->aiOvfl) );
+ assert( sqlite3_mutex_held(pPage->pBt->mutex) );
+ assert( sz==pPage->xCellSize(pPage, pCell) || CORRUPT_DB );
+ assert( pPage->nFree>=0 );
+ assert( pPage->nOverflow==0 );
+ if( sz+2>pPage->nFree ){
j = pPage->nOverflow++;
/* Comparison against ArraySize-1 since we hold back one extra slot
** as a contingency. In other words, never need more than 3 overflow
@@ -75527,17 +75987,7 @@ static int insertCell(
assert( idx >= pPage->cellOffset+2*pPage->nCell+2 || CORRUPT_DB );
assert( idx+sz <= (int)pPage->pBt->usableSize );
pPage->nFree -= (u16)(2 + sz);
- if( iChild ){
- /* In a corrupt database where an entry in the cell index section of
- ** a btree page has a value of 3 or less, the pCell value might point
- ** as many as 4 bytes in front of the start of the aData buffer for
- ** the source page. Make sure this does not cause problems by not
- ** reading the first 4 bytes */
- memcpy(&data[idx+4], pCell+4, sz-4);
- put4byte(&data[idx], iChild);
- }else{
- memcpy(&data[idx], pCell, sz);
- }
+ memcpy(&data[idx], pCell, sz);
pIns = pPage->aCellIdx + i*2;
memmove(pIns+2, pIns, 2*(pPage->nCell - i));
put2byte(pIns, idx);
@@ -75722,7 +76172,7 @@ static int rebuildPage(
assert( i<iEnd );
j = get2byte(&aData[hdr+5]);
- if( j>(u32)usableSize ){ j = 0; }
+ if( NEVER(j>(u32)usableSize) ){ j = 0; }
memcpy(&pTmp[j], &aData[j], usableSize - j);
for(k=0; pCArray->ixNx[k]<=i && ALWAYS(k<NB*2); k++){}
@@ -75866,42 +76316,50 @@ static int pageFreeArray(
u8 * const pEnd = &aData[pPg->pBt->usableSize];
u8 * const pStart = &aData[pPg->hdrOffset + 8 + pPg->childPtrSize];
int nRet = 0;
- int i;
+ int i, j;
int iEnd = iFirst + nCell;
- u8 *pFree = 0; /* \__ Parameters for pending call to */
- int szFree = 0; /* / freeSpace() */
+ int nFree = 0;
+ int aOfst[10];
+ int aAfter[10];
for(i=iFirst; i<iEnd; i++){
u8 *pCell = pCArray->apCell[i];
if( SQLITE_WITHIN(pCell, pStart, pEnd) ){
int sz;
+ int iAfter;
+ int iOfst;
/* No need to use cachedCellSize() here. The sizes of all cells that
** are to be freed have already been computing while deciding which
** cells need freeing */
sz = pCArray->szCell[i]; assert( sz>0 );
- if( pFree!=(pCell + sz) ){
- if( pFree ){
- assert( pFree>aData && (pFree - aData)<65536 );
- freeSpace(pPg, (u16)(pFree - aData), szFree);
- }
- pFree = pCell;
- szFree = sz;
- if( pFree+sz>pEnd ){
- return 0;
+ iOfst = (u16)(pCell - aData);
+ iAfter = iOfst+sz;
+ for(j=0; j<nFree; j++){
+ if( aOfst[j]==iAfter ){
+ aOfst[j] = iOfst;
+ break;
+ }else if( aAfter[j]==iOfst ){
+ aAfter[j] = iAfter;
+ break;
}
- }else{
- /* The current cell is adjacent to and before the pFree cell.
- ** Combine the two regions into one to reduce the number of calls
- ** to freeSpace(). */
- pFree = pCell;
- szFree += sz;
+ }
+ if( j>=nFree ){
+ if( nFree>=(int)(sizeof(aOfst)/sizeof(aOfst[0])) ){
+ for(j=0; j<nFree; j++){
+ freeSpace(pPg, aOfst[j], aAfter[j]-aOfst[j]);
+ }
+ nFree = 0;
+ }
+ aOfst[nFree] = iOfst;
+ aAfter[nFree] = iAfter;
+ if( &aData[iAfter]>pEnd ) return 0;
+ nFree++;
}
nRet++;
}
}
- if( pFree ){
- assert( pFree>aData && (pFree - aData)<65536 );
- freeSpace(pPg, (u16)(pFree - aData), szFree);
+ for(j=0; j<nFree; j++){
+ freeSpace(pPg, aOfst[j], aAfter[j]-aOfst[j]);
}
return nRet;
}
@@ -75954,9 +76412,9 @@ static int editPage(
nCell -= nTail;
}
- pData = &aData[get2byteNotZero(&aData[hdr+5])];
+ pData = &aData[get2byte(&aData[hdr+5])];
if( pData<pBegin ) goto editpage_fail;
- if( pData>pPg->aDataEnd ) goto editpage_fail;
+ if( NEVER(pData>pPg->aDataEnd) ) goto editpage_fail;
/* Add cells to the start of the page */
if( iNew<iOld ){
@@ -76693,7 +77151,7 @@ static int balance_nonroot(
** that page.
*/
assert( cntNew[0]>0 || (pParent->pgno==1 && pParent->nCell==0) || CORRUPT_DB);
- TRACE(("BALANCE: old: %d(nc=%d) %d(nc=%d) %d(nc=%d)\n",
+ TRACE(("BALANCE: old: %u(nc=%u) %u(nc=%u) %u(nc=%u)\n",
apOld[0]->pgno, apOld[0]->nCell,
nOld>=2 ? apOld[1]->pgno : 0, nOld>=2 ? apOld[1]->nCell : 0,
nOld>=3 ? apOld[2]->pgno : 0, nOld>=3 ? apOld[2]->nCell : 0
@@ -76777,8 +77235,8 @@ static int balance_nonroot(
}
}
- TRACE(("BALANCE: new: %d(%d nc=%d) %d(%d nc=%d) %d(%d nc=%d) "
- "%d(%d nc=%d) %d(%d nc=%d)\n",
+ TRACE(("BALANCE: new: %u(%u nc=%u) %u(%u nc=%u) %u(%u nc=%u) "
+ "%u(%u nc=%u) %u(%u nc=%u)\n",
apNew[0]->pgno, szNew[0], cntNew[0],
nNew>=2 ? apNew[1]->pgno : 0, nNew>=2 ? szNew[1] : 0,
nNew>=2 ? cntNew[1] - cntNew[0] - !leafData : 0,
@@ -77023,7 +77481,7 @@ static int balance_nonroot(
}
assert( pParent->isInit );
- TRACE(("BALANCE: finished: old=%d new=%d cells=%d\n",
+ TRACE(("BALANCE: finished: old=%u new=%u cells=%u\n",
nOld, nNew, b.nCell));
/* Free any old pages that were not reused as new pages.
@@ -77108,7 +77566,7 @@ static int balance_deeper(MemPage *pRoot, MemPage **ppChild){
assert( sqlite3PagerIswriteable(pRoot->pDbPage) );
assert( pChild->nCell==pRoot->nCell || CORRUPT_DB );
- TRACE(("BALANCE: copy root %d into %d\n", pRoot->pgno, pChild->pgno));
+ TRACE(("BALANCE: copy root %u into %u\n", pRoot->pgno, pChild->pgno));
/* Copy the overflow cells from pRoot to pChild */
memcpy(pChild->aiOvfl, pRoot->aiOvfl,
@@ -77591,7 +78049,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
}
}
assert( pCur->eState==CURSOR_VALID
- || (pCur->eState==CURSOR_INVALID && loc) );
+ || (pCur->eState==CURSOR_INVALID && loc) || CORRUPT_DB );
pPage = pCur->pPage;
assert( pPage->intKey || pX->nKey>=0 || (flags & BTREE_PREFORMAT) );
@@ -77606,7 +78064,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
if( rc ) return rc;
}
- TRACE(("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n",
+ TRACE(("INSERT: table=%u nkey=%lld ndata=%u page=%u %s\n",
pCur->pgnoRoot, pX->nKey, pX->nData, pPage->pgno,
loc==0 ? "overwrite" : "new entry"));
assert( pPage->isInit || CORRUPT_DB );
@@ -77633,6 +78091,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
assert( szNew==pPage->xCellSize(pPage, newCell) );
assert( szNew <= MX_CELL_SIZE(p->pBt) );
idx = pCur->ix;
+ pCur->info.nSize = 0;
if( loc==0 ){
CellInfo info;
assert( idx>=0 );
@@ -77681,7 +78140,7 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
}else{
assert( pPage->leaf );
}
- rc = insertCell(pPage, idx, newCell, szNew, 0, 0);
+ rc = insertCellFast(pPage, idx, newCell, szNew);
assert( pPage->nOverflow==0 || rc==SQLITE_OK );
assert( rc!=SQLITE_OK || pPage->nCell>0 || pPage->nOverflow>0 );
@@ -77705,7 +78164,6 @@ SQLITE_PRIVATE int sqlite3BtreeInsert(
** larger than the largest existing key, it is possible to insert the
** row without seeking the cursor. This can be a big performance boost.
*/
- pCur->info.nSize = 0;
if( pPage->nOverflow ){
assert( rc==SQLITE_OK );
pCur->curFlags &= ~(BTCF_ValidNKey);
@@ -77906,6 +78364,9 @@ SQLITE_PRIVATE int sqlite3BtreeDelete(BtCursor *pCur, u8 flags){
if( pPage->nFree<0 && btreeComputeFreeSpace(pPage) ){
return SQLITE_CORRUPT_BKPT;
}
+ if( pCell<&pPage->aCellIdx[pPage->nCell] ){
+ return SQLITE_CORRUPT_BKPT;
+ }
/* If the BTREE_SAVEPOSITION bit is on, then the cursor position must
** be preserved following this delete operation. If the current delete
@@ -78654,7 +79115,8 @@ static void checkAppendMsg(
sqlite3_str_append(&pCheck->errMsg, "\n", 1);
}
if( pCheck->zPfx ){
- sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx, pCheck->v1, pCheck->v2);
+ sqlite3_str_appendf(&pCheck->errMsg, pCheck->zPfx,
+ pCheck->v0, pCheck->v1, pCheck->v2);
}
sqlite3_str_vappendf(&pCheck->errMsg, zFormat, ap);
va_end(ap);
@@ -78694,11 +79156,11 @@ static void setPageReferenced(IntegrityCk *pCheck, Pgno iPg){
*/
static int checkRef(IntegrityCk *pCheck, Pgno iPage){
if( iPage>pCheck->nPage || iPage==0 ){
- checkAppendMsg(pCheck, "invalid page number %d", iPage);
+ checkAppendMsg(pCheck, "invalid page number %u", iPage);
return 1;
}
if( getPageReferenced(pCheck, iPage) ){
- checkAppendMsg(pCheck, "2nd reference to page %d", iPage);
+ checkAppendMsg(pCheck, "2nd reference to page %u", iPage);
return 1;
}
setPageReferenced(pCheck, iPage);
@@ -78724,13 +79186,13 @@ static void checkPtrmap(
rc = ptrmapGet(pCheck->pBt, iChild, &ePtrmapType, &iPtrmapParent);
if( rc!=SQLITE_OK ){
if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ) checkOom(pCheck);
- checkAppendMsg(pCheck, "Failed to read ptrmap key=%d", iChild);
+ checkAppendMsg(pCheck, "Failed to read ptrmap key=%u", iChild);
return;
}
if( ePtrmapType!=eType || iPtrmapParent!=iParent ){
checkAppendMsg(pCheck,
- "Bad ptr map entry key=%d expected=(%d,%d) got=(%d,%d)",
+ "Bad ptr map entry key=%u expected=(%u,%u) got=(%u,%u)",
iChild, eType, iParent, ePtrmapType, iPtrmapParent);
}
}
@@ -78755,7 +79217,7 @@ static void checkList(
if( checkRef(pCheck, iPage) ) break;
N--;
if( sqlite3PagerGet(pCheck->pPager, (Pgno)iPage, &pOvflPage, 0) ){
- checkAppendMsg(pCheck, "failed to get page %d", iPage);
+ checkAppendMsg(pCheck, "failed to get page %u", iPage);
break;
}
pOvflData = (unsigned char *)sqlite3PagerGetData(pOvflPage);
@@ -78768,7 +79230,7 @@ static void checkList(
#endif
if( n>pCheck->pBt->usableSize/4-2 ){
checkAppendMsg(pCheck,
- "freelist leaf count too big on page %d", iPage);
+ "freelist leaf count too big on page %u", iPage);
N--;
}else{
for(i=0; i<(int)n; i++){
@@ -78800,7 +79262,7 @@ static void checkList(
}
if( N && nErrAtStart==pCheck->nErr ){
checkAppendMsg(pCheck,
- "%s is %d but should be %d",
+ "%s is %u but should be %u",
isFreeList ? "size" : "overflow list length",
expected-N, expected);
}
@@ -78915,8 +79377,8 @@ static int checkTreePage(
usableSize = pBt->usableSize;
if( iPage==0 ) return 0;
if( checkRef(pCheck, iPage) ) return 0;
- pCheck->zPfx = "Page %u: ";
- pCheck->v1 = iPage;
+ pCheck->zPfx = "Tree %u page %u: ";
+ pCheck->v0 = pCheck->v1 = iPage;
if( (rc = btreeGetPage(pBt, iPage, &pPage, 0))!=0 ){
checkAppendMsg(pCheck,
"unable to get the page. error code=%d", rc);
@@ -78942,7 +79404,7 @@ static int checkTreePage(
hdr = pPage->hdrOffset;
/* Set up for cell analysis */
- pCheck->zPfx = "On tree page %u cell %d: ";
+ pCheck->zPfx = "Tree %u page %u cell %u: ";
contentOffset = get2byteNotZero(&data[hdr+5]);
assert( contentOffset<=usableSize ); /* Enforced by btreeInitPage() */
@@ -78962,7 +79424,7 @@ static int checkTreePage(
pgno = get4byte(&data[hdr+8]);
#ifndef SQLITE_OMIT_AUTOVACUUM
if( pBt->autoVacuum ){
- pCheck->zPfx = "On page %u at right child: ";
+ pCheck->zPfx = "Tree %u page %u right child: ";
checkPtrmap(pCheck, pgno, PTRMAP_BTREE, iPage);
}
#endif
@@ -78986,7 +79448,7 @@ static int checkTreePage(
pc = get2byteAligned(pCellIdx);
pCellIdx -= 2;
if( pc<contentOffset || pc>usableSize-4 ){
- checkAppendMsg(pCheck, "Offset %d out of range %d..%d",
+ checkAppendMsg(pCheck, "Offset %u out of range %u..%u",
pc, contentOffset, usableSize-4);
doCoverageCheck = 0;
continue;
@@ -79118,7 +79580,7 @@ static int checkTreePage(
*/
if( heap[0]==0 && nFrag!=data[hdr+7] ){
checkAppendMsg(pCheck,
- "Fragmentation of %d bytes reported as %d on page %u",
+ "Fragmentation of %u bytes reported as %u on page %u",
nFrag, data[hdr+7], iPage);
}
}
@@ -79215,7 +79677,7 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
/* Check the integrity of the freelist
*/
if( bCkFreelist ){
- sCheck.zPfx = "Main freelist: ";
+ sCheck.zPfx = "Freelist: ";
checkList(&sCheck, 1, get4byte(&pBt->pPage1->aData[32]),
get4byte(&pBt->pPage1->aData[36]));
sCheck.zPfx = 0;
@@ -79232,7 +79694,7 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
mxInHdr = get4byte(&pBt->pPage1->aData[52]);
if( mx!=mxInHdr ){
checkAppendMsg(&sCheck,
- "max rootpage (%d) disagrees with header (%d)",
+ "max rootpage (%u) disagrees with header (%u)",
mx, mxInHdr
);
}
@@ -79263,7 +79725,7 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
for(i=1; i<=sCheck.nPage && sCheck.mxErr; i++){
#ifdef SQLITE_OMIT_AUTOVACUUM
if( getPageReferenced(&sCheck, i)==0 ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
+ checkAppendMsg(&sCheck, "Page %u: never used", i);
}
#else
/* If the database supports auto-vacuum, make sure no tables contain
@@ -79271,11 +79733,11 @@ SQLITE_PRIVATE int sqlite3BtreeIntegrityCheck(
*/
if( getPageReferenced(&sCheck, i)==0 &&
(PTRMAP_PAGENO(pBt, i)!=i || !pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Page %d is never used", i);
+ checkAppendMsg(&sCheck, "Page %u: never used", i);
}
if( getPageReferenced(&sCheck, i)!=0 &&
(PTRMAP_PAGENO(pBt, i)==i && pBt->autoVacuum) ){
- checkAppendMsg(&sCheck, "Pointer map page %d is referenced", i);
+ checkAppendMsg(&sCheck, "Page %u: pointer map referenced", i);
}
#endif
}
@@ -79837,13 +80299,7 @@ static int backupOnePage(
assert( !isFatalError(p->rc) );
assert( iSrcPg!=PENDING_BYTE_PAGE(p->pSrc->pBt) );
assert( zSrcData );
-
- /* Catch the case where the destination is an in-memory database and the
- ** page sizes of the source and destination differ.
- */
- if( nSrcPgsz!=nDestPgsz && sqlite3PagerIsMemdb(pDestPager) ){
- rc = SQLITE_READONLY;
- }
+ assert( nSrcPgsz==nDestPgsz || sqlite3PagerIsMemdb(pDestPager)==0 );
/* This loop runs once for each destination page spanned by the source
** page. For each iteration, variable iOff is set to the byte offset
@@ -79976,7 +80432,10 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){
pgszSrc = sqlite3BtreeGetPageSize(p->pSrc);
pgszDest = sqlite3BtreeGetPageSize(p->pDest);
destMode = sqlite3PagerGetJournalMode(sqlite3BtreePager(p->pDest));
- if( SQLITE_OK==rc && destMode==PAGER_JOURNALMODE_WAL && pgszSrc!=pgszDest ){
+ if( SQLITE_OK==rc
+ && (destMode==PAGER_JOURNALMODE_WAL || sqlite3PagerIsMemdb(pDestPager))
+ && pgszSrc!=pgszDest
+ ){
rc = SQLITE_READONLY;
}
@@ -80525,6 +80984,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemValidStrRep(Mem *p){
char *z;
int i, j, incr;
if( (p->flags & MEM_Str)==0 ) return 1;
+ if( p->db && p->db->mallocFailed ) return 1;
if( p->flags & MEM_Term ){
/* Insure that the string is properly zero-terminated. Pay particular
** attention to the case where p->n is odd */
@@ -80807,7 +81267,7 @@ SQLITE_PRIVATE int sqlite3VdbeMemStringify(Mem *pMem, u8 enc, u8 bForce){
vdbeMemRenderNum(nByte, pMem->z, pMem);
assert( pMem->z!=0 );
- assert( pMem->n==sqlite3Strlen30NN(pMem->z) );
+ assert( pMem->n==(int)sqlite3Strlen30NN(pMem->z) );
pMem->enc = SQLITE_UTF8;
pMem->flags |= MEM_Str|MEM_Term;
if( bForce ) pMem->flags &= ~(MEM_Int|MEM_Real|MEM_IntReal);
@@ -81851,6 +82311,9 @@ static int valueFromFunction(
if( pList ) nVal = pList->nExpr;
assert( !ExprHasProperty(p, EP_IntValue) );
pFunc = sqlite3FindFunction(db, p->u.zToken, nVal, enc, 0);
+#ifdef SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION
+ if( pFunc==0 ) return SQLITE_OK;
+#endif
assert( pFunc );
if( (pFunc->funcFlags & (SQLITE_FUNC_CONSTANT|SQLITE_FUNC_SLOCHNG))==0
|| (pFunc->funcFlags & SQLITE_FUNC_NEEDCOLL)
@@ -81887,16 +82350,11 @@ static int valueFromFunction(
}else{
sqlite3ValueApplyAffinity(pVal, aff, SQLITE_UTF8);
assert( rc==SQLITE_OK );
- assert( enc==pVal->enc
- || (pVal->flags & MEM_Str)==0
- || db->mallocFailed );
-#if 0 /* Not reachable except after a prior failure */
rc = sqlite3VdbeChangeEncoding(pVal, enc);
- if( rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal) ){
+ if( NEVER(rc==SQLITE_OK && sqlite3VdbeMemTooBig(pVal)) ){
rc = SQLITE_TOOBIG;
pCtx->pParse->nErr++;
}
-#endif
}
value_from_function_out:
@@ -81960,6 +82418,13 @@ static int valueFromExpr(
rc = valueFromExpr(db, pExpr->pLeft, enc, aff, ppVal, pCtx);
testcase( rc!=SQLITE_OK );
if( *ppVal ){
+#ifdef SQLITE_ENABLE_STAT4
+ rc = ExpandBlob(*ppVal);
+#else
+ /* zero-blobs only come from functions, not literal values. And
+ ** functions are only processed under STAT4 */
+ assert( (ppVal[0][0].flags & MEM_Zero)==0 );
+#endif
sqlite3VdbeMemCast(*ppVal, aff, enc);
sqlite3ValueApplyAffinity(*ppVal, affinity, enc);
}
@@ -82806,10 +83271,10 @@ SQLITE_PRIVATE void sqlite3ExplainBreakpoint(const char *z1, const char *z2){
*/
SQLITE_PRIVATE int sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){
int addr = 0;
-#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+#if !defined(SQLITE_DEBUG)
/* Always include the OP_Explain opcodes if SQLITE_DEBUG is defined.
** But omit them (for performance) during production builds */
- if( pParse->explain==2 )
+ if( pParse->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
#endif
{
char *zMsg;
@@ -83183,6 +83648,8 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
Op *pOp;
Parse *pParse = p->pParse;
int *aLabel = pParse->aLabel;
+
+ assert( pParse->db->mallocFailed==0 ); /* tag-20230419-1 */
p->readOnly = 1;
p->bIsReader = 0;
pOp = &p->aOp[p->nOp-1];
@@ -83242,6 +83709,7 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){
** have non-negative values for P2. */
assert( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_JUMP)!=0 );
assert( ADDR(pOp->p2)<-pParse->nLabel );
+ assert( aLabel!=0 ); /* True because of tag-20230419-1 */
pOp->p2 = aLabel[ADDR(pOp->p2)];
}
break;
@@ -83485,18 +83953,20 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatus(
LogEst nEst, /* Estimated number of output rows */
const char *zName /* Name of table or index being scanned */
){
- sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus);
- ScanStatus *aNew;
- aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte);
- if( aNew ){
- ScanStatus *pNew = &aNew[p->nScan++];
- memset(pNew, 0, sizeof(ScanStatus));
- pNew->addrExplain = addrExplain;
- pNew->addrLoop = addrLoop;
- pNew->addrVisit = addrVisit;
- pNew->nEst = nEst;
- pNew->zName = sqlite3DbStrDup(p->db, zName);
- p->aScan = aNew;
+ if( IS_STMT_SCANSTATUS(p->db) ){
+ sqlite3_int64 nByte = (p->nScan+1) * sizeof(ScanStatus);
+ ScanStatus *aNew;
+ aNew = (ScanStatus*)sqlite3DbRealloc(p->db, p->aScan, nByte);
+ if( aNew ){
+ ScanStatus *pNew = &aNew[p->nScan++];
+ memset(pNew, 0, sizeof(ScanStatus));
+ pNew->addrExplain = addrExplain;
+ pNew->addrLoop = addrLoop;
+ pNew->addrVisit = addrVisit;
+ pNew->nEst = nEst;
+ pNew->zName = sqlite3DbStrDup(p->db, zName);
+ p->aScan = aNew;
+ }
}
}
@@ -83513,20 +83983,22 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatusRange(
int addrStart,
int addrEnd
){
- ScanStatus *pScan = 0;
- int ii;
- for(ii=p->nScan-1; ii>=0; ii--){
- pScan = &p->aScan[ii];
- if( pScan->addrExplain==addrExplain ) break;
- pScan = 0;
- }
- if( pScan ){
- if( addrEnd<0 ) addrEnd = sqlite3VdbeCurrentAddr(p)-1;
- for(ii=0; ii<ArraySize(pScan->aAddrRange); ii+=2){
- if( pScan->aAddrRange[ii]==0 ){
- pScan->aAddrRange[ii] = addrStart;
- pScan->aAddrRange[ii+1] = addrEnd;
- break;
+ if( IS_STMT_SCANSTATUS(p->db) ){
+ ScanStatus *pScan = 0;
+ int ii;
+ for(ii=p->nScan-1; ii>=0; ii--){
+ pScan = &p->aScan[ii];
+ if( pScan->addrExplain==addrExplain ) break;
+ pScan = 0;
+ }
+ if( pScan ){
+ if( addrEnd<0 ) addrEnd = sqlite3VdbeCurrentAddr(p)-1;
+ for(ii=0; ii<ArraySize(pScan->aAddrRange); ii+=2){
+ if( pScan->aAddrRange[ii]==0 ){
+ pScan->aAddrRange[ii] = addrStart;
+ pScan->aAddrRange[ii+1] = addrEnd;
+ break;
+ }
}
}
}
@@ -83543,19 +84015,21 @@ SQLITE_PRIVATE void sqlite3VdbeScanStatusCounters(
int addrLoop,
int addrVisit
){
- ScanStatus *pScan = 0;
- int ii;
- for(ii=p->nScan-1; ii>=0; ii--){
- pScan = &p->aScan[ii];
- if( pScan->addrExplain==addrExplain ) break;
- pScan = 0;
- }
- if( pScan ){
- pScan->addrLoop = addrLoop;
- pScan->addrVisit = addrVisit;
+ if( IS_STMT_SCANSTATUS(p->db) ){
+ ScanStatus *pScan = 0;
+ int ii;
+ for(ii=p->nScan-1; ii>=0; ii--){
+ pScan = &p->aScan[ii];
+ if( pScan->addrExplain==addrExplain ) break;
+ pScan = 0;
+ }
+ if( pScan ){
+ pScan->addrLoop = addrLoop;
+ pScan->addrVisit = addrVisit;
+ }
}
}
-#endif
+#endif /* defined(SQLITE_ENABLE_STMT_SCANSTATUS) */
/*
@@ -83979,7 +84453,7 @@ SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){
/* Return the most recently added opcode
*/
-VdbeOp * sqlite3VdbeGetLastOp(Vdbe *p){
+SQLITE_PRIVATE VdbeOp *sqlite3VdbeGetLastOp(Vdbe *p){
return sqlite3VdbeGetOp(p, p->nOp - 1);
}
@@ -85683,6 +86157,8 @@ SQLITE_PRIVATE int sqlite3VdbeHalt(Vdbe *p){
db->flags &= ~(u64)SQLITE_DeferFKs;
sqlite3CommitInternalChanges(db);
}
+ }else if( p->rc==SQLITE_SCHEMA && db->nVdbeActive>1 ){
+ p->nChange = 0;
}else{
sqlite3RollbackAll(db, SQLITE_OK);
p->nChange = 0;
@@ -86001,9 +86477,9 @@ static void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){
#ifdef SQLITE_ENABLE_NORMALIZE
sqlite3DbFree(db, p->zNormSql);
{
- DblquoteStr *pThis, *pNext;
- for(pThis=p->pDblStr; pThis; pThis=pNext){
- pNext = pThis->pNextStr;
+ DblquoteStr *pThis, *pNxt;
+ for(pThis=p->pDblStr; pThis; pThis=pNxt){
+ pNxt = pThis->pNextStr;
sqlite3DbFree(db, pThis);
}
}
@@ -87630,6 +88106,20 @@ SQLITE_PRIVATE int sqlite3NotPureFunc(sqlite3_context *pCtx){
return 1;
}
+#if defined(SQLITE_ENABLE_CURSOR_HINTS) && defined(SQLITE_DEBUG)
+/*
+** This Walker callback is used to help verify that calls to
+** sqlite3BtreeCursorHint() with opcode BTREE_HINT_RANGE have
+** byte-code register values correctly initialized.
+*/
+SQLITE_PRIVATE int sqlite3CursorRangeHintExprCheck(Walker *pWalker, Expr *pExpr){
+ if( pExpr->op==TK_REGISTER ){
+ assert( (pWalker->u.aMem[pExpr->iTable].flags & MEM_Undefined)==0 );
+ }
+ return WRC_Continue;
+}
+#endif /* SQLITE_ENABLE_CURSOR_HINTS && SQLITE_DEBUG */
+
#ifndef SQLITE_OMIT_VIRTUALTABLE
/*
** Transfer error message text from an sqlite3_vtab.zErrMsg (text stored
@@ -87692,6 +88182,16 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
PreUpdate preupdate;
const char *zTbl = pTab->zName;
static const u8 fakeSortOrder = 0;
+#ifdef SQLITE_DEBUG
+ int nRealCol;
+ if( pTab->tabFlags & TF_WithoutRowid ){
+ nRealCol = sqlite3PrimaryKeyIndex(pTab)->nColumn;
+ }else if( pTab->tabFlags & TF_HasVirtual ){
+ nRealCol = pTab->nNVCol;
+ }else{
+ nRealCol = pTab->nCol;
+ }
+#endif
assert( db->pPreUpdate==0 );
memset(&preupdate, 0, sizeof(PreUpdate));
@@ -87708,8 +88208,8 @@ SQLITE_PRIVATE void sqlite3VdbePreUpdateHook(
assert( pCsr!=0 );
assert( pCsr->eCurType==CURTYPE_BTREE );
- assert( pCsr->nField==pTab->nCol
- || (pCsr->nField==pTab->nCol+1 && op==SQLITE_DELETE && iReg==-1)
+ assert( pCsr->nField==nRealCol
+ || (pCsr->nField==nRealCol+1 && op==SQLITE_DELETE && iReg==-1)
);
preupdate.v = v;
@@ -88016,7 +88516,7 @@ SQLITE_API int sqlite3_value_type(sqlite3_value* pVal){
SQLITE_NULL, /* 0x1f (not possible) */
SQLITE_FLOAT, /* 0x20 INTREAL */
SQLITE_NULL, /* 0x21 (not possible) */
- SQLITE_TEXT, /* 0x22 INTREAL + TEXT */
+ SQLITE_FLOAT, /* 0x22 INTREAL + TEXT */
SQLITE_NULL, /* 0x23 (not possible) */
SQLITE_FLOAT, /* 0x24 (not possible) */
SQLITE_NULL, /* 0x25 (not possible) */
@@ -89082,9 +89582,9 @@ static const void *columnName(
assert( db!=0 );
n = sqlite3_column_count(pStmt);
if( N<n && N>=0 ){
+ u8 prior_mallocFailed = db->mallocFailed;
N += useType*n;
sqlite3_mutex_enter(db->mutex);
- assert( db->mallocFailed==0 );
#ifndef SQLITE_OMIT_UTF16
if( useUtf16 ){
ret = sqlite3_value_text16((sqlite3_value*)&p->aColName[N]);
@@ -89096,7 +89596,8 @@ static const void *columnName(
/* A malloc may have failed inside of the _text() call. If this
** is the case, clear the mallocFailed flag and return NULL.
*/
- if( db->mallocFailed ){
+ assert( db->mallocFailed==0 || db->mallocFailed==1 );
+ if( db->mallocFailed > prior_mallocFailed ){
sqlite3OomClear(db);
ret = 0;
}
@@ -89883,15 +90384,24 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
void *pOut /* OUT: Write the answer here */
){
Vdbe *p = (Vdbe*)pStmt;
- ScanStatus *pScan;
+ VdbeOp *aOp = p->aOp;
+ int nOp = p->nOp;
+ ScanStatus *pScan = 0;
int idx;
+ if( p->pFrame ){
+ VdbeFrame *pFrame;
+ for(pFrame=p->pFrame; pFrame->pParent; pFrame=pFrame->pParent);
+ aOp = pFrame->aOp;
+ nOp = pFrame->nOp;
+ }
+
if( iScan<0 ){
int ii;
if( iScanStatusOp==SQLITE_SCANSTAT_NCYCLE ){
i64 res = 0;
- for(ii=0; ii<p->nOp; ii++){
- res += p->aOp[ii].nCycle;
+ for(ii=0; ii<nOp; ii++){
+ res += aOp[ii].nCycle;
}
*(i64*)pOut = res;
return 0;
@@ -89917,7 +90427,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
switch( iScanStatusOp ){
case SQLITE_SCANSTAT_NLOOP: {
if( pScan->addrLoop>0 ){
- *(sqlite3_int64*)pOut = p->aOp[pScan->addrLoop].nExec;
+ *(sqlite3_int64*)pOut = aOp[pScan->addrLoop].nExec;
}else{
*(sqlite3_int64*)pOut = -1;
}
@@ -89925,7 +90435,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_NVISIT: {
if( pScan->addrVisit>0 ){
- *(sqlite3_int64*)pOut = p->aOp[pScan->addrVisit].nExec;
+ *(sqlite3_int64*)pOut = aOp[pScan->addrVisit].nExec;
}else{
*(sqlite3_int64*)pOut = -1;
}
@@ -89947,7 +90457,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_EXPLAIN: {
if( pScan->addrExplain ){
- *(const char**)pOut = p->aOp[ pScan->addrExplain ].p4.z;
+ *(const char**)pOut = aOp[ pScan->addrExplain ].p4.z;
}else{
*(const char**)pOut = 0;
}
@@ -89955,7 +90465,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_SELECTID: {
if( pScan->addrExplain ){
- *(int*)pOut = p->aOp[ pScan->addrExplain ].p1;
+ *(int*)pOut = aOp[ pScan->addrExplain ].p1;
}else{
*(int*)pOut = -1;
}
@@ -89963,7 +90473,7 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
}
case SQLITE_SCANSTAT_PARENTID: {
if( pScan->addrExplain ){
- *(int*)pOut = p->aOp[ pScan->addrExplain ].p2;
+ *(int*)pOut = aOp[ pScan->addrExplain ].p2;
}else{
*(int*)pOut = -1;
}
@@ -89981,18 +90491,18 @@ SQLITE_API int sqlite3_stmt_scanstatus_v2(
if( iIns==0 ) break;
if( iIns>0 ){
while( iIns<=iEnd ){
- res += p->aOp[iIns].nCycle;
+ res += aOp[iIns].nCycle;
iIns++;
}
}else{
int iOp;
- for(iOp=0; iOp<p->nOp; iOp++){
- Op *pOp = &p->aOp[iOp];
+ for(iOp=0; iOp<nOp; iOp++){
+ Op *pOp = &aOp[iOp];
if( pOp->p1!=iEnd ) continue;
if( (sqlite3OpcodeProperty[pOp->opcode] & OPFLG_NCYCLE)==0 ){
continue;
}
- res += p->aOp[iOp].nCycle;
+ res += aOp[iOp].nCycle;
}
}
}
@@ -90915,8 +91425,10 @@ static u64 filterHash(const Mem *aMem, const Op *pOp){
}else if( p->flags & MEM_Real ){
h += sqlite3VdbeIntValue(p);
}else if( p->flags & (MEM_Str|MEM_Blob) ){
- h += p->n;
- if( p->flags & MEM_Zero ) h += p->u.nZero;
+ /* All strings have the same hash and all blobs have the same hash,
+ ** though, at least, those hashes are different from each other and
+ ** from NULL. */
+ h += 4093 + (p->flags & (MEM_Str|MEM_Blob));
}
}
return h;
@@ -90966,6 +91478,7 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
Mem *pOut = 0; /* Output operand */
#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
u64 *pnCycle = 0;
+ int bStmtScanStatus = IS_STMT_SCANSTATUS(db)!=0;
#endif
/*** INSERT STACK UNION HERE ***/
@@ -91030,13 +91543,17 @@ SQLITE_PRIVATE int sqlite3VdbeExec(
assert( pOp>=aOp && pOp<&aOp[p->nOp]);
nVmStep++;
-#if defined(SQLITE_ENABLE_STMT_SCANSTATUS) || defined(VDBE_PROFILE)
+
+#if defined(VDBE_PROFILE)
pOp->nExec++;
pnCycle = &pOp->nCycle;
-# ifdef VDBE_PROFILE
- if( sqlite3NProfileCnt==0 )
-# endif
+ if( sqlite3NProfileCnt==0 ) *pnCycle -= sqlite3Hwtime();
+#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+ if( bStmtScanStatus ){
+ pOp->nExec++;
+ pnCycle = &pOp->nCycle;
*pnCycle -= sqlite3Hwtime();
+ }
#endif
/* Only allow tracing if SQLITE_DEBUG is defined.
@@ -92624,7 +93141,7 @@ case OP_Compare: {
/* Opcode: Jump P1 P2 P3 * *
**
** Jump to the instruction at address P1, P2, or P3 depending on whether
-** in the most recent OP_Compare instruction the P1 vector was less than
+** in the most recent OP_Compare instruction the P1 vector was less than,
** equal to, or greater than the P2 vector, respectively.
**
** This opcode must immediately follow an OP_Compare opcode.
@@ -92851,6 +93368,12 @@ case OP_IsNull: { /* same as TK_ISNULL, jump, in1 */
** (0x01) bit. SQLITE_FLOAT is the 0x02 bit. SQLITE_TEXT is 0x04.
** SQLITE_BLOB is 0x08. SQLITE_NULL is 0x10.
**
+** WARNING: This opcode does not reliably distinguish between NULL and REAL
+** when P1>=0. If the database contains a NaN value, this opcode will think
+** that the datatype is REAL when it should be NULL. When P1<0 and the value
+** is already stored in register P3, then this opcode does reliably
+** distinguish between NULL and REAL. The problem only arises then P1>=0.
+**
** Take the jump to address P2 if and only if the datatype of the
** value determined by P1 and P3 corresponds to one of the bits in the
** P5 bitmask.
@@ -92964,7 +93487,7 @@ case OP_IfNullRow: { /* jump */
VdbeCursor *pC;
assert( pOp->p1>=0 && pOp->p1<p->nCursor );
pC = p->apCsr[pOp->p1];
- if( ALWAYS(pC) && pC->nullRow ){
+ if( pC && pC->nullRow ){
sqlite3VdbeMemSetNull(aMem + pOp->p3);
goto jump_to_p2;
}
@@ -93459,7 +93982,7 @@ case OP_Affinity: {
}else{
pIn1->u.r = (double)pIn1->u.i;
pIn1->flags |= MEM_Real;
- pIn1->flags &= ~MEM_Int;
+ pIn1->flags &= ~(MEM_Int|MEM_Str);
}
}
REGISTER_TRACE((int)(pIn1-aMem), pIn1);
@@ -95198,6 +95721,7 @@ case OP_SeekScan: { /* ncycle */
break;
}
nStep--;
+ pC->cacheStatus = CACHE_STALE;
rc = sqlite3BtreeNext(pC->uc.pCursor, 0);
if( rc ){
if( rc==SQLITE_DONE ){
@@ -97850,6 +98374,7 @@ case OP_AggFinal: {
}
sqlite3VdbeChangeEncoding(pMem, encoding);
UPDATE_MAX_BLOBSIZE(pMem);
+ REGISTER_TRACE((int)(pMem-aMem), pMem);
break;
}
@@ -98988,8 +99513,10 @@ default: { /* This is really OP_Noop, OP_Explain */
*pnCycle += sqlite3NProfileCnt ? sqlite3NProfileCnt : sqlite3Hwtime();
pnCycle = 0;
#elif defined(SQLITE_ENABLE_STMT_SCANSTATUS)
- *pnCycle += sqlite3Hwtime();
- pnCycle = 0;
+ if( pnCycle ){
+ *pnCycle += sqlite3Hwtime();
+ pnCycle = 0;
+ }
#endif
/* The following code adds nothing to the actual functionality
@@ -99468,7 +99995,7 @@ blob_open_out:
if( pBlob && pBlob->pStmt ) sqlite3VdbeFinalize((Vdbe *)pBlob->pStmt);
sqlite3DbFree(db, pBlob);
}
- sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
+ sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr);
sqlite3DbFree(db, zErr);
sqlite3ParseObjectReset(&sParse);
rc = sqlite3ApiExit(db, rc);
@@ -99627,7 +100154,7 @@ SQLITE_API int sqlite3_blob_reopen(sqlite3_blob *pBlob, sqlite3_int64 iRow){
((Vdbe*)p->pStmt)->rc = SQLITE_OK;
rc = blobSeekToRow(p, iRow, &zErr);
if( rc!=SQLITE_OK ){
- sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr);
+ sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : (char*)0), zErr);
sqlite3DbFree(db, zErr);
}
assert( rc!=SQLITE_SCHEMA );
@@ -104015,7 +104542,8 @@ static int lookupName(
assert( op==TK_DELETE || op==TK_UPDATE || op==TK_INSERT );
if( pParse->bReturning ){
if( (pNC->ncFlags & NC_UBaseReg)!=0
- && (zTab==0 || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0)
+ && ALWAYS(zTab==0
+ || sqlite3StrICmp(zTab,pParse->pTriggerTab->zName)==0)
){
pExpr->iTable = op!=TK_DELETE;
pTab = pParse->pTriggerTab;
@@ -104495,14 +105023,10 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
if( 0==sqlite3ExprCanBeNull(pExpr->pLeft) && !IN_RENAME_OBJECT ){
testcase( ExprHasProperty(pExpr, EP_OuterON) );
assert( !ExprHasProperty(pExpr, EP_IntValue) );
- if( pExpr->op==TK_NOTNULL ){
- pExpr->u.zToken = "true";
- ExprSetProperty(pExpr, EP_IsTrue);
- }else{
- pExpr->u.zToken = "false";
- ExprSetProperty(pExpr, EP_IsFalse);
- }
- pExpr->op = TK_TRUEFALSE;
+ pExpr->u.iValue = (pExpr->op==TK_NOTNULL);
+ pExpr->flags |= EP_IntValue;
+ pExpr->op = TK_INTEGER;
+
for(i=0, p=pNC; p && i<ArraySize(anRef); p=p->pNext, i++){
p->nRef = anRef[i];
}
@@ -104804,8 +105328,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){
assert( pNC->nRef>=nRef );
if( nRef!=pNC->nRef ){
ExprSetProperty(pExpr, EP_VarSelect);
- pNC->ncFlags |= NC_VarSelect;
}
+ pNC->ncFlags |= NC_Subquery;
}
break;
}
@@ -105993,11 +106517,10 @@ SQLITE_PRIVATE CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){
}else{
Expr *pNext = p->pRight;
/* The Expr.x union is never used at the same time as Expr.pRight */
- assert( ExprUseXList(p) );
- assert( p->x.pList==0 || p->pRight==0 );
- if( p->x.pList!=0 && !db->mallocFailed ){
+ assert( !ExprUseXList(p) || p->x.pList==0 || p->pRight==0 );
+ if( ExprUseXList(p) && p->x.pList!=0 && !db->mallocFailed ){
int i;
- for(i=0; ALWAYS(i<p->x.pList->nExpr); i++){
+ for(i=0; i<p->x.pList->nExpr; i++){
if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){
pNext = p->x.pList->a[i].pExpr;
break;
@@ -106829,9 +107352,9 @@ SQLITE_PRIVATE Select *sqlite3ExprListToValues(Parse *pParse, int nElem, ExprLis
** Join two expressions using an AND operator. If either expression is
** NULL, then just return the other expression.
**
-** If one side or the other of the AND is known to be false, then instead
-** of returning an AND expression, just return a constant expression with
-** a value of false.
+** If one side or the other of the AND is known to be false, and neither side
+** is part of an ON clause, then instead of returning an AND expression,
+** just return a constant expression with a value of false.
*/
SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
sqlite3 *db = pParse->db;
@@ -106839,14 +107362,17 @@ SQLITE_PRIVATE Expr *sqlite3ExprAnd(Parse *pParse, Expr *pLeft, Expr *pRight){
return pRight;
}else if( pRight==0 ){
return pLeft;
- }else if( (ExprAlwaysFalse(pLeft) || ExprAlwaysFalse(pRight))
- && !IN_RENAME_OBJECT
- ){
- sqlite3ExprDeferredDelete(pParse, pLeft);
- sqlite3ExprDeferredDelete(pParse, pRight);
- return sqlite3Expr(db, TK_INTEGER, "0");
}else{
- return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
+ u32 f = pLeft->flags | pRight->flags;
+ if( (f&(EP_OuterON|EP_InnerON|EP_IsFalse))==EP_IsFalse
+ && !IN_RENAME_OBJECT
+ ){
+ sqlite3ExprDeferredDelete(pParse, pLeft);
+ sqlite3ExprDeferredDelete(pParse, pRight);
+ return sqlite3Expr(db, TK_INTEGER, "0");
+ }else{
+ return sqlite3PExpr(pParse, TK_AND, pLeft, pRight);
+ }
}
}
@@ -108091,12 +108617,17 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){
}
/*
-** Check pExpr to see if it is an invariant constraint on data source pSrc.
+** Check pExpr to see if it is an constraint on the single data source
+** pSrc = &pSrcList->a[iSrc]. In other words, check to see if pExpr
+** constrains pSrc but does not depend on any other tables or data
+** sources anywhere else in the query. Return true (non-zero) if pExpr
+** is a constraint on pSrc only.
+**
** This is an optimization. False negatives will perhaps cause slower
** queries, but false positives will yield incorrect answers. So when in
** doubt, return 0.
**
-** To be an invariant constraint, the following must be true:
+** To be an single-source constraint, the following must be true:
**
** (1) pExpr cannot refer to any table other than pSrc->iCursor.
**
@@ -108107,13 +108638,31 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstant(Expr *p, int iCur){
**
** (4) If pSrc is the right operand of a LEFT JOIN, then...
** (4a) pExpr must come from an ON clause..
- (4b) and specifically the ON clause associated with the LEFT JOIN.
+** (4b) and specifically the ON clause associated with the LEFT JOIN.
**
** (5) If pSrc is not the right operand of a LEFT JOIN or the left
** operand of a RIGHT JOIN, then pExpr must be from the WHERE
** clause, not an ON clause.
+**
+** (6) Either:
+**
+** (6a) pExpr does not originate in an ON or USING clause, or
+**
+** (6b) The ON or USING clause from which pExpr is derived is
+** not to the left of a RIGHT JOIN (or FULL JOIN).
+**
+** Without this restriction, accepting pExpr as a single-table
+** constraint might move the the ON/USING filter expression
+** from the left side of a RIGHT JOIN over to the right side,
+** which leads to incorrect answers. See also restriction (9)
+** on push-down.
*/
-SQLITE_PRIVATE int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc){
+SQLITE_PRIVATE int sqlite3ExprIsSingleTableConstraint(
+ Expr *pExpr, /* The constraint */
+ const SrcList *pSrcList, /* Complete FROM clause */
+ int iSrc /* Which element of pSrcList to use */
+){
+ const SrcItem *pSrc = &pSrcList->a[iSrc];
if( pSrc->fg.jointype & JT_LTORJ ){
return 0; /* rule (3) */
}
@@ -108123,6 +108672,19 @@ SQLITE_PRIVATE int sqlite3ExprIsTableConstraint(Expr *pExpr, const SrcItem *pSrc
}else{
if( ExprHasProperty(pExpr, EP_OuterON) ) return 0; /* rule (5) */
}
+ if( ExprHasProperty(pExpr, EP_OuterON|EP_InnerON) /* (6a) */
+ && (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (6b) */
+ ){
+ int jj;
+ for(jj=0; jj<iSrc; jj++){
+ if( pExpr->w.iJoin==pSrcList->a[jj].iCursor ){
+ if( (pSrcList->a[jj].fg.jointype & JT_LTORJ)!=0 ){
+ return 0; /* restriction (6) */
+ }
+ break;
+ }
+ }
+ }
return sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor); /* rules (1), (2) */
}
@@ -108365,7 +108927,7 @@ SQLITE_PRIVATE int sqlite3IsRowid(const char *z){
** pX is the RHS of an IN operator. If pX is a SELECT statement
** that can be simplified to a direct table access, then return
** a pointer to the SELECT statement. If pX is not a SELECT statement,
-** or if the SELECT statement needs to be manifested into a transient
+** or if the SELECT statement needs to be materialized into a transient
** table, then return NULL.
*/
#ifndef SQLITE_OMIT_SUBQUERY
@@ -108651,7 +109213,6 @@ SQLITE_PRIVATE int sqlite3FindInIndex(
CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
int j;
- assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr );
for(j=0; j<nExpr; j++){
if( pIdx->aiColumn[j]!=pRhs->iColumn ) continue;
assert( pIdx->azColl[j] );
@@ -109554,6 +110115,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(
){
int iAddr;
Vdbe *v = pParse->pVdbe;
+ int nErr = pParse->nErr;
assert( v!=0 );
assert( pParse->iSelfTab!=0 );
if( pParse->iSelfTab>0 ){
@@ -109566,6 +110128,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGeneratedColumn(
sqlite3VdbeAddOp4(v, OP_Affinity, regOut, 1, 0, &pCol->affinity, 1);
}
if( iAddr ) sqlite3VdbeJumpHere(v, iAddr);
+ if( pParse->nErr>nErr ) pParse->db->errByteOffset = -1;
}
#endif /* SQLITE_OMIT_GENERATED_COLUMNS */
@@ -109582,6 +110145,7 @@ SQLITE_PRIVATE void sqlite3ExprCodeGetColumnOfTable(
Column *pCol;
assert( v!=0 );
assert( pTab!=0 );
+ assert( iCol!=XN_EXPR );
if( iCol<0 || iCol==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
VdbeComment((v, "%s.rowid", pTab->zName));
@@ -109848,6 +110412,7 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup(
IndexedExpr *p;
Vdbe *v;
for(p=pParse->pIdxEpr; p; p=p->pIENext){
+ u8 exprAff;
int iDataCur = p->iDataCur;
if( iDataCur<0 ) continue;
if( pParse->iSelfTab ){
@@ -109855,6 +110420,16 @@ static SQLITE_NOINLINE int sqlite3IndexedExprLookup(
iDataCur = -1;
}
if( sqlite3ExprCompare(0, pExpr, p->pExpr, iDataCur)!=0 ) continue;
+ assert( p->aff>=SQLITE_AFF_BLOB && p->aff<=SQLITE_AFF_NUMERIC );
+ exprAff = sqlite3ExprAffinity(pExpr);
+ if( (exprAff<=SQLITE_AFF_BLOB && p->aff!=SQLITE_AFF_BLOB)
+ || (exprAff==SQLITE_AFF_TEXT && p->aff!=SQLITE_AFF_TEXT)
+ || (exprAff>=SQLITE_AFF_NUMERIC && p->aff!=SQLITE_AFF_NUMERIC)
+ ){
+ /* Affinity mismatch on a generated column */
+ continue;
+ }
+
v = pParse->pVdbe;
assert( v!=0 );
if( p->bMaybeNullRow ){
@@ -109923,7 +110498,19 @@ expr_code_doover:
AggInfo *pAggInfo = pExpr->pAggInfo;
struct AggInfo_col *pCol;
assert( pAggInfo!=0 );
- assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
+ assert( pExpr->iAgg>=0 );
+ if( pExpr->iAgg>=pAggInfo->nColumn ){
+ /* Happens when the left table of a RIGHT JOIN is null and
+ ** is using an expression index */
+ sqlite3VdbeAddOp2(v, OP_Null, 0, target);
+#ifdef SQLITE_VDBE_COVERAGE
+ /* Verify that the OP_Null above is exercised by tests
+ ** tag-20230325-2 */
+ sqlite3VdbeAddOp2(v, OP_NotNull, target, 1);
+ VdbeCoverageNeverTaken(v);
+#endif
+ break;
+ }
pCol = &pAggInfo->aCol[pExpr->iAgg];
if( !pAggInfo->directMode ){
return AggInfoColumnReg(pAggInfo, pExpr->iAgg);
@@ -110098,11 +110685,8 @@ expr_code_doover:
#ifndef SQLITE_OMIT_CAST
case TK_CAST: {
/* Expressions of the form: CAST(pLeft AS token) */
- inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
- if( inReg!=target ){
- sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
- inReg = target;
- }
+ sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ assert( inReg==target );
assert( !ExprHasProperty(pExpr, EP_IntValue) );
sqlite3VdbeAddOp2(v, OP_Cast, target,
sqlite3AffinityType(pExpr->u.zToken, 0));
@@ -110434,17 +111018,16 @@ expr_code_doover:
return target;
}
case TK_COLLATE: {
- if( !ExprHasProperty(pExpr, EP_Collate)
- && ALWAYS(pExpr->pLeft)
- && pExpr->pLeft->op==TK_FUNCTION
- ){
- inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
- if( inReg!=target ){
- sqlite3VdbeAddOp2(v, OP_SCopy, inReg, target);
- inReg = target;
- }
- sqlite3VdbeAddOp1(v, OP_ClrSubtype, inReg);
- return inReg;
+ if( !ExprHasProperty(pExpr, EP_Collate) ){
+ /* A TK_COLLATE Expr node without the EP_Collate tag is a so-called
+ ** "SOFT-COLLATE" that is added to constraints that are pushed down
+ ** from outer queries into sub-queries by the push-down optimization.
+ ** Clear subtypes as subtypes may not cross a subquery boundary.
+ */
+ assert( pExpr->pLeft );
+ sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ sqlite3VdbeAddOp1(v, OP_ClrSubtype, target);
+ return target;
}else{
pExpr = pExpr->pLeft;
goto expr_code_doover; /* 2018-04-28: Prevent deep recursion. */
@@ -110545,16 +111128,19 @@ expr_code_doover:
break;
}
}
- addrINR = sqlite3VdbeAddOp1(v, OP_IfNullRow, pExpr->iTable);
- /* Temporarily disable factoring of constant expressions, since
- ** even though expressions may appear to be constant, they are not
- ** really constant because they originate from the right-hand side
- ** of a LEFT JOIN. */
- pParse->okConstFactor = 0;
- inReg = sqlite3ExprCodeTarget(pParse, pExpr->pLeft, target);
+ addrINR = sqlite3VdbeAddOp3(v, OP_IfNullRow, pExpr->iTable, 0, target);
+ /* The OP_IfNullRow opcode above can overwrite the result register with
+ ** NULL. So we have to ensure that the result register is not a value
+ ** that is suppose to be a constant. Two defenses are needed:
+ ** (1) Temporarily disable factoring of constant expressions
+ ** (2) Make sure the computed value really is stored in register
+ ** "target" and not someplace else.
+ */
+ pParse->okConstFactor = 0; /* note (1) above */
+ sqlite3ExprCode(pParse, pExpr->pLeft, target);
+ assert( target==inReg );
pParse->okConstFactor = okConstFactor;
sqlite3VdbeJumpHere(v, addrINR);
- sqlite3VdbeChangeP3(v, addrINR, inReg);
break;
}
@@ -110791,7 +111377,9 @@ SQLITE_PRIVATE void sqlite3ExprCode(Parse *pParse, Expr *pExpr, int target){
inReg = sqlite3ExprCodeTarget(pParse, pExpr, target);
if( inReg!=target ){
u8 op;
- if( ALWAYS(pExpr) && ExprHasProperty(pExpr,EP_Subquery) ){
+ if( ALWAYS(pExpr)
+ && (ExprHasProperty(pExpr,EP_Subquery) || pExpr->op==TK_REGISTER)
+ ){
op = OP_Copy;
}else{
op = OP_SCopy;
@@ -111976,9 +112564,11 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
int iAgg = pExpr->iAgg;
Parse *pParse = pWalker->pParse;
sqlite3 *db = pParse->db;
+ assert( iAgg>=0 );
if( pExpr->op!=TK_AGG_FUNCTION ){
- assert( iAgg>=0 && iAgg<pAggInfo->nColumn );
- if( pAggInfo->aCol[iAgg].pCExpr==pExpr ){
+ if( iAgg<pAggInfo->nColumn
+ && pAggInfo->aCol[iAgg].pCExpr==pExpr
+ ){
pExpr = sqlite3ExprDup(db, pExpr, 0);
if( pExpr ){
pAggInfo->aCol[iAgg].pCExpr = pExpr;
@@ -111987,8 +112577,9 @@ static int agginfoPersistExprCb(Walker *pWalker, Expr *pExpr){
}
}else{
assert( pExpr->op==TK_AGG_FUNCTION );
- assert( iAgg>=0 && iAgg<pAggInfo->nFunc );
- if( pAggInfo->aFunc[iAgg].pFExpr==pExpr ){
+ if( ALWAYS(iAgg<pAggInfo->nFunc)
+ && pAggInfo->aFunc[iAgg].pFExpr==pExpr
+ ){
pExpr = sqlite3ExprDup(db, pExpr, 0);
if( pExpr ){
pAggInfo->aFunc[iAgg].pFExpr = pExpr;
@@ -112138,7 +112729,12 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
}
if( pIEpr==0 ) break;
if( NEVER(!ExprUseYTab(pExpr)) ) break;
- if( pExpr->pAggInfo!=0 ) break; /* Already resolved by outer context */
+ for(i=0; i<pSrcList->nSrc; i++){
+ if( pSrcList->a[0].iCursor==pIEpr->iDataCur ) break;
+ }
+ if( i>=pSrcList->nSrc ) break;
+ if( NEVER(pExpr->pAggInfo!=0) ) break; /* Resolved by outer context */
+ if( pParse->nErr ){ return WRC_Abort; }
/* If we reach this point, it means that expression pExpr can be
** translated into a reference to an index column as described by
@@ -112149,6 +112745,9 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
tmp.iTable = pIEpr->iIdxCur;
tmp.iColumn = pIEpr->iIdxCol;
findOrCreateAggInfoColumn(pParse, pAggInfo, &tmp);
+ if( pParse->nErr ){ return WRC_Abort; }
+ assert( pAggInfo->aCol!=0 );
+ assert( tmp.iAgg<pAggInfo->nColumn );
pAggInfo->aCol[tmp.iAgg].pCExpr = pExpr;
pExpr->pAggInfo = pAggInfo;
pExpr->iAgg = tmp.iAgg;
@@ -112172,7 +112771,7 @@ static int analyzeAggregate(Walker *pWalker, Expr *pExpr){
} /* endif pExpr->iTable==pItem->iCursor */
} /* end loop over pSrcList */
}
- return WRC_Prune;
+ return WRC_Continue;
}
case TK_AGG_FUNCTION: {
if( (pNC->ncFlags & NC_InAggFunc)==0
@@ -112326,6 +112925,37 @@ SQLITE_PRIVATE void sqlite3ClearTempRegCache(Parse *pParse){
}
/*
+** Make sure sufficient registers have been allocated so that
+** iReg is a valid register number.
+*/
+SQLITE_PRIVATE void sqlite3TouchRegister(Parse *pParse, int iReg){
+ if( pParse->nMem<iReg ) pParse->nMem = iReg;
+}
+
+#if defined(SQLITE_ENABLE_STAT4) || defined(SQLITE_DEBUG)
+/*
+** Return the latest reusable register in the set of all registers.
+** The value returned is no less than iMin. If any register iMin or
+** greater is in permanent use, then return one more than that last
+** permanent register.
+*/
+SQLITE_PRIVATE int sqlite3FirstAvailableRegister(Parse *pParse, int iMin){
+ const ExprList *pList = pParse->pConstExpr;
+ if( pList ){
+ int i;
+ for(i=0; i<pList->nExpr; i++){
+ if( pList->a[i].u.iConstExprReg>=iMin ){
+ iMin = pList->a[i].u.iConstExprReg + 1;
+ }
+ }
+ }
+ pParse->nTempReg = 0;
+ pParse->nRangeReg = 0;
+ return iMin;
+}
+#endif /* SQLITE_ENABLE_STAT4 || SQLITE_DEBUG */
+
+/*
** Validate that no temporary register falls within the range of
** iFirst..iLast, inclusive. This routine is only call from within assert()
** statements.
@@ -112344,6 +112974,14 @@ SQLITE_PRIVATE int sqlite3NoTempsInRange(Parse *pParse, int iFirst, int iLast){
return 0;
}
}
+ if( pParse->pConstExpr ){
+ ExprList *pList = pParse->pConstExpr;
+ for(i=0; i<pList->nExpr; i++){
+ int iReg = pList->a[i].u.iConstExprReg;
+ if( iReg==0 ) continue;
+ if( iReg>=iFirst && iReg<=iLast ) return 0;
+ }
+ }
return 1;
}
#endif /* SQLITE_DEBUG */
@@ -113632,6 +114270,19 @@ static int renameEditSql(
}
/*
+** Set all pEList->a[].fg.eEName fields in the expression-list to val.
+*/
+static void renameSetENames(ExprList *pEList, int val){
+ if( pEList ){
+ int i;
+ for(i=0; i<pEList->nExpr; i++){
+ assert( val==ENAME_NAME || pEList->a[i].fg.eEName==ENAME_NAME );
+ pEList->a[i].fg.eEName = val;
+ }
+ }
+}
+
+/*
** Resolve all symbols in the trigger at pParse->pNewTrigger, assuming
** it was read from the schema of database zDb. Return SQLITE_OK if
** successful. Otherwise, return an SQLite error code and leave an error
@@ -113678,7 +114329,17 @@ static int renameResolveTrigger(Parse *pParse){
pSrc = 0;
rc = SQLITE_NOMEM;
}else{
+ /* pStep->pExprList contains an expression-list used for an UPDATE
+ ** statement. So the a[].zEName values are the RHS of the
+ ** "<col> = <expr>" clauses of the UPDATE statement. So, before
+ ** running SelectPrep(), change all the eEName values in
+ ** pStep->pExprList to ENAME_SPAN (from their current value of
+ ** ENAME_NAME). This is to prevent any ids in ON() clauses that are
+ ** part of pSrc from being incorrectly resolved against the
+ ** a[].zEName values as if they were column aliases. */
+ renameSetENames(pStep->pExprList, ENAME_SPAN);
sqlite3SelectPrep(pParse, pSel, 0);
+ renameSetENames(pStep->pExprList, ENAME_NAME);
rc = pParse->nErr ? SQLITE_ERROR : SQLITE_OK;
assert( pStep->pExprList==0 || pStep->pExprList==pSel->pEList );
assert( pSrc==pSel->pSrc );
@@ -115627,11 +116288,15 @@ static void analyzeOneTable(
int regIdxname = iMem++; /* Register containing index name */
int regStat1 = iMem++; /* Value for the stat column of sqlite_stat1 */
int regPrev = iMem; /* MUST BE LAST (see below) */
+#ifdef SQLITE_ENABLE_STAT4
+ int doOnce = 1; /* Flag for a one-time computation */
+#endif
#ifdef SQLITE_ENABLE_PREUPDATE_HOOK
Table *pStat1 = 0;
#endif
- pParse->nMem = MAX(pParse->nMem, iMem);
+ sqlite3TouchRegister(pParse, iMem);
+ assert( sqlite3NoTempsInRange(pParse, regNewRowid, iMem) );
v = sqlite3GetVdbe(pParse);
if( v==0 || NEVER(pTab==0) ){
return;
@@ -115737,7 +116402,7 @@ static void analyzeOneTable(
** the regPrev array and a trailing rowid (the rowid slot is required
** when building a record to insert into the sample column of
** the sqlite_stat4 table. */
- pParse->nMem = MAX(pParse->nMem, regPrev+nColTest);
+ sqlite3TouchRegister(pParse, regPrev+nColTest);
/* Open a read-only cursor on the index being analyzed. */
assert( iDb==sqlite3SchemaToIndex(db, pIdx->pSchema) );
@@ -115909,7 +116574,35 @@ static void analyzeOneTable(
int addrIsNull;
u8 seekOp = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
- pParse->nMem = MAX(pParse->nMem, regCol+nCol);
+ if( doOnce ){
+ int mxCol = nCol;
+ Index *pX;
+
+ /* Compute the maximum number of columns in any index */
+ for(pX=pTab->pIndex; pX; pX=pX->pNext){
+ int nColX; /* Number of columns in pX */
+ if( !HasRowid(pTab) && IsPrimaryKeyIndex(pX) ){
+ nColX = pX->nKeyCol;
+ }else{
+ nColX = pX->nColumn;
+ }
+ if( nColX>mxCol ) mxCol = nColX;
+ }
+
+ /* Allocate space to compute results for the largest index */
+ sqlite3TouchRegister(pParse, regCol+mxCol);
+ doOnce = 0;
+#ifdef SQLITE_DEBUG
+ /* Verify that the call to sqlite3ClearTempRegCache() below
+ ** really is needed.
+ ** https://sqlite.org/forum/forumpost/83cb4a95a0 (2023-03-25)
+ */
+ testcase( !sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) );
+#endif
+ sqlite3ClearTempRegCache(pParse); /* tag-20230325-1 */
+ assert( sqlite3NoTempsInRange(pParse, regEq, regCol+mxCol) );
+ }
+ assert( sqlite3NoTempsInRange(pParse, regEq, regCol+nCol) );
addrNext = sqlite3VdbeCurrentAddr(v);
callStatGet(pParse, regStat, STAT_GET_ROWID, regSampleRowid);
@@ -115990,6 +116683,11 @@ static void analyzeDatabase(Parse *pParse, int iDb){
for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
Table *pTab = (Table*)sqliteHashData(k);
analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab);
+#ifdef SQLITE_ENABLE_STAT4
+ iMem = sqlite3FirstAvailableRegister(pParse, iMem);
+#else
+ assert( iMem==sqlite3FirstAvailableRegister(pParse,iMem) );
+#endif
}
loadAnalysis(pParse, iDb);
}
@@ -116377,6 +117075,10 @@ static int loadStatTbl(
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
assert( pIdx==0 || pIdx->nSample==0 );
if( pIdx==0 ) continue;
+ if( pIdx->aSample!=0 ){
+ /* The same index appears in sqlite_stat4 under multiple names */
+ continue;
+ }
assert( !HasRowid(pIdx->pTable) || pIdx->nColumn==pIdx->nKeyCol+1 );
if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
nIdxCol = pIdx->nKeyCol;
@@ -116384,6 +117086,7 @@ static int loadStatTbl(
nIdxCol = pIdx->nColumn;
}
pIdx->nSampleCol = nIdxCol;
+ pIdx->mxSample = nSample;
nByte = sizeof(IndexSample) * nSample;
nByte += sizeof(tRowcnt) * nIdxCol * 3 * nSample;
nByte += nIdxCol * sizeof(tRowcnt); /* Space for Index.aAvgEq[] */
@@ -116423,6 +117126,11 @@ static int loadStatTbl(
if( zIndex==0 ) continue;
pIdx = findIndexOrPrimaryKey(db, zIndex, zDb);
if( pIdx==0 ) continue;
+ if( pIdx->nSample>=pIdx->mxSample ){
+ /* Too many slots used because the same index appears in
+ ** sqlite_stat4 using multiple names */
+ continue;
+ }
/* This next condition is true if data has already been loaded from
** the sqlite_stat4 table. */
nCol = pIdx->nSampleCol;
@@ -116466,11 +117174,12 @@ static int loadStat4(sqlite3 *db, const char *zDb){
const Table *pStat4;
assert( db->lookaside.bDisable );
- if( (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
+ if( OptimizationEnabled(db, SQLITE_Stat4)
+ && (pStat4 = sqlite3FindTable(db, "sqlite_stat4", zDb))!=0
&& IsOrdinaryTable(pStat4)
){
rc = loadStatTbl(db,
- "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx",
+ "SELECT idx,count(*) FROM %Q.sqlite_stat4 GROUP BY idx COLLATE nocase",
"SELECT idx,neq,nlt,ndlt,sample FROM %Q.sqlite_stat4",
zDb
);
@@ -118314,7 +119023,7 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){
if( IsOrdinaryTable(pTable) ){
sqlite3FkDelete(db, pTable);
}
-#ifndef SQLITE_OMIT_VIRTUAL_TABLE
+#ifndef SQLITE_OMIT_VIRTUALTABLE
else if( IsVirtual(pTable) ){
sqlite3VtabClear(db, pTable);
}
@@ -118917,7 +119626,7 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){
if( pParse->pNewTrigger ){
sqlite3ErrorMsg(pParse, "cannot use RETURNING in a trigger");
}else{
- assert( pParse->bReturning==0 );
+ assert( pParse->bReturning==0 || pParse->ifNotExists );
}
pParse->bReturning = 1;
pRet = sqlite3DbMallocZero(db, sizeof(*pRet));
@@ -118943,7 +119652,8 @@ SQLITE_PRIVATE void sqlite3AddReturning(Parse *pParse, ExprList *pList){
pRet->retTStep.pTrig = &pRet->retTrig;
pRet->retTStep.pExprList = pList;
pHash = &(db->aDb[1].pSchema->trigHash);
- assert( sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0 || pParse->nErr );
+ assert( sqlite3HashFind(pHash, RETURNING_TRIGGER_NAME)==0
+ || pParse->nErr || pParse->ifNotExists );
if( sqlite3HashInsert(pHash, RETURNING_TRIGGER_NAME, &pRet->retTrig)
==&pRet->retTrig ){
sqlite3OomFault(db);
@@ -119478,6 +120188,7 @@ SQLITE_PRIVATE void sqlite3AddGenerated(Parse *pParse, Expr *pExpr, Token *pType
** turn it into one by adding a unary "+" operator. */
pExpr = sqlite3PExpr(pParse, TK_UPLUS, pExpr, 0);
}
+ if( pExpr && pExpr->op!=TK_RAISE ) pExpr->affExpr = pCol->affinity;
sqlite3ColumnSetExpr(pParse, pTab, pCol, pExpr);
pExpr = 0;
goto generated_done;
@@ -123344,6 +124055,7 @@ SQLITE_PRIVATE void sqlite3SetTextEncoding(sqlite3 *db, u8 enc){
** strings is BINARY.
*/
db->pDfltColl = sqlite3FindCollSeq(db, enc, sqlite3StrBINARY, 0);
+ sqlite3ExpirePreparedStatements(db, 1);
}
/*
@@ -123815,13 +124527,15 @@ static int tabIsReadOnly(Parse *pParse, Table *pTab){
** If pTab is writable but other errors have occurred -> return 1.
** If pTab is writable and no prior errors -> return 0;
*/
-SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){
+SQLITE_PRIVATE int sqlite3IsReadOnly(Parse *pParse, Table *pTab, Trigger *pTrigger){
if( tabIsReadOnly(pParse, pTab) ){
sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName);
return 1;
}
#ifndef SQLITE_OMIT_VIEW
- if( !viewOk && IsView(pTab) ){
+ if( IsView(pTab)
+ && (pTrigger==0 || (pTrigger->bReturning && pTrigger->pNext==0))
+ ){
sqlite3ErrorMsg(pParse,"cannot modify %s because it is a view",pTab->zName);
return 1;
}
@@ -124075,7 +124789,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
goto delete_from_cleanup;
}
- if( sqlite3IsReadOnly(pParse, pTab, (pTrigger?1:0)) ){
+ if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto delete_from_cleanup;
}
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
@@ -124184,7 +124898,7 @@ SQLITE_PRIVATE void sqlite3DeleteFrom(
#endif /* SQLITE_OMIT_TRUNCATE_OPTIMIZATION */
{
u16 wcf = WHERE_ONEPASS_DESIRED|WHERE_DUPLICATES_OK;
- if( sNC.ncFlags & NC_VarSelect ) bComplex = 1;
+ if( sNC.ncFlags & NC_Subquery ) bComplex = 1;
wcf |= (bComplex ? 0 : WHERE_ONEPASS_MULTIROW);
if( HasRowid(pTab) ){
/* For a rowid table, initialize the RowSet to an empty set */
@@ -126238,7 +126952,7 @@ static void trimFunc(
/*
** The "unknown" function is automatically substituted in place of
** any unrecognized function name when doing an EXPLAIN or EXPLAIN QUERY PLAN
-** when the SQLITE_ENABLE_UNKNOWN_FUNCTION compile-time option is used.
+** when the SQLITE_ENABLE_UNKNOWN_SQL_FUNCTION compile-time option is used.
** When the "sqlite3" command-line shell is built using this functionality,
** that allows an EXPLAIN or EXPLAIN QUERY PLAN for complex queries
** involving application-defined functions to be examined in a generic
@@ -126882,6 +127596,18 @@ static double xCeil(double x){ return ceil(x); }
static double xFloor(double x){ return floor(x); }
/*
+** Some systems do not have log2() and log10() in their standard math
+** libraries.
+*/
+#if defined(HAVE_LOG10) && HAVE_LOG10==0
+# define log10(X) (0.4342944819032517867*log(X))
+#endif
+#if defined(HAVE_LOG2) && HAVE_LOG2==0
+# define log2(X) (1.442695040888963456*log(X))
+#endif
+
+
+/*
** Implementation of SQL functions:
**
** ln(X) - natural logarithm
@@ -128529,22 +129255,22 @@ static Trigger *fkActionTrigger(
if( action==OE_Restrict ){
int iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
- Token tFrom;
- Token tDb;
+ SrcList *pSrc;
Expr *pRaise;
- tFrom.z = zFrom;
- tFrom.n = nFrom;
- tDb.z = db->aDb[iDb].zDbSName;
- tDb.n = sqlite3Strlen30(tDb.z);
-
pRaise = sqlite3Expr(db, TK_RAISE, "FOREIGN KEY constraint failed");
if( pRaise ){
pRaise->affExpr = OE_Abort;
}
+ pSrc = sqlite3SrcListAppend(pParse, 0, 0, 0);
+ if( pSrc ){
+ assert( pSrc->nSrc==1 );
+ pSrc->a[0].zName = sqlite3DbStrDup(db, zFrom);
+ pSrc->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zDbSName);
+ }
pSelect = sqlite3SelectNew(pParse,
sqlite3ExprListAppend(pParse, 0, pRaise),
- sqlite3SrcListAppend(pParse, 0, &tDb, &tFrom),
+ pSrc,
pWhere,
0, 0, 0, 0, 0
);
@@ -128760,45 +129486,47 @@ SQLITE_PRIVATE void sqlite3OpenTable(
** is managed along with the rest of the Index structure. It will be
** released when sqlite3DeleteIndex() is called.
*/
-SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
+static SQLITE_NOINLINE const char *computeIndexAffStr(sqlite3 *db, Index *pIdx){
+ /* The first time a column affinity string for a particular index is
+ ** required, it is allocated and populated here. It is then stored as
+ ** a member of the Index structure for subsequent use.
+ **
+ ** The column affinity string will eventually be deleted by
+ ** sqliteDeleteIndex() when the Index structure itself is cleaned
+ ** up.
+ */
+ int n;
+ Table *pTab = pIdx->pTable;
+ pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
if( !pIdx->zColAff ){
- /* The first time a column affinity string for a particular index is
- ** required, it is allocated and populated here. It is then stored as
- ** a member of the Index structure for subsequent use.
- **
- ** The column affinity string will eventually be deleted by
- ** sqliteDeleteIndex() when the Index structure itself is cleaned
- ** up.
- */
- int n;
- Table *pTab = pIdx->pTable;
- pIdx->zColAff = (char *)sqlite3DbMallocRaw(0, pIdx->nColumn+1);
- if( !pIdx->zColAff ){
- sqlite3OomFault(db);
- return 0;
- }
- for(n=0; n<pIdx->nColumn; n++){
- i16 x = pIdx->aiColumn[n];
- char aff;
- if( x>=0 ){
- aff = pTab->aCol[x].affinity;
- }else if( x==XN_ROWID ){
- aff = SQLITE_AFF_INTEGER;
- }else{
- assert( x==XN_EXPR );
- assert( pIdx->bHasExpr );
- assert( pIdx->aColExpr!=0 );
- aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
- }
- if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB;
- if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC;
- pIdx->zColAff[n] = aff;
+ sqlite3OomFault(db);
+ return 0;
+ }
+ for(n=0; n<pIdx->nColumn; n++){
+ i16 x = pIdx->aiColumn[n];
+ char aff;
+ if( x>=0 ){
+ aff = pTab->aCol[x].affinity;
+ }else if( x==XN_ROWID ){
+ aff = SQLITE_AFF_INTEGER;
+ }else{
+ assert( x==XN_EXPR );
+ assert( pIdx->bHasExpr );
+ assert( pIdx->aColExpr!=0 );
+ aff = sqlite3ExprAffinity(pIdx->aColExpr->a[n].pExpr);
}
- pIdx->zColAff[n] = 0;
+ if( aff<SQLITE_AFF_BLOB ) aff = SQLITE_AFF_BLOB;
+ if( aff>SQLITE_AFF_NUMERIC) aff = SQLITE_AFF_NUMERIC;
+ pIdx->zColAff[n] = aff;
}
-
+ pIdx->zColAff[n] = 0;
return pIdx->zColAff;
}
+SQLITE_PRIVATE const char *sqlite3IndexAffinityStr(sqlite3 *db, Index *pIdx){
+ if( !pIdx->zColAff ) return computeIndexAffStr(db, pIdx);
+ return pIdx->zColAff;
+}
+
/*
** Compute an affinity string for a table. Space is obtained
@@ -129484,7 +130212,7 @@ SQLITE_PRIVATE void sqlite3Insert(
/* Cannot insert into a read-only table.
*/
- if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
+ if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto insert_cleanup;
}
@@ -129931,7 +130659,7 @@ SQLITE_PRIVATE void sqlite3Insert(
}
/* Copy the new data already generated. */
- assert( pTab->nNVCol>0 );
+ assert( pTab->nNVCol>0 || pParse->nErr>0 );
sqlite3VdbeAddOp3(v, OP_Copy, regRowid+1, regCols+1, pTab->nNVCol-1);
#ifndef SQLITE_OMIT_GENERATED_COLUMNS
@@ -133294,7 +134022,11 @@ static int sqlite3LoadExtension(
/* tag-20210611-1. Some dlopen() implementations will segfault if given
** an oversize filename. Most filesystems have a pathname limit of 4K,
** so limit the extension filename length to about twice that.
- ** https://sqlite.org/forum/forumpost/08a0d6d9bf */
+ ** https://sqlite.org/forum/forumpost/08a0d6d9bf
+ **
+ ** Later (2023-03-25): Save an extra 6 bytes for the filename suffix.
+ ** See https://sqlite.org/forum/forumpost/24083b579d.
+ */
if( nMsg>SQLITE_MAX_PATHLEN ) goto extension_not_found;
handle = sqlite3OsDlOpen(pVfs, zFile);
@@ -133302,7 +134034,9 @@ static int sqlite3LoadExtension(
for(ii=0; ii<ArraySize(azEndings) && handle==0; ii++){
char *zAltFile = sqlite3_mprintf("%s.%s", zFile, azEndings[ii]);
if( zAltFile==0 ) return SQLITE_NOMEM_BKPT;
- handle = sqlite3OsDlOpen(pVfs, zAltFile);
+ if( nMsg+strlen(azEndings[ii])+1<=SQLITE_MAX_PATHLEN ){
+ handle = sqlite3OsDlOpen(pVfs, zAltFile);
+ }
sqlite3_free(zAltFile);
}
#endif
@@ -135797,7 +136531,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
zDb = db->aDb[iDb].zDbSName;
sqlite3CodeVerifySchema(pParse, iDb);
sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
- if( pTab->nCol+regRow>pParse->nMem ) pParse->nMem = pTab->nCol + regRow;
+ sqlite3TouchRegister(pParse, pTab->nCol+regRow);
sqlite3OpenTable(pParse, 0, iDb, pTab, OP_OpenRead);
sqlite3VdbeLoadString(v, regResult, pTab->zName);
assert( IsOrdinaryTable(pTab) );
@@ -135838,7 +136572,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
** regRow..regRow+n. If any of the child key values are NULL, this
** row cannot cause an FK violation. Jump directly to addrOk in
** this case. */
- if( regRow+pFK->nCol>pParse->nMem ) pParse->nMem = regRow+pFK->nCol;
+ sqlite3TouchRegister(pParse, regRow + pFK->nCol);
for(j=0; j<pFK->nCol; j++){
int iCol = aiCols ? aiCols[j] : pFK->aCol[j].iFrom;
sqlite3ExprCodeGetColumnOfTable(v, pTab, 0, iCol, regRow+j);
@@ -135967,6 +136701,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
if( iDb>=0 && i!=iDb ) continue;
sqlite3CodeVerifySchema(pParse, i);
+ pParse->okConstFactor = 0; /* tag-20230327-1 */
/* Do an integrity check of the B-Tree
**
@@ -136002,7 +136737,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
aRoot[0] = cnt;
/* Make sure sufficient number of registers have been allocated */
- pParse->nMem = MAX( pParse->nMem, 8+mxIdx );
+ sqlite3TouchRegister(pParse, 8+mxIdx);
sqlite3ClearTempRegCache(pParse);
/* Do the b-tree integrity checks */
@@ -136152,15 +136887,29 @@ SQLITE_PRIVATE void sqlite3Pragma(
labelOk = sqlite3VdbeMakeLabel(pParse);
if( pCol->notNull ){
/* (1) NOT NULL columns may not contain a NULL */
+ int jmp3;
int jmp2 = sqlite3VdbeAddOp4Int(v, OP_IsType, p1, labelOk, p3, p4);
- sqlite3VdbeChangeP5(v, 0x0f);
VdbeCoverage(v);
+ if( p1<0 ){
+ sqlite3VdbeChangeP5(v, 0x0f); /* INT, REAL, TEXT, or BLOB */
+ jmp3 = jmp2;
+ }else{
+ sqlite3VdbeChangeP5(v, 0x0d); /* INT, TEXT, or BLOB */
+ /* OP_IsType does not detect NaN values in the database file
+ ** which should be treated as a NULL. So if the header type
+ ** is REAL, we have to load the actual data using OP_Column
+ ** to reliably determine if the value is a NULL. */
+ sqlite3VdbeAddOp3(v, OP_Column, p1, p3, 3);
+ jmp3 = sqlite3VdbeAddOp2(v, OP_NotNull, 3, labelOk);
+ VdbeCoverage(v);
+ }
zErr = sqlite3MPrintf(db, "NULL value in %s.%s", pTab->zName,
pCol->zCnName);
sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, zErr, P4_DYNAMIC);
if( doTypeCheck ){
sqlite3VdbeGoto(v, labelError);
sqlite3VdbeJumpHere(v, jmp2);
+ sqlite3VdbeJumpHere(v, jmp3);
}else{
/* VDBE byte code will fall thru */
}
@@ -136260,6 +137009,23 @@ SQLITE_PRIVATE void sqlite3Pragma(
jmp4 = integrityCheckResultRow(v);
sqlite3VdbeJumpHere(v, jmp2);
+ /* The OP_IdxRowid opcode is an optimized version of OP_Column
+ ** that extracts the rowid off the end of the index record.
+ ** But it only works correctly if index record does not have
+ ** any extra bytes at the end. Verify that this is the case. */
+ if( HasRowid(pTab) ){
+ int jmp7;
+ sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur+j, 3);
+ jmp7 = sqlite3VdbeAddOp3(v, OP_Eq, 3, 0, r1+pIdx->nColumn-1);
+ VdbeCoverageNeverNull(v);
+ sqlite3VdbeLoadString(v, 3,
+ "rowid not at end-of-record for row ");
+ sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
+ sqlite3VdbeLoadString(v, 4, " of index ");
+ sqlite3VdbeGoto(v, jmp5-1);
+ sqlite3VdbeJumpHere(v, jmp7);
+ }
+
/* Any indexed columns with non-BINARY collations must still hold
** the exact same text value as the table. */
label6 = 0;
@@ -137457,7 +138223,9 @@ SQLITE_PRIVATE int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFl
#else
encoding = SQLITE_UTF8;
#endif
- if( db->nVdbeActive>0 && encoding!=ENC(db) ){
+ if( db->nVdbeActive>0 && encoding!=ENC(db)
+ && (db->mDbFlags & DBFLAG_Vacuum)==0
+ ){
rc = SQLITE_LOCKED;
goto initone_error_out;
}else{
@@ -137851,7 +138619,11 @@ static int sqlite3Prepare(
sParse.db = db;
sParse.pReprepare = pReprepare;
assert( ppStmt && *ppStmt==0 );
- if( db->mallocFailed ) sqlite3ErrorMsg(&sParse, "out of memory");
+ if( db->mallocFailed ){
+ sqlite3ErrorMsg(&sParse, "out of memory");
+ db->errCode = rc = SQLITE_NOMEM;
+ goto end_prepare;
+ }
assert( sqlite3_mutex_held(db->mutex) );
/* For a long-term use prepared statement avoid the use of
@@ -138940,7 +139712,7 @@ static void pushOntoSorter(
** (2) All output columns are included in the sort record. In that
** case regData==regOrigData.
** (3) Some output columns are omitted from the sort record due to
- ** the SQLITE_ENABLE_SORTER_REFERENCE optimization, or due to the
+ ** the SQLITE_ENABLE_SORTER_REFERENCES optimization, or due to the
** SQLITE_ECEL_OMITREF optimization, or due to the
** SortCtx.pDeferredRowLoad optimiation. In any of these cases
** regOrigData is 0 to prevent this routine from trying to copy
@@ -140541,7 +141313,7 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(
assert( (pSelect->selFlags & SF_Resolved)!=0 );
assert( pTab->nCol==pSelect->pEList->nExpr || pParse->nErr>0 );
assert( aff==SQLITE_AFF_NONE || aff==SQLITE_AFF_BLOB );
- if( db->mallocFailed ) return;
+ if( db->mallocFailed || IN_RENAME_OBJECT ) return;
while( pSelect->pPrior ) pSelect = pSelect->pPrior;
a = pSelect->pEList->a;
memset(&sNC, 0, sizeof(sNC));
@@ -140555,8 +141327,6 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(
pCol->affinity = sqlite3ExprAffinity(p);
if( pCol->affinity<=SQLITE_AFF_NONE ){
pCol->affinity = aff;
- }else if( pCol->affinity>=SQLITE_AFF_NUMERIC && p->op==TK_CAST ){
- pCol->affinity = SQLITE_AFF_FLEXNUM;
}
if( pCol->affinity>=SQLITE_AFF_TEXT && pSelect->pNext ){
int m = 0;
@@ -140570,6 +141340,9 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(
if( pCol->affinity>=SQLITE_AFF_NUMERIC && (m&0x02)!=0 ){
pCol->affinity = SQLITE_AFF_BLOB;
}
+ if( pCol->affinity>=SQLITE_AFF_NUMERIC && p->op==TK_CAST ){
+ pCol->affinity = SQLITE_AFF_FLEXNUM;
+ }
}
zType = columnType(&sNC, p, 0, 0, 0);
if( zType==0 || pCol->affinity!=sqlite3AffinityType(zType, 0) ){
@@ -140585,18 +141358,16 @@ SQLITE_PRIVATE void sqlite3SubqueryColumnTypes(
break;
}
}
- }
- }
- if( zType ){
- i64 m = sqlite3Strlen30(zType);
- n = sqlite3Strlen30(pCol->zCnName);
- pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2);
- if( pCol->zCnName ){
- memcpy(&pCol->zCnName[n+1], zType, m+1);
- pCol->colFlags |= COLFLAG_HASTYPE;
- }else{
- testcase( pCol->colFlags & COLFLAG_HASTYPE );
- pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
+ }
+ }
+ if( zType ){
+ i64 m = sqlite3Strlen30(zType);
+ n = sqlite3Strlen30(pCol->zCnName);
+ pCol->zCnName = sqlite3DbReallocOrFree(db, pCol->zCnName, n+m+2);
+ pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL);
+ if( pCol->zCnName ){
+ memcpy(&pCol->zCnName[n+1], zType, m+1);
+ pCol->colFlags |= COLFLAG_HASTYPE;
}
}
pColl = sqlite3ExprCollSeq(pParse, p);
@@ -142084,7 +142855,9 @@ static Expr *substExpr(
sqlite3VectorErrorMsg(pSubst->pParse, pCopy);
}else{
sqlite3 *db = pSubst->pParse->db;
- if( pSubst->isOuterJoin && pCopy->op!=TK_COLUMN ){
+ if( pSubst->isOuterJoin
+ && (pCopy->op!=TK_COLUMN || pCopy->iTable!=pSubst->iNewTable)
+ ){
memset(&ifNullRow, 0, sizeof(ifNullRow));
ifNullRow.op = TK_IF_NULL_ROW;
ifNullRow.pLeft = pCopy;
@@ -142461,8 +143234,7 @@ static int compoundHasDifferentAffinities(Select *p){
** query or there are no RIGHT or FULL JOINs in any arm
** of the subquery. (This is a duplicate of condition (27b).)
** (17h) The corresponding result set expressions in all arms of the
-** compound must have the same affinity. (See restriction (9)
-** on the push-down optimization.)
+** compound must have the same affinity.
**
** The parent and sub-query may contain WHERE clauses. Subject to
** rules (11), (13) and (14), they may also contain ORDER BY,
@@ -143330,10 +144102,24 @@ static int pushDownWindowCheck(Parse *pParse, Select *pSubq, Expr *pExpr){
** or EXCEPT, then all of the result set columns for all arms of
** the compound must use the BINARY collating sequence.
**
-** (9) If the subquery is a compound, then all arms of the compound must
-** have the same affinity. (This is the same as restriction (17h)
-** for query flattening.)
+** (9) All three of the following are true:
+**
+** (9a) The WHERE clause expression originates in the ON or USING clause
+** of a join (either an INNER or an OUTER join), and
+**
+** (9b) The subquery is to the right of the ON/USING clause
**
+** (9c) There is a RIGHT JOIN (or FULL JOIN) in between the ON/USING
+** clause and the subquery.
+**
+** Without this restriction, the push-down optimization might move
+** the ON/USING filter expression from the left side of a RIGHT JOIN
+** over to the right side, which leads to incorrect answers. See
+** also restriction (6) in sqlite3ExprIsSingleTableConstraint().
+**
+** (10) The inner query is not the right-hand table of a RIGHT JOIN.
+**
+** (11) The subquery is not a VALUES clause
**
** Return 0 if no changes are made and non-zero if one or more WHERE clause
** terms are duplicated into the subquery.
@@ -143342,13 +144128,20 @@ static int pushDownWhereTerms(
Parse *pParse, /* Parse context (for malloc() and error reporting) */
Select *pSubq, /* The subquery whose WHERE clause is to be augmented */
Expr *pWhere, /* The WHERE clause of the outer query */
- SrcItem *pSrc /* The subquery term of the outer FROM clause */
+ SrcList *pSrcList, /* The complete from clause of the outer query */
+ int iSrc /* Which FROM clause term to try to push into */
){
Expr *pNew;
+ SrcItem *pSrc; /* The subquery FROM term into which WHERE is pushed */
int nChng = 0;
+ pSrc = &pSrcList->a[iSrc];
if( pWhere==0 ) return 0;
- if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ) return 0;
- if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ) return 0;
+ if( pSubq->selFlags & (SF_Recursive|SF_MultiPart) ){
+ return 0; /* restrictions (2) and (11) */
+ }
+ if( pSrc->fg.jointype & (JT_LTORJ|JT_RIGHT) ){
+ return 0; /* restrictions (10) */
+ }
if( pSubq->pPrior ){
Select *pSel;
@@ -143364,9 +144157,6 @@ static int pushDownWhereTerms(
if( pSel->pWin ) return 0; /* restriction (6b) */
#endif
}
- if( compoundHasDifferentAffinities(pSubq) ){
- return 0; /* restriction (9) */
- }
if( notUnionAll ){
/* If any of the compound arms are connected using UNION, INTERSECT,
** or EXCEPT, then we must ensure that none of the columns use a
@@ -143406,11 +144196,28 @@ static int pushDownWhereTerms(
return 0; /* restriction (3) */
}
while( pWhere->op==TK_AND ){
- nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrc);
+ nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, pSrcList, iSrc);
pWhere = pWhere->pLeft;
}
-#if 0 /* Legacy code. Checks now done by sqlite3ExprIsTableConstraint() */
+#if 0 /* These checks now done by sqlite3ExprIsSingleTableConstraint() */
+ if( ExprHasProperty(pWhere, EP_OuterON|EP_InnerON) /* (9a) */
+ && (pSrcList->a[0].fg.jointype & JT_LTORJ)!=0 /* Fast pre-test of (9c) */
+ ){
+ int jj;
+ for(jj=0; jj<iSrc; jj++){
+ if( pWhere->w.iJoin==pSrcList->a[jj].iCursor ){
+ /* If we reach this point, both (9a) and (9b) are satisfied.
+ ** The following loop checks (9c):
+ */
+ for(jj++; jj<iSrc; jj++){
+ if( (pSrcList->a[jj].fg.jointype & JT_RIGHT)!=0 ){
+ return 0; /* restriction (9) */
+ }
+ }
+ }
+ }
+ }
if( isLeftJoin
&& (ExprHasProperty(pWhere,EP_OuterON)==0
|| pWhere->w.iJoin!=iCursor)
@@ -143424,7 +144231,7 @@ static int pushDownWhereTerms(
}
#endif
- if( sqlite3ExprIsTableConstraint(pWhere, pSrc) ){
+ if( sqlite3ExprIsSingleTableConstraint(pWhere, pSrcList, iSrc) ){
nChng++;
pSubq->selFlags |= SF_PushDown;
while( pSubq ){
@@ -143459,6 +144266,78 @@ static int pushDownWhereTerms(
#endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */
/*
+** Check to see if a subquery contains result-set columns that are
+** never used. If it does, change the value of those result-set columns
+** to NULL so that they do not cause unnecessary work to compute.
+**
+** Return the number of column that were changed to NULL.
+*/
+static int disableUnusedSubqueryResultColumns(SrcItem *pItem){
+ int nCol;
+ Select *pSub; /* The subquery to be simplified */
+ Select *pX; /* For looping over compound elements of pSub */
+ Table *pTab; /* The table that describes the subquery */
+ int j; /* Column number */
+ int nChng = 0; /* Number of columns converted to NULL */
+ Bitmask colUsed; /* Columns that may not be NULLed out */
+
+ assert( pItem!=0 );
+ if( pItem->fg.isCorrelated || pItem->fg.isCte ){
+ return 0;
+ }
+ assert( pItem->pTab!=0 );
+ pTab = pItem->pTab;
+ assert( pItem->pSelect!=0 );
+ pSub = pItem->pSelect;
+ assert( pSub->pEList->nExpr==pTab->nCol );
+ if( (pSub->selFlags & (SF_Distinct|SF_Aggregate))!=0 ){
+ testcase( pSub->selFlags & SF_Distinct );
+ testcase( pSub->selFlags & SF_Aggregate );
+ return 0;
+ }
+ for(pX=pSub; pX; pX=pX->pPrior){
+ if( pX->pPrior && pX->op!=TK_ALL ){
+ /* This optimization does not work for compound subqueries that
+ ** use UNION, INTERSECT, or EXCEPT. Only UNION ALL is allowed. */
+ return 0;
+ }
+#ifndef SQLITE_OMIT_WINDOWFUNC
+ if( pX->pWin ){
+ /* This optimization does not work for subqueries that use window
+ ** functions. */
+ return 0;
+ }
+#endif
+ }
+ colUsed = pItem->colUsed;
+ if( pSub->pOrderBy ){
+ ExprList *pList = pSub->pOrderBy;
+ for(j=0; j<pList->nExpr; j++){
+ u16 iCol = pList->a[j].u.x.iOrderByCol;
+ if( iCol>0 ){
+ iCol--;
+ colUsed |= ((Bitmask)1)<<(iCol>=BMS ? BMS-1 : iCol);
+ }
+ }
+ }
+ nCol = pTab->nCol;
+ for(j=0; j<nCol; j++){
+ Bitmask m = j<BMS-1 ? MASKBIT(j) : TOPBIT;
+ if( (m & colUsed)!=0 ) continue;
+ for(pX=pSub; pX; pX=pX->pPrior) {
+ Expr *pY = pX->pEList->a[j].pExpr;
+ if( pY->op==TK_NULL ) continue;
+ pY->op = TK_NULL;
+ ExprClearProperty(pY, EP_Skip|EP_Unlikely);
+ pX->selFlags |= SF_PushDown;
+ nChng++;
+ }
+ }
+ return nChng;
+}
+
+
+/*
** The pFunc is the only aggregate function in the query. Check to see
** if the query is a candidate for the min/max optimization.
**
@@ -144600,14 +145479,17 @@ static void optimizeAggregateUseOfIndexedExpr(
NameContext *pNC /* Name context used to resolve agg-func args */
){
assert( pAggInfo->iFirstReg==0 );
+ assert( pSelect!=0 );
+ assert( pSelect->pGroupBy!=0 );
pAggInfo->nColumn = pAggInfo->nAccumulator;
if( ALWAYS(pAggInfo->nSortingColumn>0) ){
- if( pAggInfo->nColumn==0 ){
- pAggInfo->nSortingColumn = 0;
- }else{
- pAggInfo->nSortingColumn =
- pAggInfo->aCol[pAggInfo->nColumn-1].iSorterColumn+1;
+ int mx = pSelect->pGroupBy->nExpr - 1;
+ int j, k;
+ for(j=0; j<pAggInfo->nColumn; j++){
+ k = pAggInfo->aCol[j].iSorterColumn;
+ if( k>mx ) mx = k;
}
+ pAggInfo->nSortingColumn = mx+1;
}
analyzeAggFuncArgs(pAggInfo, pNC);
#if TREETRACE_ENABLED
@@ -144641,11 +145523,13 @@ static int aggregateIdxEprRefToColCallback(Walker *pWalker, Expr *pExpr){
if( pExpr->op==TK_AGG_FUNCTION ) return WRC_Continue;
if( pExpr->op==TK_IF_NULL_ROW ) return WRC_Continue;
pAggInfo = pExpr->pAggInfo;
- assert( pExpr->iAgg>=0 && pExpr->iAgg<pAggInfo->nColumn );
+ if( NEVER(pExpr->iAgg>=pAggInfo->nColumn) ) return WRC_Continue;
+ assert( pExpr->iAgg>=0 );
pCol = &pAggInfo->aCol[pExpr->iAgg];
pExpr->op = TK_AGG_COLUMN;
pExpr->iTable = pCol->iTable;
pExpr->iColumn = pCol->iColumn;
+ ExprClearProperty(pExpr, EP_Skip|EP_Collate);
return WRC_Prune;
}
@@ -144999,7 +145883,6 @@ static void agginfoFree(sqlite3 *db, AggInfo *p){
sqlite3DbFreeNN(db, p);
}
-#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
/*
** Attempt to transform a query of the form
**
@@ -145027,7 +145910,9 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
if( (p->selFlags & SF_Aggregate)==0 ) return 0; /* This is an aggregate */
if( p->pEList->nExpr!=1 ) return 0; /* Single result column */
if( p->pWhere ) return 0;
+ if( p->pHaving ) return 0;
if( p->pGroupBy ) return 0;
+ if( p->pOrderBy ) return 0;
pExpr = p->pEList->a[0].pExpr;
if( pExpr->op!=TK_AGG_FUNCTION ) return 0; /* Result is an aggregate */
assert( ExprUseUToken(pExpr) );
@@ -145038,13 +145923,15 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
if( ExprHasProperty(pExpr, EP_WinFunc) ) return 0;/* Not a window function */
pSub = p->pSrc->a[0].pSelect;
if( pSub==0 ) return 0; /* The FROM is a subquery */
- if( pSub->pPrior==0 ) return 0; /* Must be a compound ry */
+ if( pSub->pPrior==0 ) return 0; /* Must be a compound */
+ if( pSub->selFlags & SF_CopyCte ) return 0; /* Not a CTE */
do{
if( pSub->op!=TK_ALL && pSub->pPrior ) return 0; /* Must be UNION ALL */
if( pSub->pWhere ) return 0; /* No WHERE clause */
if( pSub->pLimit ) return 0; /* No LIMIT clause */
if( pSub->selFlags & SF_Aggregate ) return 0; /* Not an aggregate */
- pSub = pSub->pPrior; /* Repeat over compound */
+ assert( pSub->pHaving==0 ); /* Due to the previous */
+ pSub = pSub->pPrior; /* Repeat over compound */
}while( pSub );
/* If we reach this point then it is OK to perform the transformation */
@@ -145087,7 +145974,6 @@ static int countOfViewOptimization(Parse *pParse, Select *p){
#endif
return 1;
}
-#endif /* SQLITE_COUNTOFVIEW_OPTIMIZATION */
/*
** If any term of pSrc, or any SF_NestedFrom sub-query, is not the same
@@ -145343,7 +146229,7 @@ SQLITE_PRIVATE int sqlite3Select(
pTabList->a[0].fg.jointype & JT_LTORJ);
}
- /* No futher action if this term of the FROM clause is no a subquery */
+ /* No futher action if this term of the FROM clause is not a subquery */
if( pSub==0 ) continue;
/* Catch mismatch in the declared columns of a view and the number of
@@ -145476,15 +146362,12 @@ SQLITE_PRIVATE int sqlite3Select(
TREETRACE(0x2000,pParse,p,("Constant propagation not helpful\n"));
}
-#ifdef SQLITE_COUNTOFVIEW_OPTIMIZATION
if( OptimizationEnabled(db, SQLITE_QueryFlattener|SQLITE_CountOfView)
&& countOfViewOptimization(pParse, p)
){
if( db->mallocFailed ) goto select_end;
- pEList = p->pEList;
pTabList = p->pSrc;
}
-#endif
/* For each term in the FROM clause, do two things:
** (1) Authorized unreferenced tables
@@ -145543,7 +146426,7 @@ SQLITE_PRIVATE int sqlite3Select(
if( OptimizationEnabled(db, SQLITE_PushDown)
&& (pItem->fg.isCte==0
|| (pItem->u2.pCteUse->eM10d!=M10d_Yes && pItem->u2.pCteUse->nUse<2))
- && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem)
+ && pushDownWhereTerms(pParse, pSub, p->pWhere, pTabList, i)
){
#if TREETRACE_ENABLED
if( sqlite3TreeTrace & 0x4000 ){
@@ -145557,6 +146440,22 @@ SQLITE_PRIVATE int sqlite3Select(
TREETRACE(0x4000,pParse,p,("Push-down not possible\n"));
}
+ /* Convert unused result columns of the subquery into simple NULL
+ ** expressions, to avoid unneeded searching and computation.
+ */
+ if( OptimizationEnabled(db, SQLITE_NullUnusedCols)
+ && disableUnusedSubqueryResultColumns(pItem)
+ ){
+#if TREETRACE_ENABLED
+ if( sqlite3TreeTrace & 0x4000 ){
+ TREETRACE(0x4000,pParse,p,
+ ("Change unused result columns to NULL for subquery %d:\n",
+ pSub->selId));
+ sqlite3TreeViewSelect(0, p, 0);
+ }
+#endif
+ }
+
zSavedAuthContext = pParse->zAuthContext;
pParse->zAuthContext = pItem->zName;
@@ -146843,6 +147742,7 @@ SQLITE_PRIVATE void sqlite3BeginTrigger(
}else{
assert( !db->init.busy );
sqlite3CodeVerifySchema(pParse, iDb);
+ VVA_ONLY( pParse->ifNotExists = 1; )
}
goto trigger_cleanup;
}
@@ -147624,7 +148524,7 @@ static void codeReturningTrigger(
}
sqlite3ExprListDelete(db, sSelect.pEList);
pNew = sqlite3ExpandReturning(pParse, pReturning->pReturnEL, pTab);
- if( !db->mallocFailed ){
+ if( pParse->nErr==0 ){
NameContext sNC;
memset(&sNC, 0, sizeof(sNC));
if( pReturning->nRetCol==0 ){
@@ -148093,6 +148993,9 @@ SQLITE_PRIVATE u32 sqlite3TriggerColmask(
Trigger *p;
assert( isNew==1 || isNew==0 );
+ if( IsView(pTab) ){
+ return 0xffffffff;
+ }
for(p=pTrigger; p; p=p->pNext){
if( p->op==op
&& (tr_tm&p->tr_tm)
@@ -148527,7 +149430,7 @@ SQLITE_PRIVATE void sqlite3Update(
if( sqlite3ViewGetColumnNames(pParse, pTab) ){
goto update_cleanup;
}
- if( sqlite3IsReadOnly(pParse, pTab, tmask) ){
+ if( sqlite3IsReadOnly(pParse, pTab, pTrigger) ){
goto update_cleanup;
}
@@ -148846,12 +149749,22 @@ SQLITE_PRIVATE void sqlite3Update(
/* Begin the database scan.
**
** Do not consider a single-pass strategy for a multi-row update if
- ** there are any triggers or foreign keys to process, or rows may
- ** be deleted as a result of REPLACE conflict handling. Any of these
- ** things might disturb a cursor being used to scan through the table
- ** or index, causing a single-pass approach to malfunction. */
+ ** there is anything that might disrupt the cursor being used to do
+ ** the UPDATE:
+ ** (1) This is a nested UPDATE
+ ** (2) There are triggers
+ ** (3) There are FOREIGN KEY constraints
+ ** (4) There are REPLACE conflict handlers
+ ** (5) There are subqueries in the WHERE clause
+ */
flags = WHERE_ONEPASS_DESIRED;
- if( !pParse->nested && !pTrigger && !hasFK && !chngKey && !bReplace ){
+ if( !pParse->nested
+ && !pTrigger
+ && !hasFK
+ && !chngKey
+ && !bReplace
+ && (sNC.ncFlags & NC_Subquery)==0
+ ){
flags |= WHERE_ONEPASS_MULTIROW;
}
pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere,0,0,0,flags,iIdxCur);
@@ -150816,7 +151729,9 @@ static int vtabCallConstructor(
sCtx.pPrior = db->pVtabCtx;
sCtx.bDeclared = 0;
db->pVtabCtx = &sCtx;
+ pTab->nTabRef++;
rc = xConstruct(db, pMod->pAux, nArg, azArg, &pVTable->pVtab, &zErr);
+ sqlite3DeleteTable(db, pTab);
db->pVtabCtx = sCtx.pPrior;
if( rc==SQLITE_NOMEM ) sqlite3OomFault(db);
assert( sCtx.pTab==pTab );
@@ -151306,7 +152221,10 @@ SQLITE_PRIVATE int sqlite3VtabSavepoint(sqlite3 *db, int op, int iSavepoint){
break;
}
if( xMethod && pVTab->iSavepoint>iSavepoint ){
+ u64 savedFlags = (db->flags & SQLITE_Defensive);
+ db->flags &= ~(u64)SQLITE_Defensive;
rc = xMethod(pVTab->pVtab, iSavepoint);
+ db->flags |= savedFlags;
}
sqlite3VtabUnlock(pVTab);
}
@@ -151535,6 +152453,10 @@ SQLITE_API int sqlite3_vtab_config(sqlite3 *db, int op, ...){
p->pVTable->eVtabRisk = SQLITE_VTABRISK_High;
break;
}
+ case SQLITE_VTAB_USES_ALL_SCHEMAS: {
+ p->pVTable->bAllSchemas = 1;
+ break;
+ }
default: {
rc = SQLITE_MISUSE_BKPT;
break;
@@ -152308,9 +153230,9 @@ static void explainIndexRange(StrAccum *pStr, WhereLoop *pLoop){
/*
** This function is a no-op unless currently processing an EXPLAIN QUERY PLAN
-** command, or if either SQLITE_DEBUG or SQLITE_ENABLE_STMT_SCANSTATUS was
-** defined at compile-time. If it is not a no-op, a single OP_Explain opcode
-** is added to the output to describe the table scan strategy in pLevel.
+** command, or if stmt_scanstatus_v2() stats are enabled, or if SQLITE_DEBUG
+** was defined at compile-time. If it is not a no-op, a single OP_Explain
+** opcode is added to the output to describe the table scan strategy in pLevel.
**
** If an OP_Explain opcode is added to the VM, its address is returned.
** Otherwise, if no OP_Explain is coded, zero is returned.
@@ -152322,8 +153244,8 @@ SQLITE_PRIVATE int sqlite3WhereExplainOneScan(
u16 wctrlFlags /* Flags passed to sqlite3WhereBegin() */
){
int ret = 0;
-#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS)
- if( sqlite3ParseToplevel(pParse)->explain==2 )
+#if !defined(SQLITE_DEBUG)
+ if( sqlite3ParseToplevel(pParse)->explain==2 || IS_STMT_SCANSTATUS(pParse->db) )
#endif
{
SrcItem *pItem = &pTabList->a[pLevel->iFrom];
@@ -152489,27 +153411,29 @@ SQLITE_PRIVATE void sqlite3WhereAddScanStatus(
WhereLevel *pLvl, /* Level to add scanstatus() entry for */
int addrExplain /* Address of OP_Explain (or 0) */
){
- const char *zObj = 0;
- WhereLoop *pLoop = pLvl->pWLoop;
- int wsFlags = pLoop->wsFlags;
- int viaCoroutine = 0;
-
- if( (wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
- zObj = pLoop->u.btree.pIndex->zName;
- }else{
- zObj = pSrclist->a[pLvl->iFrom].zName;
- viaCoroutine = pSrclist->a[pLvl->iFrom].fg.viaCoroutine;
- }
- sqlite3VdbeScanStatus(
- v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
- );
+ if( IS_STMT_SCANSTATUS( sqlite3VdbeDb(v) ) ){
+ const char *zObj = 0;
+ WhereLoop *pLoop = pLvl->pWLoop;
+ int wsFlags = pLoop->wsFlags;
+ int viaCoroutine = 0;
- if( viaCoroutine==0 ){
- if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){
- sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur);
+ if( (wsFlags & WHERE_VIRTUALTABLE)==0 && pLoop->u.btree.pIndex!=0 ){
+ zObj = pLoop->u.btree.pIndex->zName;
+ }else{
+ zObj = pSrclist->a[pLvl->iFrom].zName;
+ viaCoroutine = pSrclist->a[pLvl->iFrom].fg.viaCoroutine;
}
- if( wsFlags & WHERE_INDEXED ){
- sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
+ sqlite3VdbeScanStatus(
+ v, addrExplain, pLvl->addrBody, pLvl->addrVisit, pLoop->nOut, zObj
+ );
+
+ if( viaCoroutine==0 ){
+ if( (wsFlags & (WHERE_MULTI_OR|WHERE_AUTO_INDEX))==0 ){
+ sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iTabCur);
+ }
+ if( wsFlags & WHERE_INDEXED ){
+ sqlite3VdbeScanStatusRange(v, addrExplain, -1, pLvl->iIdxCur);
+ }
}
}
}
@@ -153206,11 +154130,12 @@ static int codeCursorHintIsOrFunction(Walker *pWalker, Expr *pExpr){
*/
static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
int rc = WRC_Continue;
+ int reg;
struct CCurHint *pHint = pWalker->u.pCCurHint;
if( pExpr->op==TK_COLUMN ){
if( pExpr->iTable!=pHint->iTabCur ){
- int reg = ++pWalker->pParse->nMem; /* Register for column value */
- sqlite3ExprCode(pWalker->pParse, pExpr, reg);
+ reg = ++pWalker->pParse->nMem; /* Register for column value */
+ reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
pExpr->op = TK_REGISTER;
pExpr->iTable = reg;
}else if( pHint->pIdx!=0 ){
@@ -153218,15 +154143,15 @@ static int codeCursorHintFixExpr(Walker *pWalker, Expr *pExpr){
pExpr->iColumn = sqlite3TableColumnToIndex(pHint->pIdx, pExpr->iColumn);
assert( pExpr->iColumn>=0 );
}
- }else if( pExpr->op==TK_AGG_FUNCTION ){
- /* An aggregate function in the WHERE clause of a query means this must
- ** be a correlated sub-query, and expression pExpr is an aggregate from
- ** the parent context. Do not walk the function arguments in this case.
- **
- ** todo: It should be possible to replace this node with a TK_REGISTER
- ** expression, as the result of the expression must be stored in a
- ** register at this point. The same holds for TK_AGG_COLUMN nodes. */
+ }else if( pExpr->pAggInfo ){
rc = WRC_Prune;
+ reg = ++pWalker->pParse->nMem; /* Register for column value */
+ reg = sqlite3ExprCodeTarget(pWalker->pParse, pExpr, reg);
+ pExpr->op = TK_REGISTER;
+ pExpr->iTable = reg;
+ }else if( pExpr->op==TK_TRUEFALSE ){
+ /* Do not walk disabled expressions. tag-20230504-1 */
+ return WRC_Prune;
}
return rc;
}
@@ -153328,7 +154253,7 @@ static void codeCursorHint(
}
if( pExpr!=0 ){
sWalker.xExprCallback = codeCursorHintFixExpr;
- sqlite3WalkExpr(&sWalker, pExpr);
+ if( pParse->nErr==0 ) sqlite3WalkExpr(&sWalker, pExpr);
sqlite3VdbeAddOp4(v, OP_CursorHint,
(sHint.pIdx ? sHint.iIdxCur : sHint.iTabCur), 0, 0,
(const char*)pExpr, P4_EXPR);
@@ -154122,7 +155047,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
** guess. */
addrSeekScan = sqlite3VdbeAddOp1(v, OP_SeekScan,
(pIdx->aiRowLogEst[0]+9)/10);
- if( pRangeStart ){
+ if( pRangeStart || pRangeEnd ){
sqlite3VdbeChangeP5(v, 1);
sqlite3VdbeChangeP2(v, addrSeekScan, sqlite3VdbeCurrentAddr(v)+1);
addrSeekScan = 0;
@@ -154163,16 +155088,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
assert( pLevel->p2==0 );
if( pRangeEnd ){
Expr *pRight = pRangeEnd->pExpr->pRight;
- if( addrSeekScan ){
- /* For a seek-scan that has a range on the lowest term of the index,
- ** we have to make the top of the loop be code that sets the end
- ** condition of the range. Otherwise, the OP_SeekScan might jump
- ** over that initialization, leaving the range-end value set to the
- ** range-start value, resulting in a wrong answer.
- ** See ticket 5981a8c041a3c2f3 (2021-11-02).
- */
- pLevel->p2 = sqlite3VdbeCurrentAddr(v);
- }
+ assert( addrSeekScan==0 );
codeExprOrVector(pParse, pRight, regBase+nEq, nTop);
whereLikeOptimizationStringFixup(v, pLevel, pRangeEnd);
if( (pRangeEnd->wtFlags & TERM_VNULL)==0
@@ -154206,7 +155122,7 @@ SQLITE_PRIVATE Bitmask sqlite3WhereCodeOneLoopStart(
if( zEndAff ) sqlite3DbNNFreeNN(db, zEndAff);
/* Top of the loop body */
- if( pLevel->p2==0 ) pLevel->p2 = sqlite3VdbeCurrentAddr(v);
+ pLevel->p2 = sqlite3VdbeCurrentAddr(v);
/* Check if the index cursor is past the end of the range. */
if( nConstraint ){
@@ -156203,7 +157119,7 @@ static void exprAnalyze(
&& 0==sqlite3ExprCanBeNull(pLeft)
){
assert( !ExprHasProperty(pExpr, EP_IntValue) );
- pExpr->op = TK_TRUEFALSE;
+ pExpr->op = TK_TRUEFALSE; /* See tag-20230504-1 */
pExpr->u.zToken = "false";
ExprSetProperty(pExpr, EP_IsFalse);
pTerm->prereqAll = 0;
@@ -156848,9 +157764,12 @@ SQLITE_PRIVATE void sqlite3WhereTabFuncArgs(
pRhs = sqlite3PExpr(pParse, TK_UPLUS,
sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0);
pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs);
- if( pItem->fg.jointype & (JT_LEFT|JT_LTORJ) ){
+ if( pItem->fg.jointype & (JT_LEFT|JT_RIGHT) ){
+ testcase( pItem->fg.jointype & JT_LEFT ); /* testtag-20230227a */
+ testcase( pItem->fg.jointype & JT_RIGHT ); /* testtag-20230227b */
joinType = EP_OuterON;
}else{
+ testcase( pItem->fg.jointype & JT_LTORJ ); /* testtag-20230227c */
joinType = EP_InnerON;
}
sqlite3SetJoinExpr(pTerm, pItem->iCursor, joinType);
@@ -157693,7 +158612,7 @@ static void explainAutomaticIndex(
int bPartial, /* True if pIdx is a partial index */
int *pAddrExplain /* OUT: Address of OP_Explain */
){
- if( pParse->explain!=2 ){
+ if( IS_STMT_SCANSTATUS(pParse->db) && pParse->explain!=2 ){
Table *pTab = pIdx->pTable;
const char *zSep = "";
char *zText = 0;
@@ -157732,8 +158651,7 @@ static void explainAutomaticIndex(
*/
static SQLITE_NOINLINE void constructAutomaticIndex(
Parse *pParse, /* The parsing context */
- const WhereClause *pWC, /* The WHERE clause */
- const SrcItem *pSrc, /* The FROM clause term to get the next index */
+ WhereClause *pWC, /* The WHERE clause */
const Bitmask notReady, /* Mask of cursors that are not available */
WhereLevel *pLevel /* Write new index here */
){
@@ -157754,10 +158672,12 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
char *zNotUsed; /* Extra space on the end of pIdx */
Bitmask idxCols; /* Bitmap of columns used for indexing */
Bitmask extraCols; /* Bitmap of additional columns */
- u8 sentWarning = 0; /* True if a warnning has been issued */
+ u8 sentWarning = 0; /* True if a warning has been issued */
+ u8 useBloomFilter = 0; /* True to also add a Bloom filter */
Expr *pPartial = 0; /* Partial Index Expression */
int iContinue = 0; /* Jump here to skip excluded rows */
- SrcItem *pTabItem; /* FROM clause term being indexed */
+ SrcList *pTabList; /* The complete FROM clause */
+ SrcItem *pSrc; /* The FROM clause term to get the next index */
int addrCounter = 0; /* Address where integer counter is initialized */
int regBase; /* Array of registers where record is assembled */
#ifdef SQLITE_ENABLE_STMT_SCANSTATUS
@@ -157773,6 +158693,8 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
/* Count the number of columns that will be added to the index
** and used to match WHERE clause constraints */
nKeyCol = 0;
+ pTabList = pWC->pWInfo->pTabList;
+ pSrc = &pTabList->a[pLevel->iFrom];
pTable = pSrc->pTab;
pWCEnd = &pWC->a[pWC->nTerm];
pLoop = pLevel->pWLoop;
@@ -157783,7 +158705,7 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
** WHERE clause (or the ON clause of a LEFT join) that constrain which
** rows of the target table (pSrc) that can be used. */
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
- && sqlite3ExprIsTableConstraint(pExpr, pSrc)
+ && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, pLevel->iFrom)
){
pPartial = sqlite3ExprAnd(pParse, pPartial,
sqlite3ExprDup(pParse->db, pExpr, 0));
@@ -157824,7 +158746,11 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
** original table changes and the index and table cannot both be used
** if they go out of sync.
*/
- extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
+ if( IsView(pTable) ){
+ extraCols = ALLBITS;
+ }else{
+ extraCols = pSrc->colUsed & (~idxCols | MASKBIT(BMS-1));
+ }
mxBitCol = MIN(BMS-1,pTable->nCol);
testcase( pTable->nCol==BMS-1 );
testcase( pTable->nCol==BMS-2 );
@@ -157860,6 +158786,16 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
assert( pColl!=0 || pParse->nErr>0 ); /* TH3 collate01.800 */
pIdx->azColl[n] = pColl ? pColl->zName : sqlite3StrBINARY;
n++;
+ if( ALWAYS(pX->pLeft!=0)
+ && sqlite3ExprAffinity(pX->pLeft)!=SQLITE_AFF_TEXT
+ ){
+ /* TUNING: only use a Bloom filter on an automatic index
+ ** if one or more key columns has the ability to hold numeric
+ ** values, since strings all have the same hash in the Bloom
+ ** filter implementation and hence a Bloom filter on a text column
+ ** is not usually helpful. */
+ useBloomFilter = 1;
+ }
}
}
}
@@ -157892,20 +158828,21 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
sqlite3VdbeAddOp2(v, OP_OpenAutoindex, pLevel->iIdxCur, nKeyCol+1);
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
VdbeComment((v, "for %s", pTable->zName));
- if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) ){
+ if( OptimizationEnabled(pParse->db, SQLITE_BloomFilter) && useBloomFilter ){
+ sqlite3WhereExplainBloomFilter(pParse, pWC->pWInfo, pLevel);
pLevel->regFilter = ++pParse->nMem;
sqlite3VdbeAddOp2(v, OP_Blob, 10000, pLevel->regFilter);
}
/* Fill the automatic index with content */
- pTabItem = &pWC->pWInfo->pTabList->a[pLevel->iFrom];
- if( pTabItem->fg.viaCoroutine ){
- int regYield = pTabItem->regReturn;
+ assert( pSrc == &pWC->pWInfo->pTabList->a[pLevel->iFrom] );
+ if( pSrc->fg.viaCoroutine ){
+ int regYield = pSrc->regReturn;
addrCounter = sqlite3VdbeAddOp2(v, OP_Integer, 0, 0);
- sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pTabItem->addrFillSub);
+ sqlite3VdbeAddOp3(v, OP_InitCoroutine, regYield, 0, pSrc->addrFillSub);
addrTop = sqlite3VdbeAddOp1(v, OP_Yield, regYield);
VdbeCoverage(v);
- VdbeComment((v, "next row of %s", pTabItem->pTab->zName));
+ VdbeComment((v, "next row of %s", pSrc->pTab->zName));
}else{
addrTop = sqlite3VdbeAddOp1(v, OP_Rewind, pLevel->iTabCur); VdbeCoverage(v);
}
@@ -157926,14 +158863,14 @@ static SQLITE_NOINLINE void constructAutomaticIndex(
sqlite3VdbeAddOp2(v, OP_IdxInsert, pLevel->iIdxCur, regRecord);
sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
if( pPartial ) sqlite3VdbeResolveLabel(v, iContinue);
- if( pTabItem->fg.viaCoroutine ){
+ if( pSrc->fg.viaCoroutine ){
sqlite3VdbeChangeP2(v, addrCounter, regBase+n);
testcase( pParse->db->mallocFailed );
assert( pLevel->iIdxCur>0 );
translateColumnToCopy(pParse, addrTop, pLevel->iTabCur,
- pTabItem->regResult, pLevel->iIdxCur);
+ pSrc->regResult, pLevel->iIdxCur);
sqlite3VdbeGoto(v, addrTop);
- pTabItem->fg.viaCoroutine = 0;
+ pSrc->fg.viaCoroutine = 0;
}else{
sqlite3VdbeAddOp2(v, OP_Next, pLevel->iTabCur, addrTop+1); VdbeCoverage(v);
sqlite3VdbeChangeP5(v, SQLITE_STMTSTATUS_AUTOINDEX);
@@ -157985,6 +158922,10 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
Vdbe *v = pParse->pVdbe; /* VDBE under construction */
WhereLoop *pLoop = pLevel->pWLoop; /* The loop being coded */
int iCur; /* Cursor for table getting the filter */
+ IndexedExpr *saved_pIdxEpr; /* saved copy of Parse.pIdxEpr */
+
+ saved_pIdxEpr = pParse->pIdxEpr;
+ pParse->pIdxEpr = 0;
assert( pLoop!=0 );
assert( v!=0 );
@@ -157992,9 +158933,11 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
addrOnce = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v);
do{
+ const SrcList *pTabList;
const SrcItem *pItem;
const Table *pTab;
u64 sz;
+ int iSrc;
sqlite3WhereExplainBloomFilter(pParse, pWInfo, pLevel);
addrCont = sqlite3VdbeMakeLabel(pParse);
iCur = pLevel->iTabCur;
@@ -158008,7 +158951,9 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
** testing complicated. By basing the blob size on the value in the
** sqlite_stat1 table, testing is much easier.
*/
- pItem = &pWInfo->pTabList->a[pLevel->iFrom];
+ pTabList = pWInfo->pTabList;
+ iSrc = pLevel->iFrom;
+ pItem = &pTabList->a[iSrc];
assert( pItem!=0 );
pTab = pItem->pTab;
assert( pTab!=0 );
@@ -158025,7 +158970,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
for(pTerm=pWInfo->sWC.a; pTerm<pWCEnd; pTerm++){
Expr *pExpr = pTerm->pExpr;
if( (pTerm->wtFlags & TERM_VIRTUAL)==0
- && sqlite3ExprIsTableConstraint(pExpr, pItem)
+ && sqlite3ExprIsSingleTableConstraint(pExpr, pTabList, iSrc)
){
sqlite3ExprIfFalse(pParse, pTerm->pExpr, addrCont, SQLITE_JUMPIFNULL);
}
@@ -158041,9 +158986,8 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
int r1 = sqlite3GetTempRange(pParse, n);
int jj;
for(jj=0; jj<n; jj++){
- int iCol = pIdx->aiColumn[jj];
assert( pIdx->pTable==pItem->pTab );
- sqlite3ExprCodeGetColumnOfTable(v, pIdx->pTable, iCur, iCol,r1+jj);
+ sqlite3ExprCodeLoadIndexColumn(pParse, pIdx, iCur, jj, r1+jj);
}
sqlite3VdbeAddOp4Int(v, OP_FilterAdd, pLevel->regFilter, 0, r1, n);
sqlite3ReleaseTempRange(pParse, r1, n);
@@ -158074,6 +159018,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter(
}
}while( iLevel < pWInfo->nLevel );
sqlite3VdbeJumpHere(v, addrOnce);
+ pParse->pIdxEpr = saved_pIdxEpr;
}
@@ -158329,6 +159274,9 @@ static int vtabBestIndex(Parse *pParse, Table *pTab, sqlite3_index_info *p){
sqlite3ErrorMsg(pParse, "%s", pVtab->zErrMsg);
}
}
+ if( pTab->u.vtab.p->bAllSchemas ){
+ sqlite3VtabUsesAllSchemas(pParse);
+ }
sqlite3_free(pVtab->zErrMsg);
pVtab->zErrMsg = 0;
return rc;
@@ -158373,6 +159321,7 @@ static int whereKeyStats(
assert( pIdx->nSample>0 );
assert( pRec->nField>0 );
+
/* Do a binary search to find the first sample greater than or equal
** to pRec. If pRec contains a single field, the set of samples to search
** is simply the aSample[] array. If the samples in aSample[] contain more
@@ -158417,7 +159366,12 @@ static int whereKeyStats(
** it is extended to two fields. The duplicates that this creates do not
** cause any problems.
*/
- nField = MIN(pRec->nField, pIdx->nSample);
+ if( !HasRowid(pIdx->pTable) && IsPrimaryKeyIndex(pIdx) ){
+ nField = pIdx->nKeyCol;
+ }else{
+ nField = pIdx->nColumn;
+ }
+ nField = MIN(pRec->nField, nField);
iCol = 0;
iSample = pIdx->nSample * nField;
do{
@@ -158853,7 +159807,7 @@ static int whereRangeScanEst(
UNUSED_PARAMETER(pBuilder);
assert( pLower || pUpper );
#endif
- assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 );
+ assert( pUpper==0 || (pUpper->wtFlags & TERM_VNULL)==0 || pParse->nErr>0 );
nNew = whereRangeAdjust(pLower, nOut);
nNew = whereRangeAdjust(pUpper, nNew);
@@ -160954,8 +161908,6 @@ SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){
return pHidden->eDistinct;
}
-#if (defined(SQLITE_ENABLE_DBPAGE_VTAB) || defined(SQLITE_TEST)) \
- && !defined(SQLITE_OMIT_VIRTUALTABLE)
/*
** Cause the prepared statement that is associated with a call to
** xBestIndex to potentially use all schemas. If the statement being
@@ -160965,9 +161917,7 @@ SQLITE_API int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){
**
** This is used by the (built-in) sqlite_dbpage virtual table.
*/
-SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(sqlite3_index_info *pIdxInfo){
- HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1];
- Parse *pParse = pHidden->pParse;
+SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(Parse *pParse){
int nDb = pParse->db->nDb;
int i;
for(i=0; i<nDb; i++){
@@ -160979,7 +161929,6 @@ SQLITE_PRIVATE void sqlite3VtabUsesAllSchemas(sqlite3_index_info *pIdxInfo){
}
}
}
-#endif
/*
** Add all WhereLoop objects for a table of the join identified by
@@ -162145,6 +163094,10 @@ static int wherePathSolver(WhereInfo *pWInfo, LogEst nRowEst){
if( pFrom->isOrdered==pWInfo->pOrderBy->nExpr ){
pWInfo->eDistinct = WHERE_DISTINCT_ORDERED;
}
+ if( pWInfo->pSelect->pOrderBy
+ && pWInfo->nOBSat > pWInfo->pSelect->pOrderBy->nExpr ){
+ pWInfo->nOBSat = pWInfo->pSelect->pOrderBy->nExpr;
+ }
}else{
pWInfo->revMask = pFrom->revLoop;
if( pWInfo->nOBSat<=0 ){
@@ -162356,6 +163309,13 @@ static void showAllWhereLoops(WhereInfo *pWInfo, WhereClause *pWC){
** at most a single row.
** 4) The table must not be referenced by any part of the query apart
** from its own USING or ON clause.
+** 5) The table must not have an inner-join ON or USING clause if there is
+** a RIGHT JOIN anywhere in the query. Otherwise the ON/USING clause
+** might move from the right side to the left side of the RIGHT JOIN.
+** Note: Due to (2), this condition can only arise if the table is
+** the right-most table of a subquery that was flattened into the
+** main query and that subquery was the right-hand operand of an
+** inner join that held an ON or USING clause.
**
** For example, given:
**
@@ -162381,6 +163341,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
){
int i;
Bitmask tabUsed;
+ int hasRightJoin;
/* Preconditions checked by the caller */
assert( pWInfo->nLevel>=2 );
@@ -162395,6 +163356,7 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
if( pWInfo->pOrderBy ){
tabUsed |= sqlite3WhereExprListUsage(&pWInfo->sMaskSet, pWInfo->pOrderBy);
}
+ hasRightJoin = (pWInfo->pTabList->a[0].fg.jointype & JT_LTORJ)!=0;
for(i=pWInfo->nLevel-1; i>=1; i--){
WhereTerm *pTerm, *pEnd;
SrcItem *pItem;
@@ -162417,6 +163379,12 @@ static SQLITE_NOINLINE Bitmask whereOmitNoopJoin(
break;
}
}
+ if( hasRightJoin
+ && ExprHasProperty(pTerm->pExpr, EP_InnerON)
+ && pTerm->pExpr->w.iJoin==pItem->iCursor
+ ){
+ break; /* restriction (5) */
+ }
}
if( pTerm<pEnd ) continue;
WHERETRACE(0xffffffff, ("-> drop loop %c not used\n", pLoop->cId));
@@ -162556,6 +163524,9 @@ static SQLITE_NOINLINE void whereAddIndexedExpr(
p->iIdxCur = iIdxCur;
p->iIdxCol = i;
p->bMaybeNullRow = bMaybeNullRow;
+ if( sqlite3IndexAffinityStr(pParse->db, pIdx) ){
+ p->aff = pIdx->zColAff[i];
+ }
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
p->zIdxName = pIdx->zName;
#endif
@@ -162813,22 +163784,45 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
}
if( pParse->nErr ) goto whereBeginError;
- /* Special case: WHERE terms that do not refer to any tables in the join
- ** (constant expressions). Evaluate each such term, and jump over all the
- ** generated code if the result is not true.
+ /* The False-WHERE-Term-Bypass optimization:
+ **
+ ** If there are WHERE terms that are false, then no rows will be output,
+ ** so skip over all of the code generated here.
+ **
+ ** Conditions:
**
- ** Do not do this if the expression contains non-deterministic functions
- ** that are not within a sub-select. This is not strictly required, but
- ** preserves SQLite's legacy behaviour in the following two cases:
+ ** (1) The WHERE term must not refer to any tables in the join.
+ ** (2) The term must not come from an ON clause on the
+ ** right-hand side of a LEFT or FULL JOIN.
+ ** (3) The term must not come from an ON clause, or there must be
+ ** no RIGHT or FULL OUTER joins in pTabList.
+ ** (4) If the expression contains non-deterministic functions
+ ** that are not within a sub-select. This is not required
+ ** for correctness but rather to preserves SQLite's legacy
+ ** behaviour in the following two cases:
**
- ** FROM ... WHERE random()>0; -- eval random() once per row
- ** FROM ... WHERE (SELECT random())>0; -- eval random() once overall
+ ** WHERE random()>0; -- eval random() once per row
+ ** WHERE (SELECT random())>0; -- eval random() just once overall
+ **
+ ** Note that the Where term need not be a constant in order for this
+ ** optimization to apply, though it does need to be constant relative to
+ ** the current subquery (condition 1). The term might include variables
+ ** from outer queries so that the value of the term changes from one
+ ** invocation of the current subquery to the next.
*/
for(ii=0; ii<sWLB.pWC->nBase; ii++){
- WhereTerm *pT = &sWLB.pWC->a[ii];
+ WhereTerm *pT = &sWLB.pWC->a[ii]; /* A term of the WHERE clause */
+ Expr *pX; /* The expression of pT */
if( pT->wtFlags & TERM_VIRTUAL ) continue;
- if( pT->prereqAll==0 && (nTabList==0 || exprIsDeterministic(pT->pExpr)) ){
- sqlite3ExprIfFalse(pParse, pT->pExpr, pWInfo->iBreak, SQLITE_JUMPIFNULL);
+ pX = pT->pExpr;
+ assert( pX!=0 );
+ assert( pT->prereqAll!=0 || !ExprHasProperty(pX, EP_OuterON) );
+ if( pT->prereqAll==0 /* Conditions (1) and (2) */
+ && (nTabList==0 || exprIsDeterministic(pX)) /* Condition (4) */
+ && !(ExprHasProperty(pX, EP_InnerON) /* Condition (3) */
+ && (pTabList->a[0].fg.jointype & JT_LTORJ)!=0 )
+ ){
+ sqlite3ExprIfFalse(pParse, pX, pWInfo->iBreak, SQLITE_JUMPIFNULL);
pT->wtFlags |= TERM_CODED;
}
}
@@ -163071,7 +164065,7 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
assert( n<=pTab->nCol );
}
#ifdef SQLITE_ENABLE_CURSOR_HINTS
- if( pLoop->u.btree.pIndex!=0 ){
+ if( pLoop->u.btree.pIndex!=0 && (pTab->tabFlags & TF_WithoutRowid)==0 ){
sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete);
}else
#endif
@@ -163208,11 +164202,11 @@ SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(
sqlite3VdbeJumpHere(v, iOnce);
}
}
+ assert( pTabList == pWInfo->pTabList );
if( (wsFlags & (WHERE_AUTO_INDEX|WHERE_BLOOMFILTER))!=0 ){
if( (wsFlags & WHERE_AUTO_INDEX)!=0 ){
#ifndef SQLITE_OMIT_AUTOMATIC_INDEX
- constructAutomaticIndex(pParse, &pWInfo->sWC,
- &pTabList->a[pLevel->iFrom], notReady, pLevel);
+ constructAutomaticIndex(pParse, &pWInfo->sWC, notReady, pLevel);
#endif
}else{
sqlite3ConstructBloomFilter(pWInfo, ii, pLevel, notReady);
@@ -163529,7 +164523,8 @@ SQLITE_PRIVATE void sqlite3WhereEnd(WhereInfo *pWInfo){
k = pLevel->addrBody + 1;
#ifdef SQLITE_DEBUG
if( db->flags & SQLITE_VdbeAddopTrace ){
- printf("TRANSLATE opcodes in range %d..%d\n", k, last-1);
+ printf("TRANSLATE cursor %d->%d in opcode range %d..%d\n",
+ pLevel->iTabCur, pLevel->iIdxCur, k, last-1);
}
/* Proof that the "+1" on the k value above is safe */
pOp = sqlite3VdbeGetOp(v, k - 1);
@@ -164404,6 +165399,7 @@ static int selectWindowRewriteExprCb(Walker *pWalker, Expr *pExpr){
}
/* no break */ deliberate_fall_through
+ case TK_IF_NULL_ROW:
case TK_AGG_FUNCTION:
case TK_COLUMN: {
int iCol = -1;
@@ -167232,18 +168228,18 @@ typedef union {
#define sqlite3ParserCTX_FETCH Parse *pParse=yypParser->pParse;
#define sqlite3ParserCTX_STORE yypParser->pParse=pParse;
#define YYFALLBACK 1
-#define YYNSTATE 576
-#define YYNRULE 405
-#define YYNRULE_WITH_ACTION 342
+#define YYNSTATE 575
+#define YYNRULE 403
+#define YYNRULE_WITH_ACTION 340
#define YYNTOKEN 185
-#define YY_MAX_SHIFT 575
-#define YY_MIN_SHIFTREDUCE 835
-#define YY_MAX_SHIFTREDUCE 1239
-#define YY_ERROR_ACTION 1240
-#define YY_ACCEPT_ACTION 1241
-#define YY_NO_ACTION 1242
-#define YY_MIN_REDUCE 1243
-#define YY_MAX_REDUCE 1647
+#define YY_MAX_SHIFT 574
+#define YY_MIN_SHIFTREDUCE 833
+#define YY_MAX_SHIFTREDUCE 1235
+#define YY_ERROR_ACTION 1236
+#define YY_ACCEPT_ACTION 1237
+#define YY_NO_ACTION 1238
+#define YY_MIN_REDUCE 1239
+#define YY_MAX_REDUCE 1641
/************* End control #defines *******************************************/
#define YY_NLOOKAHEAD ((int)(sizeof(yy_lookahead)/sizeof(yy_lookahead[0])))
@@ -167310,218 +168306,218 @@ typedef union {
** yy_default[] Default action for each state.
**
*********** Begin parsing tables **********************************************/
-#define YY_ACTTAB_COUNT (2098)
+#define YY_ACTTAB_COUNT (2096)
static const YYACTIONTYPE yy_action[] = {
/* 0 */ 568, 208, 568, 118, 115, 229, 568, 118, 115, 229,
- /* 10 */ 568, 1314, 377, 1293, 408, 562, 562, 562, 568, 409,
- /* 20 */ 378, 1314, 1276, 41, 41, 41, 41, 208, 1526, 71,
- /* 30 */ 71, 971, 419, 41, 41, 491, 303, 279, 303, 972,
- /* 40 */ 397, 71, 71, 125, 126, 80, 1217, 1217, 1050, 1053,
- /* 50 */ 1040, 1040, 123, 123, 124, 124, 124, 124, 476, 409,
- /* 60 */ 1241, 1, 1, 575, 2, 1245, 550, 118, 115, 229,
- /* 70 */ 317, 480, 146, 480, 524, 118, 115, 229, 529, 1327,
- /* 80 */ 417, 523, 142, 125, 126, 80, 1217, 1217, 1050, 1053,
- /* 90 */ 1040, 1040, 123, 123, 124, 124, 124, 124, 118, 115,
+ /* 10 */ 568, 1310, 377, 1289, 408, 562, 562, 562, 568, 409,
+ /* 20 */ 378, 1310, 1272, 41, 41, 41, 41, 208, 1520, 71,
+ /* 30 */ 71, 969, 419, 41, 41, 491, 303, 279, 303, 970,
+ /* 40 */ 397, 71, 71, 125, 126, 80, 1212, 1212, 1047, 1050,
+ /* 50 */ 1037, 1037, 123, 123, 124, 124, 124, 124, 476, 409,
+ /* 60 */ 1237, 1, 1, 574, 2, 1241, 550, 118, 115, 229,
+ /* 70 */ 317, 480, 146, 480, 524, 118, 115, 229, 529, 1323,
+ /* 80 */ 417, 523, 142, 125, 126, 80, 1212, 1212, 1047, 1050,
+ /* 90 */ 1037, 1037, 123, 123, 124, 124, 124, 124, 118, 115,
/* 100 */ 229, 327, 122, 122, 122, 122, 121, 121, 120, 120,
/* 110 */ 120, 119, 116, 444, 284, 284, 284, 284, 442, 442,
- /* 120 */ 442, 1567, 376, 1569, 1192, 375, 1163, 565, 1163, 565,
- /* 130 */ 409, 1567, 537, 259, 226, 444, 101, 145, 449, 316,
+ /* 120 */ 442, 1561, 376, 1563, 1188, 375, 1159, 565, 1159, 565,
+ /* 130 */ 409, 1561, 537, 259, 226, 444, 101, 145, 449, 316,
/* 140 */ 559, 240, 122, 122, 122, 122, 121, 121, 120, 120,
- /* 150 */ 120, 119, 116, 444, 125, 126, 80, 1217, 1217, 1050,
- /* 160 */ 1053, 1040, 1040, 123, 123, 124, 124, 124, 124, 142,
- /* 170 */ 294, 1192, 339, 448, 120, 120, 120, 119, 116, 444,
- /* 180 */ 127, 1192, 1193, 1194, 148, 441, 440, 568, 119, 116,
+ /* 150 */ 120, 119, 116, 444, 125, 126, 80, 1212, 1212, 1047,
+ /* 160 */ 1050, 1037, 1037, 123, 123, 124, 124, 124, 124, 142,
+ /* 170 */ 294, 1188, 339, 448, 120, 120, 120, 119, 116, 444,
+ /* 180 */ 127, 1188, 1189, 1188, 148, 441, 440, 568, 119, 116,
/* 190 */ 444, 124, 124, 124, 124, 117, 122, 122, 122, 122,
/* 200 */ 121, 121, 120, 120, 120, 119, 116, 444, 454, 113,
/* 210 */ 13, 13, 546, 122, 122, 122, 122, 121, 121, 120,
- /* 220 */ 120, 120, 119, 116, 444, 422, 316, 559, 1192, 1193,
- /* 230 */ 1194, 149, 1224, 409, 1224, 124, 124, 124, 124, 122,
+ /* 220 */ 120, 120, 119, 116, 444, 422, 316, 559, 1188, 1189,
+ /* 230 */ 1188, 149, 1220, 409, 1220, 124, 124, 124, 124, 122,
/* 240 */ 122, 122, 122, 121, 121, 120, 120, 120, 119, 116,
- /* 250 */ 444, 465, 342, 1037, 1037, 1051, 1054, 125, 126, 80,
- /* 260 */ 1217, 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124,
- /* 270 */ 124, 124, 1279, 522, 222, 1192, 568, 409, 224, 514,
+ /* 250 */ 444, 465, 342, 1034, 1034, 1048, 1051, 125, 126, 80,
+ /* 260 */ 1212, 1212, 1047, 1050, 1037, 1037, 123, 123, 124, 124,
+ /* 270 */ 124, 124, 1275, 522, 222, 1188, 568, 409, 224, 514,
/* 280 */ 175, 82, 83, 122, 122, 122, 122, 121, 121, 120,
- /* 290 */ 120, 120, 119, 116, 444, 1007, 16, 16, 1192, 133,
- /* 300 */ 133, 125, 126, 80, 1217, 1217, 1050, 1053, 1040, 1040,
+ /* 290 */ 120, 120, 119, 116, 444, 1005, 16, 16, 1188, 133,
+ /* 300 */ 133, 125, 126, 80, 1212, 1212, 1047, 1050, 1037, 1037,
/* 310 */ 123, 123, 124, 124, 124, 124, 122, 122, 122, 122,
- /* 320 */ 121, 121, 120, 120, 120, 119, 116, 444, 1041, 546,
- /* 330 */ 1192, 373, 1192, 1193, 1194, 252, 1434, 399, 504, 501,
- /* 340 */ 500, 111, 560, 566, 4, 926, 926, 433, 499, 340,
- /* 350 */ 460, 328, 360, 394, 1237, 1192, 1193, 1194, 563, 568,
+ /* 320 */ 121, 121, 120, 120, 120, 119, 116, 444, 1038, 546,
+ /* 330 */ 1188, 373, 1188, 1189, 1188, 252, 1429, 399, 504, 501,
+ /* 340 */ 500, 111, 560, 566, 4, 924, 924, 433, 499, 340,
+ /* 350 */ 460, 328, 360, 394, 1233, 1188, 1189, 1188, 563, 568,
/* 360 */ 122, 122, 122, 122, 121, 121, 120, 120, 120, 119,
- /* 370 */ 116, 444, 284, 284, 369, 1580, 1607, 441, 440, 154,
- /* 380 */ 409, 445, 71, 71, 1286, 565, 1221, 1192, 1193, 1194,
- /* 390 */ 85, 1223, 271, 557, 543, 515, 1561, 568, 98, 1222,
- /* 400 */ 6, 1278, 472, 142, 125, 126, 80, 1217, 1217, 1050,
- /* 410 */ 1053, 1040, 1040, 123, 123, 124, 124, 124, 124, 550,
- /* 420 */ 13, 13, 1027, 507, 1224, 1192, 1224, 549, 109, 109,
- /* 430 */ 222, 568, 1238, 175, 568, 427, 110, 197, 445, 570,
- /* 440 */ 569, 430, 1552, 1017, 325, 551, 1192, 270, 287, 368,
+ /* 370 */ 116, 444, 284, 284, 369, 1574, 1600, 441, 440, 154,
+ /* 380 */ 409, 445, 71, 71, 1282, 565, 1217, 1188, 1189, 1188,
+ /* 390 */ 85, 1219, 271, 557, 543, 515, 1555, 568, 98, 1218,
+ /* 400 */ 6, 1274, 472, 142, 125, 126, 80, 1212, 1212, 1047,
+ /* 410 */ 1050, 1037, 1037, 123, 123, 124, 124, 124, 124, 550,
+ /* 420 */ 13, 13, 1024, 507, 1220, 1188, 1220, 549, 109, 109,
+ /* 430 */ 222, 568, 1234, 175, 568, 427, 110, 197, 445, 569,
+ /* 440 */ 445, 430, 1546, 1014, 325, 551, 1188, 270, 287, 368,
/* 450 */ 510, 363, 509, 257, 71, 71, 543, 71, 71, 359,
- /* 460 */ 316, 559, 1613, 122, 122, 122, 122, 121, 121, 120,
- /* 470 */ 120, 120, 119, 116, 444, 1017, 1017, 1019, 1020, 27,
- /* 480 */ 284, 284, 1192, 1193, 1194, 1158, 568, 1612, 409, 901,
- /* 490 */ 190, 550, 356, 565, 550, 937, 533, 517, 1158, 516,
- /* 500 */ 413, 1158, 552, 1192, 1193, 1194, 568, 544, 1554, 51,
- /* 510 */ 51, 214, 125, 126, 80, 1217, 1217, 1050, 1053, 1040,
- /* 520 */ 1040, 123, 123, 124, 124, 124, 124, 1192, 474, 135,
- /* 530 */ 135, 409, 284, 284, 1490, 505, 121, 121, 120, 120,
- /* 540 */ 120, 119, 116, 444, 1007, 565, 518, 217, 541, 1561,
- /* 550 */ 316, 559, 142, 6, 532, 125, 126, 80, 1217, 1217,
- /* 560 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
- /* 570 */ 1555, 122, 122, 122, 122, 121, 121, 120, 120, 120,
- /* 580 */ 119, 116, 444, 485, 1192, 1193, 1194, 482, 281, 1267,
- /* 590 */ 957, 252, 1192, 373, 504, 501, 500, 1192, 340, 571,
- /* 600 */ 1192, 571, 409, 292, 499, 957, 876, 191, 480, 316,
+ /* 460 */ 316, 559, 1606, 122, 122, 122, 122, 121, 121, 120,
+ /* 470 */ 120, 120, 119, 116, 444, 1014, 1014, 1016, 1017, 27,
+ /* 480 */ 284, 284, 1188, 1189, 1188, 1154, 568, 1605, 409, 899,
+ /* 490 */ 190, 550, 356, 565, 550, 935, 533, 517, 1154, 516,
+ /* 500 */ 413, 1154, 552, 1188, 1189, 1188, 568, 544, 1548, 51,
+ /* 510 */ 51, 214, 125, 126, 80, 1212, 1212, 1047, 1050, 1037,
+ /* 520 */ 1037, 123, 123, 124, 124, 124, 124, 1188, 474, 135,
+ /* 530 */ 135, 409, 284, 284, 1484, 505, 121, 121, 120, 120,
+ /* 540 */ 120, 119, 116, 444, 1005, 565, 518, 217, 541, 1555,
+ /* 550 */ 316, 559, 142, 6, 532, 125, 126, 80, 1212, 1212,
+ /* 560 */ 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, 124,
+ /* 570 */ 1549, 122, 122, 122, 122, 121, 121, 120, 120, 120,
+ /* 580 */ 119, 116, 444, 485, 1188, 1189, 1188, 482, 281, 1263,
+ /* 590 */ 955, 252, 1188, 373, 504, 501, 500, 1188, 340, 570,
+ /* 600 */ 1188, 570, 409, 292, 499, 955, 874, 191, 480, 316,
/* 610 */ 559, 384, 290, 380, 122, 122, 122, 122, 121, 121,
- /* 620 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
- /* 630 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 640 */ 124, 409, 394, 1136, 1192, 869, 100, 284, 284, 1192,
- /* 650 */ 1193, 1194, 373, 1093, 1192, 1193, 1194, 1192, 1193, 1194,
- /* 660 */ 565, 455, 32, 373, 233, 125, 126, 80, 1217, 1217,
- /* 670 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
- /* 680 */ 1433, 959, 568, 228, 958, 122, 122, 122, 122, 121,
- /* 690 */ 121, 120, 120, 120, 119, 116, 444, 1158, 228, 1192,
- /* 700 */ 157, 1192, 1193, 1194, 1553, 13, 13, 301, 957, 1232,
- /* 710 */ 1158, 153, 409, 1158, 373, 1583, 1176, 5, 369, 1580,
- /* 720 */ 429, 1238, 3, 957, 122, 122, 122, 122, 121, 121,
- /* 730 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
- /* 740 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 750 */ 124, 409, 208, 567, 1192, 1028, 1192, 1193, 1194, 1192,
- /* 760 */ 388, 852, 155, 1552, 286, 402, 1098, 1098, 488, 568,
- /* 770 */ 465, 342, 1319, 1319, 1552, 125, 126, 80, 1217, 1217,
- /* 780 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
+ /* 620 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1212,
+ /* 630 */ 1212, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124,
+ /* 640 */ 124, 409, 394, 1132, 1188, 867, 100, 284, 284, 1188,
+ /* 650 */ 1189, 1188, 373, 1089, 1188, 1189, 1188, 1188, 1189, 1188,
+ /* 660 */ 565, 455, 32, 373, 233, 125, 126, 80, 1212, 1212,
+ /* 670 */ 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, 124,
+ /* 680 */ 1428, 957, 568, 228, 956, 122, 122, 122, 122, 121,
+ /* 690 */ 121, 120, 120, 120, 119, 116, 444, 1154, 228, 1188,
+ /* 700 */ 157, 1188, 1189, 1188, 1547, 13, 13, 301, 955, 1228,
+ /* 710 */ 1154, 153, 409, 1154, 373, 1577, 1172, 5, 369, 1574,
+ /* 720 */ 429, 1234, 3, 955, 122, 122, 122, 122, 121, 121,
+ /* 730 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1212,
+ /* 740 */ 1212, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124,
+ /* 750 */ 124, 409, 208, 567, 1188, 1025, 1188, 1189, 1188, 1188,
+ /* 760 */ 388, 850, 155, 1546, 286, 402, 1094, 1094, 488, 568,
+ /* 770 */ 465, 342, 1315, 1315, 1546, 125, 126, 80, 1212, 1212,
+ /* 780 */ 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, 124,
/* 790 */ 129, 568, 13, 13, 374, 122, 122, 122, 122, 121,
/* 800 */ 121, 120, 120, 120, 119, 116, 444, 302, 568, 453,
- /* 810 */ 528, 1192, 1193, 1194, 13, 13, 1192, 1193, 1194, 1297,
- /* 820 */ 463, 1267, 409, 1317, 1317, 1552, 1012, 453, 452, 200,
- /* 830 */ 299, 71, 71, 1265, 122, 122, 122, 122, 121, 121,
- /* 840 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
- /* 850 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 860 */ 124, 409, 227, 1073, 1158, 284, 284, 419, 312, 278,
- /* 870 */ 278, 285, 285, 1419, 406, 405, 382, 1158, 565, 568,
- /* 880 */ 1158, 1196, 565, 1600, 565, 125, 126, 80, 1217, 1217,
- /* 890 */ 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124, 124,
- /* 900 */ 453, 1482, 13, 13, 1536, 122, 122, 122, 122, 121,
+ /* 810 */ 528, 1188, 1189, 1188, 13, 13, 1188, 1189, 1188, 1293,
+ /* 820 */ 463, 1263, 409, 1313, 1313, 1546, 1010, 453, 452, 200,
+ /* 830 */ 299, 71, 71, 1261, 122, 122, 122, 122, 121, 121,
+ /* 840 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1212,
+ /* 850 */ 1212, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124,
+ /* 860 */ 124, 409, 227, 1069, 1154, 284, 284, 419, 312, 278,
+ /* 870 */ 278, 285, 285, 1415, 406, 405, 382, 1154, 565, 568,
+ /* 880 */ 1154, 1191, 565, 1594, 565, 125, 126, 80, 1212, 1212,
+ /* 890 */ 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124, 124,
+ /* 900 */ 453, 1476, 13, 13, 1530, 122, 122, 122, 122, 121,
/* 910 */ 121, 120, 120, 120, 119, 116, 444, 201, 568, 354,
- /* 920 */ 1586, 575, 2, 1245, 840, 841, 842, 1562, 317, 1212,
- /* 930 */ 146, 6, 409, 255, 254, 253, 206, 1327, 9, 1196,
+ /* 920 */ 1580, 574, 2, 1241, 838, 839, 840, 1556, 317, 1207,
+ /* 930 */ 146, 6, 409, 255, 254, 253, 206, 1323, 9, 1191,
/* 940 */ 262, 71, 71, 424, 122, 122, 122, 122, 121, 121,
- /* 950 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1217,
- /* 960 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 970 */ 124, 568, 284, 284, 568, 1213, 409, 574, 313, 1245,
- /* 980 */ 349, 1296, 352, 419, 317, 565, 146, 491, 525, 1643,
- /* 990 */ 395, 371, 491, 1327, 70, 70, 1295, 71, 71, 240,
- /* 1000 */ 1325, 104, 80, 1217, 1217, 1050, 1053, 1040, 1040, 123,
+ /* 950 */ 120, 120, 120, 119, 116, 444, 125, 126, 80, 1212,
+ /* 960 */ 1212, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124,
+ /* 970 */ 124, 568, 284, 284, 568, 1208, 409, 573, 313, 1241,
+ /* 980 */ 349, 1292, 352, 419, 317, 565, 146, 491, 525, 1637,
+ /* 990 */ 395, 371, 491, 1323, 70, 70, 1291, 71, 71, 240,
+ /* 1000 */ 1321, 104, 80, 1212, 1212, 1047, 1050, 1037, 1037, 123,
/* 1010 */ 123, 124, 124, 124, 124, 122, 122, 122, 122, 121,
- /* 1020 */ 121, 120, 120, 120, 119, 116, 444, 1114, 284, 284,
- /* 1030 */ 428, 448, 1525, 1213, 439, 284, 284, 1489, 1352, 311,
- /* 1040 */ 474, 565, 1115, 971, 491, 491, 217, 1263, 565, 1538,
- /* 1050 */ 568, 972, 207, 568, 1027, 240, 383, 1116, 519, 122,
+ /* 1020 */ 121, 120, 120, 120, 119, 116, 444, 1110, 284, 284,
+ /* 1030 */ 428, 448, 1519, 1208, 439, 284, 284, 1483, 1348, 311,
+ /* 1040 */ 474, 565, 1111, 969, 491, 491, 217, 1259, 565, 1532,
+ /* 1050 */ 568, 970, 207, 568, 1024, 240, 383, 1112, 519, 122,
/* 1060 */ 122, 122, 122, 121, 121, 120, 120, 120, 119, 116,
- /* 1070 */ 444, 1018, 107, 71, 71, 1017, 13, 13, 912, 568,
- /* 1080 */ 1495, 568, 284, 284, 97, 526, 491, 448, 913, 1326,
- /* 1090 */ 1322, 545, 409, 284, 284, 565, 151, 209, 1495, 1497,
- /* 1100 */ 262, 450, 55, 55, 56, 56, 565, 1017, 1017, 1019,
- /* 1110 */ 443, 332, 409, 527, 12, 295, 125, 126, 80, 1217,
- /* 1120 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 1130 */ 124, 347, 409, 864, 1534, 1213, 125, 126, 80, 1217,
- /* 1140 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 1150 */ 124, 1137, 1641, 474, 1641, 371, 125, 114, 80, 1217,
- /* 1160 */ 1217, 1050, 1053, 1040, 1040, 123, 123, 124, 124, 124,
- /* 1170 */ 124, 1495, 329, 474, 331, 122, 122, 122, 122, 121,
- /* 1180 */ 121, 120, 120, 120, 119, 116, 444, 203, 1419, 568,
- /* 1190 */ 1294, 864, 464, 1213, 436, 122, 122, 122, 122, 121,
- /* 1200 */ 121, 120, 120, 120, 119, 116, 444, 553, 1137, 1642,
- /* 1210 */ 539, 1642, 15, 15, 892, 122, 122, 122, 122, 121,
+ /* 1070 */ 444, 1015, 107, 71, 71, 1014, 13, 13, 910, 568,
+ /* 1080 */ 1489, 568, 284, 284, 97, 526, 491, 448, 911, 1322,
+ /* 1090 */ 1318, 545, 409, 284, 284, 565, 151, 209, 1489, 1491,
+ /* 1100 */ 262, 450, 55, 55, 56, 56, 565, 1014, 1014, 1016,
+ /* 1110 */ 443, 332, 409, 527, 12, 295, 125, 126, 80, 1212,
+ /* 1120 */ 1212, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124,
+ /* 1130 */ 124, 347, 409, 862, 1528, 1208, 125, 126, 80, 1212,
+ /* 1140 */ 1212, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124,
+ /* 1150 */ 124, 1133, 1635, 474, 1635, 371, 125, 114, 80, 1212,
+ /* 1160 */ 1212, 1047, 1050, 1037, 1037, 123, 123, 124, 124, 124,
+ /* 1170 */ 124, 1489, 329, 474, 331, 122, 122, 122, 122, 121,
+ /* 1180 */ 121, 120, 120, 120, 119, 116, 444, 203, 1415, 568,
+ /* 1190 */ 1290, 862, 464, 1208, 436, 122, 122, 122, 122, 121,
+ /* 1200 */ 121, 120, 120, 120, 119, 116, 444, 553, 1133, 1636,
+ /* 1210 */ 539, 1636, 15, 15, 890, 122, 122, 122, 122, 121,
/* 1220 */ 121, 120, 120, 120, 119, 116, 444, 568, 298, 538,
- /* 1230 */ 1135, 1419, 1559, 1560, 1331, 409, 6, 6, 1169, 1268,
- /* 1240 */ 415, 320, 284, 284, 1419, 508, 565, 525, 300, 457,
- /* 1250 */ 43, 43, 568, 893, 12, 565, 330, 478, 425, 407,
- /* 1260 */ 126, 80, 1217, 1217, 1050, 1053, 1040, 1040, 123, 123,
- /* 1270 */ 124, 124, 124, 124, 568, 57, 57, 288, 1192, 1419,
- /* 1280 */ 496, 458, 392, 392, 391, 273, 389, 1135, 1558, 849,
- /* 1290 */ 1169, 407, 6, 568, 321, 1158, 470, 44, 44, 1557,
- /* 1300 */ 1114, 426, 234, 6, 323, 256, 540, 256, 1158, 431,
- /* 1310 */ 568, 1158, 322, 17, 487, 1115, 58, 58, 122, 122,
+ /* 1230 */ 1131, 1415, 1553, 1554, 1327, 409, 6, 6, 1165, 1264,
+ /* 1240 */ 415, 320, 284, 284, 1415, 508, 565, 525, 300, 457,
+ /* 1250 */ 43, 43, 568, 891, 12, 565, 330, 478, 425, 407,
+ /* 1260 */ 126, 80, 1212, 1212, 1047, 1050, 1037, 1037, 123, 123,
+ /* 1270 */ 124, 124, 124, 124, 568, 57, 57, 288, 1188, 1415,
+ /* 1280 */ 496, 458, 392, 392, 391, 273, 389, 1131, 1552, 847,
+ /* 1290 */ 1165, 407, 6, 568, 321, 1154, 470, 44, 44, 1551,
+ /* 1300 */ 1110, 426, 234, 6, 323, 256, 540, 256, 1154, 431,
+ /* 1310 */ 568, 1154, 322, 17, 487, 1111, 58, 58, 122, 122,
/* 1320 */ 122, 122, 121, 121, 120, 120, 120, 119, 116, 444,
- /* 1330 */ 1116, 216, 481, 59, 59, 1192, 1193, 1194, 111, 560,
+ /* 1330 */ 1112, 216, 481, 59, 59, 1188, 1189, 1188, 111, 560,
/* 1340 */ 324, 4, 236, 456, 526, 568, 237, 456, 568, 437,
- /* 1350 */ 168, 556, 420, 141, 479, 563, 568, 293, 568, 1095,
- /* 1360 */ 568, 293, 568, 1095, 531, 568, 872, 8, 60, 60,
+ /* 1350 */ 168, 556, 420, 141, 479, 563, 568, 293, 568, 1091,
+ /* 1360 */ 568, 293, 568, 1091, 531, 568, 870, 8, 60, 60,
/* 1370 */ 235, 61, 61, 568, 414, 568, 414, 568, 445, 62,
/* 1380 */ 62, 45, 45, 46, 46, 47, 47, 199, 49, 49,
/* 1390 */ 557, 568, 359, 568, 100, 486, 50, 50, 63, 63,
- /* 1400 */ 64, 64, 561, 415, 535, 410, 568, 1027, 568, 534,
- /* 1410 */ 316, 559, 316, 559, 65, 65, 14, 14, 568, 1027,
- /* 1420 */ 568, 512, 932, 872, 1018, 109, 109, 931, 1017, 66,
- /* 1430 */ 66, 131, 131, 110, 451, 445, 570, 569, 416, 177,
- /* 1440 */ 1017, 132, 132, 67, 67, 568, 467, 568, 932, 471,
- /* 1450 */ 1364, 283, 226, 931, 315, 1363, 407, 568, 459, 407,
- /* 1460 */ 1017, 1017, 1019, 239, 407, 86, 213, 1350, 52, 52,
- /* 1470 */ 68, 68, 1017, 1017, 1019, 1020, 27, 1585, 1180, 447,
- /* 1480 */ 69, 69, 288, 97, 108, 1541, 106, 392, 392, 391,
- /* 1490 */ 273, 389, 568, 879, 849, 883, 568, 111, 560, 466,
- /* 1500 */ 4, 568, 152, 30, 38, 568, 1132, 234, 396, 323,
+ /* 1400 */ 64, 64, 561, 415, 535, 410, 568, 1024, 568, 534,
+ /* 1410 */ 316, 559, 316, 559, 65, 65, 14, 14, 568, 1024,
+ /* 1420 */ 568, 512, 930, 870, 1015, 109, 109, 929, 1014, 66,
+ /* 1430 */ 66, 131, 131, 110, 451, 445, 569, 445, 416, 177,
+ /* 1440 */ 1014, 132, 132, 67, 67, 568, 467, 568, 930, 471,
+ /* 1450 */ 1360, 283, 226, 929, 315, 1359, 407, 568, 459, 407,
+ /* 1460 */ 1014, 1014, 1016, 239, 407, 86, 213, 1346, 52, 52,
+ /* 1470 */ 68, 68, 1014, 1014, 1016, 1017, 27, 1579, 1176, 447,
+ /* 1480 */ 69, 69, 288, 97, 108, 1535, 106, 392, 392, 391,
+ /* 1490 */ 273, 389, 568, 877, 847, 881, 568, 111, 560, 466,
+ /* 1500 */ 4, 568, 152, 30, 38, 568, 1128, 234, 396, 323,
/* 1510 */ 111, 560, 527, 4, 563, 53, 53, 322, 568, 163,
/* 1520 */ 163, 568, 337, 468, 164, 164, 333, 563, 76, 76,
- /* 1530 */ 568, 289, 1514, 568, 31, 1513, 568, 445, 338, 483,
- /* 1540 */ 100, 54, 54, 344, 72, 72, 296, 236, 1080, 557,
- /* 1550 */ 445, 879, 1360, 134, 134, 168, 73, 73, 141, 161,
- /* 1560 */ 161, 1574, 557, 535, 568, 319, 568, 348, 536, 1009,
- /* 1570 */ 473, 261, 261, 891, 890, 235, 535, 568, 1027, 568,
+ /* 1530 */ 568, 289, 1508, 568, 31, 1507, 568, 445, 338, 483,
+ /* 1540 */ 100, 54, 54, 344, 72, 72, 296, 236, 1076, 557,
+ /* 1550 */ 445, 877, 1356, 134, 134, 168, 73, 73, 141, 161,
+ /* 1560 */ 161, 1568, 557, 535, 568, 319, 568, 348, 536, 1007,
+ /* 1570 */ 473, 261, 261, 889, 888, 235, 535, 568, 1024, 568,
/* 1580 */ 475, 534, 261, 367, 109, 109, 521, 136, 136, 130,
- /* 1590 */ 130, 1027, 110, 366, 445, 570, 569, 109, 109, 1017,
- /* 1600 */ 162, 162, 156, 156, 568, 110, 1080, 445, 570, 569,
- /* 1610 */ 410, 351, 1017, 568, 353, 316, 559, 568, 343, 568,
- /* 1620 */ 100, 497, 357, 258, 100, 898, 899, 140, 140, 355,
- /* 1630 */ 1310, 1017, 1017, 1019, 1020, 27, 139, 139, 362, 451,
- /* 1640 */ 137, 137, 138, 138, 1017, 1017, 1019, 1020, 27, 1180,
- /* 1650 */ 447, 568, 372, 288, 111, 560, 1021, 4, 392, 392,
- /* 1660 */ 391, 273, 389, 568, 1141, 849, 568, 1076, 568, 258,
- /* 1670 */ 492, 563, 568, 211, 75, 75, 555, 962, 234, 261,
- /* 1680 */ 323, 111, 560, 929, 4, 113, 77, 77, 322, 74,
- /* 1690 */ 74, 42, 42, 1373, 445, 48, 48, 1418, 563, 974,
- /* 1700 */ 975, 1092, 1091, 1092, 1091, 862, 557, 150, 930, 1346,
- /* 1710 */ 113, 1358, 554, 1424, 1021, 1275, 1266, 1254, 236, 1253,
- /* 1720 */ 1255, 445, 1593, 1343, 308, 276, 168, 309, 11, 141,
- /* 1730 */ 393, 310, 232, 557, 1405, 1027, 335, 291, 1400, 219,
- /* 1740 */ 336, 109, 109, 936, 297, 1410, 235, 341, 477, 110,
- /* 1750 */ 502, 445, 570, 569, 1393, 1409, 1017, 400, 1293, 365,
- /* 1760 */ 223, 1486, 1027, 1485, 1355, 1356, 1354, 1353, 109, 109,
- /* 1770 */ 204, 1596, 1232, 558, 265, 218, 110, 205, 445, 570,
- /* 1780 */ 569, 410, 387, 1017, 1533, 179, 316, 559, 1017, 1017,
- /* 1790 */ 1019, 1020, 27, 230, 1531, 1229, 79, 560, 85, 4,
- /* 1800 */ 418, 215, 548, 81, 84, 188, 1406, 173, 181, 461,
- /* 1810 */ 451, 35, 462, 563, 183, 1017, 1017, 1019, 1020, 27,
- /* 1820 */ 184, 1491, 185, 186, 495, 242, 98, 398, 1412, 36,
- /* 1830 */ 1411, 484, 91, 469, 401, 1414, 445, 192, 1480, 246,
- /* 1840 */ 1502, 490, 346, 277, 248, 196, 493, 511, 557, 350,
- /* 1850 */ 1256, 249, 250, 403, 1313, 1312, 111, 560, 432, 4,
- /* 1860 */ 1311, 1304, 93, 1611, 883, 1610, 224, 404, 434, 520,
- /* 1870 */ 263, 435, 1579, 563, 1283, 1282, 364, 1027, 306, 1281,
- /* 1880 */ 264, 1609, 1565, 109, 109, 370, 1303, 307, 1564, 438,
- /* 1890 */ 128, 110, 1378, 445, 570, 569, 445, 546, 1017, 10,
- /* 1900 */ 1466, 105, 381, 1377, 34, 572, 99, 1336, 557, 314,
- /* 1910 */ 1186, 530, 272, 274, 379, 210, 1335, 547, 385, 386,
- /* 1920 */ 275, 573, 1251, 1246, 411, 412, 1518, 165, 178, 1519,
- /* 1930 */ 1017, 1017, 1019, 1020, 27, 1517, 1516, 1027, 78, 147,
- /* 1940 */ 166, 220, 221, 109, 109, 836, 304, 167, 446, 212,
- /* 1950 */ 318, 110, 231, 445, 570, 569, 144, 1090, 1017, 1088,
- /* 1960 */ 326, 180, 169, 1212, 182, 334, 238, 915, 241, 1104,
+ /* 1590 */ 130, 1024, 110, 366, 445, 569, 445, 109, 109, 1014,
+ /* 1600 */ 162, 162, 156, 156, 568, 110, 1076, 445, 569, 445,
+ /* 1610 */ 410, 351, 1014, 568, 353, 316, 559, 568, 343, 568,
+ /* 1620 */ 100, 497, 357, 258, 100, 896, 897, 140, 140, 355,
+ /* 1630 */ 1306, 1014, 1014, 1016, 1017, 27, 139, 139, 362, 451,
+ /* 1640 */ 137, 137, 138, 138, 1014, 1014, 1016, 1017, 27, 1176,
+ /* 1650 */ 447, 568, 372, 288, 111, 560, 1018, 4, 392, 392,
+ /* 1660 */ 391, 273, 389, 568, 1137, 847, 568, 1072, 568, 258,
+ /* 1670 */ 492, 563, 568, 211, 75, 75, 555, 960, 234, 261,
+ /* 1680 */ 323, 111, 560, 927, 4, 113, 77, 77, 322, 74,
+ /* 1690 */ 74, 42, 42, 1369, 445, 48, 48, 1414, 563, 972,
+ /* 1700 */ 973, 1088, 1087, 1088, 1087, 860, 557, 150, 928, 1342,
+ /* 1710 */ 113, 1354, 554, 1419, 1018, 1271, 1262, 1250, 236, 1249,
+ /* 1720 */ 1251, 445, 1587, 1339, 308, 276, 168, 309, 11, 141,
+ /* 1730 */ 393, 310, 232, 557, 1401, 1024, 335, 291, 1396, 219,
+ /* 1740 */ 336, 109, 109, 934, 297, 1406, 235, 341, 477, 110,
+ /* 1750 */ 502, 445, 569, 445, 1389, 1405, 1014, 400, 1289, 365,
+ /* 1760 */ 223, 1480, 1024, 1479, 1351, 1352, 1350, 1349, 109, 109,
+ /* 1770 */ 204, 1590, 1228, 558, 265, 218, 110, 205, 445, 569,
+ /* 1780 */ 445, 410, 387, 1014, 1527, 179, 316, 559, 1014, 1014,
+ /* 1790 */ 1016, 1017, 27, 230, 1525, 1225, 79, 560, 85, 4,
+ /* 1800 */ 418, 215, 548, 81, 84, 188, 1402, 173, 181, 461,
+ /* 1810 */ 451, 35, 462, 563, 183, 1014, 1014, 1016, 1017, 27,
+ /* 1820 */ 184, 1485, 185, 186, 495, 242, 98, 398, 1408, 36,
+ /* 1830 */ 1407, 484, 91, 469, 401, 1410, 445, 192, 1474, 246,
+ /* 1840 */ 1496, 490, 346, 277, 248, 196, 493, 511, 557, 350,
+ /* 1850 */ 1252, 249, 250, 403, 1309, 1308, 111, 560, 432, 4,
+ /* 1860 */ 1307, 1300, 93, 1604, 881, 1603, 224, 404, 434, 520,
+ /* 1870 */ 263, 435, 1573, 563, 1279, 1278, 364, 1024, 306, 1277,
+ /* 1880 */ 264, 1602, 1559, 109, 109, 370, 1299, 307, 1558, 438,
+ /* 1890 */ 128, 110, 1374, 445, 569, 445, 445, 546, 1014, 10,
+ /* 1900 */ 1461, 105, 381, 1373, 34, 571, 99, 1332, 557, 314,
+ /* 1910 */ 1182, 530, 272, 274, 379, 210, 1331, 547, 385, 386,
+ /* 1920 */ 275, 572, 1247, 1242, 411, 412, 1512, 165, 178, 1513,
+ /* 1930 */ 1014, 1014, 1016, 1017, 27, 1511, 1510, 1024, 78, 147,
+ /* 1940 */ 166, 220, 221, 109, 109, 834, 304, 167, 446, 212,
+ /* 1950 */ 318, 110, 231, 445, 569, 445, 144, 1086, 1014, 1084,
+ /* 1960 */ 326, 180, 169, 1207, 182, 334, 238, 913, 241, 1100,
/* 1970 */ 187, 170, 171, 421, 87, 88, 423, 189, 89, 90,
- /* 1980 */ 172, 1107, 243, 1103, 244, 158, 18, 245, 345, 247,
- /* 1990 */ 1017, 1017, 1019, 1020, 27, 261, 1096, 193, 1226, 489,
- /* 2000 */ 194, 37, 366, 851, 494, 251, 195, 506, 92, 19,
- /* 2010 */ 498, 358, 20, 503, 881, 361, 94, 894, 305, 159,
- /* 2020 */ 513, 39, 95, 1174, 160, 1056, 966, 1143, 96, 174,
- /* 2030 */ 1142, 225, 280, 282, 198, 960, 113, 1164, 1160, 260,
- /* 2040 */ 21, 22, 23, 1162, 1168, 1167, 1148, 24, 33, 25,
- /* 2050 */ 202, 542, 26, 100, 1071, 102, 1057, 103, 7, 1055,
- /* 2060 */ 1059, 1113, 1060, 1112, 266, 267, 28, 40, 390, 1022,
- /* 2070 */ 863, 112, 29, 564, 1182, 1181, 268, 176, 143, 925,
- /* 2080 */ 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242, 1242,
- /* 2090 */ 1242, 1242, 1242, 1242, 269, 1602, 1242, 1601,
+ /* 1980 */ 172, 1103, 243, 1099, 244, 158, 18, 245, 345, 247,
+ /* 1990 */ 1014, 1014, 1016, 1017, 27, 261, 1092, 193, 1222, 489,
+ /* 2000 */ 194, 37, 366, 849, 494, 251, 195, 506, 92, 19,
+ /* 2010 */ 498, 358, 20, 503, 879, 361, 94, 892, 305, 159,
+ /* 2020 */ 513, 39, 95, 1170, 160, 1053, 964, 1139, 96, 174,
+ /* 2030 */ 1138, 225, 280, 282, 198, 958, 113, 1160, 1156, 260,
+ /* 2040 */ 21, 22, 23, 1158, 1164, 1163, 1144, 24, 33, 25,
+ /* 2050 */ 202, 542, 26, 100, 1067, 102, 1054, 103, 7, 1052,
+ /* 2060 */ 1056, 1109, 1057, 1108, 266, 267, 28, 40, 390, 1019,
+ /* 2070 */ 861, 112, 29, 564, 1178, 1177, 268, 176, 143, 923,
+ /* 2080 */ 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238, 1238,
+ /* 2090 */ 1238, 1238, 1238, 1238, 269, 1595,
};
static const YYCODETYPE yy_lookahead[] = {
/* 0 */ 193, 193, 193, 274, 275, 276, 193, 274, 275, 276,
@@ -167733,7 +168729,7 @@ static const YYCODETYPE yy_lookahead[] = {
/* 2060 */ 23, 23, 11, 23, 25, 22, 22, 22, 15, 23,
/* 2070 */ 23, 22, 22, 25, 1, 1, 141, 25, 23, 135,
/* 2080 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2090 */ 319, 319, 319, 319, 141, 141, 319, 141, 319, 319,
+ /* 2090 */ 319, 319, 319, 319, 141, 141, 319, 319, 319, 319,
/* 2100 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
/* 2110 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
/* 2120 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
@@ -167752,9 +168748,9 @@ static const YYCODETYPE yy_lookahead[] = {
/* 2250 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
/* 2260 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
/* 2270 */ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
- /* 2280 */ 319, 319, 319,
+ /* 2280 */ 319,
};
-#define YY_SHIFT_COUNT (575)
+#define YY_SHIFT_COUNT (574)
#define YY_SHIFT_MIN (0)
#define YY_SHIFT_MAX (2074)
static const unsigned short int yy_shift_ofst[] = {
@@ -167774,12 +168770,12 @@ static const unsigned short int yy_shift_ofst[] = {
/* 130 */ 137, 181, 181, 181, 181, 181, 181, 181, 94, 430,
/* 140 */ 66, 65, 112, 366, 533, 533, 740, 1261, 533, 533,
/* 150 */ 79, 79, 533, 412, 412, 412, 77, 412, 123, 113,
- /* 160 */ 113, 22, 22, 2098, 2098, 328, 328, 328, 239, 468,
+ /* 160 */ 113, 22, 22, 2096, 2096, 328, 328, 328, 239, 468,
/* 170 */ 468, 468, 468, 1015, 1015, 409, 366, 1129, 1186, 533,
/* 180 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533,
/* 190 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 969,
/* 200 */ 621, 621, 533, 642, 788, 788, 1228, 1228, 822, 822,
- /* 210 */ 67, 1274, 2098, 2098, 2098, 2098, 2098, 2098, 2098, 1307,
+ /* 210 */ 67, 1274, 2096, 2096, 2096, 2096, 2096, 2096, 2096, 1307,
/* 220 */ 954, 954, 585, 472, 640, 387, 695, 538, 541, 700,
/* 230 */ 533, 533, 533, 533, 533, 533, 533, 533, 533, 533,
/* 240 */ 222, 533, 533, 533, 533, 533, 533, 533, 533, 533,
@@ -167797,8 +168793,8 @@ static const unsigned short int yy_shift_ofst[] = {
/* 360 */ 1840, 1840, 1823, 1732, 1738, 1732, 1794, 1732, 1732, 1701,
/* 370 */ 1844, 1758, 1758, 1823, 1633, 1789, 1789, 1807, 1807, 1742,
/* 380 */ 1752, 1877, 1633, 1743, 1742, 1759, 1765, 1677, 1879, 1897,
- /* 390 */ 1897, 1914, 1914, 1914, 2098, 2098, 2098, 2098, 2098, 2098,
- /* 400 */ 2098, 2098, 2098, 2098, 2098, 2098, 2098, 2098, 2098, 207,
+ /* 390 */ 1897, 1914, 1914, 1914, 2096, 2096, 2096, 2096, 2096, 2096,
+ /* 400 */ 2096, 2096, 2096, 2096, 2096, 2096, 2096, 2096, 2096, 207,
/* 410 */ 1095, 331, 620, 903, 806, 1074, 1483, 1432, 1481, 1322,
/* 420 */ 1370, 1394, 1515, 1291, 1546, 1547, 1557, 1595, 1598, 1599,
/* 430 */ 1434, 1453, 1618, 1462, 1567, 1489, 1644, 1654, 1616, 1660,
@@ -167815,7 +168811,7 @@ static const unsigned short int yy_shift_ofst[] = {
/* 540 */ 2015, 2023, 2026, 2027, 2025, 2028, 2018, 1913, 1915, 2031,
/* 550 */ 2011, 2033, 2036, 2037, 2038, 2039, 2040, 2043, 2051, 2044,
/* 560 */ 2045, 2046, 2047, 2049, 2050, 2048, 1944, 1935, 1953, 1954,
- /* 570 */ 1956, 2052, 2055, 2053, 2073, 2074,
+ /* 570 */ 2052, 2055, 2053, 2073, 2074,
};
#define YY_REDUCE_COUNT (408)
#define YY_REDUCE_MIN (-271)
@@ -167864,64 +168860,64 @@ static const short yy_reduce_ofst[] = {
/* 400 */ 1722, 1723, 1733, 1717, 1724, 1727, 1728, 1725, 1740,
};
static const YYACTIONTYPE yy_default[] = {
- /* 0 */ 1647, 1647, 1647, 1475, 1240, 1351, 1240, 1240, 1240, 1475,
- /* 10 */ 1475, 1475, 1240, 1381, 1381, 1528, 1273, 1240, 1240, 1240,
- /* 20 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1474, 1240, 1240,
- /* 30 */ 1240, 1240, 1563, 1563, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 40 */ 1240, 1240, 1390, 1240, 1397, 1240, 1240, 1240, 1240, 1240,
- /* 50 */ 1476, 1477, 1240, 1240, 1240, 1527, 1529, 1492, 1404, 1403,
- /* 60 */ 1402, 1401, 1510, 1369, 1395, 1388, 1392, 1470, 1471, 1469,
- /* 70 */ 1473, 1477, 1476, 1240, 1391, 1438, 1454, 1437, 1240, 1240,
- /* 80 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 90 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 100 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 110 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 120 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 130 */ 1446, 1453, 1452, 1451, 1460, 1450, 1447, 1440, 1439, 1441,
- /* 140 */ 1442, 1240, 1240, 1264, 1240, 1240, 1261, 1315, 1240, 1240,
- /* 150 */ 1240, 1240, 1240, 1547, 1546, 1240, 1443, 1240, 1273, 1432,
- /* 160 */ 1431, 1457, 1444, 1456, 1455, 1535, 1599, 1598, 1493, 1240,
- /* 170 */ 1240, 1240, 1240, 1240, 1240, 1563, 1240, 1240, 1240, 1240,
- /* 180 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 190 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1371,
- /* 200 */ 1563, 1563, 1240, 1273, 1563, 1563, 1372, 1372, 1269, 1269,
- /* 210 */ 1375, 1240, 1542, 1342, 1342, 1342, 1342, 1351, 1342, 1240,
- /* 220 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 230 */ 1240, 1240, 1240, 1240, 1532, 1530, 1240, 1240, 1240, 1240,
- /* 240 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 250 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 260 */ 1240, 1240, 1240, 1347, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 270 */ 1240, 1240, 1240, 1240, 1240, 1592, 1240, 1505, 1329, 1347,
- /* 280 */ 1347, 1347, 1347, 1349, 1330, 1328, 1341, 1274, 1247, 1639,
- /* 290 */ 1407, 1396, 1348, 1396, 1636, 1394, 1407, 1407, 1394, 1407,
- /* 300 */ 1348, 1636, 1290, 1615, 1285, 1381, 1381, 1381, 1371, 1371,
- /* 310 */ 1371, 1371, 1375, 1375, 1472, 1348, 1341, 1240, 1639, 1639,
- /* 320 */ 1357, 1357, 1638, 1638, 1357, 1493, 1623, 1416, 1318, 1324,
- /* 330 */ 1324, 1324, 1324, 1357, 1258, 1394, 1623, 1623, 1394, 1416,
- /* 340 */ 1318, 1394, 1318, 1394, 1357, 1258, 1509, 1633, 1357, 1258,
- /* 350 */ 1483, 1357, 1258, 1357, 1258, 1483, 1316, 1316, 1316, 1305,
- /* 360 */ 1240, 1240, 1483, 1316, 1290, 1316, 1305, 1316, 1316, 1581,
- /* 370 */ 1240, 1487, 1487, 1483, 1357, 1573, 1573, 1384, 1384, 1389,
- /* 380 */ 1375, 1478, 1357, 1240, 1389, 1387, 1385, 1394, 1308, 1595,
- /* 390 */ 1595, 1591, 1591, 1591, 1644, 1644, 1542, 1608, 1273, 1273,
- /* 400 */ 1273, 1273, 1608, 1292, 1292, 1274, 1274, 1273, 1608, 1240,
- /* 410 */ 1240, 1240, 1240, 1240, 1240, 1603, 1240, 1537, 1494, 1361,
- /* 420 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 430 */ 1240, 1240, 1240, 1240, 1548, 1240, 1240, 1240, 1240, 1240,
- /* 440 */ 1240, 1240, 1240, 1240, 1240, 1421, 1240, 1243, 1539, 1240,
- /* 450 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1398, 1399, 1362,
- /* 460 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1413, 1240, 1240,
- /* 470 */ 1240, 1408, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 480 */ 1635, 1240, 1240, 1240, 1240, 1240, 1240, 1508, 1507, 1240,
- /* 490 */ 1240, 1359, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 500 */ 1240, 1240, 1240, 1240, 1240, 1288, 1240, 1240, 1240, 1240,
- /* 510 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 520 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1386,
- /* 530 */ 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 540 */ 1240, 1240, 1240, 1240, 1578, 1376, 1240, 1240, 1240, 1240,
- /* 550 */ 1626, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240, 1240,
- /* 560 */ 1240, 1240, 1240, 1240, 1240, 1619, 1332, 1423, 1240, 1422,
- /* 570 */ 1426, 1262, 1240, 1252, 1240, 1240,
+ /* 0 */ 1641, 1641, 1641, 1469, 1236, 1347, 1236, 1236, 1236, 1469,
+ /* 10 */ 1469, 1469, 1236, 1377, 1377, 1522, 1269, 1236, 1236, 1236,
+ /* 20 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1468, 1236, 1236,
+ /* 30 */ 1236, 1236, 1557, 1557, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 40 */ 1236, 1236, 1386, 1236, 1393, 1236, 1236, 1236, 1236, 1236,
+ /* 50 */ 1470, 1471, 1236, 1236, 1236, 1521, 1523, 1486, 1400, 1399,
+ /* 60 */ 1398, 1397, 1504, 1365, 1391, 1384, 1388, 1465, 1466, 1464,
+ /* 70 */ 1619, 1471, 1470, 1236, 1387, 1433, 1449, 1432, 1236, 1236,
+ /* 80 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 90 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 100 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 110 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 120 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 130 */ 1441, 1448, 1447, 1446, 1455, 1445, 1442, 1435, 1434, 1436,
+ /* 140 */ 1437, 1236, 1236, 1260, 1236, 1236, 1257, 1311, 1236, 1236,
+ /* 150 */ 1236, 1236, 1236, 1541, 1540, 1236, 1438, 1236, 1269, 1427,
+ /* 160 */ 1426, 1452, 1439, 1451, 1450, 1529, 1593, 1592, 1487, 1236,
+ /* 170 */ 1236, 1236, 1236, 1236, 1236, 1557, 1236, 1236, 1236, 1236,
+ /* 180 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 190 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1367,
+ /* 200 */ 1557, 1557, 1236, 1269, 1557, 1557, 1368, 1368, 1265, 1265,
+ /* 210 */ 1371, 1236, 1536, 1338, 1338, 1338, 1338, 1347, 1338, 1236,
+ /* 220 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 230 */ 1236, 1236, 1236, 1236, 1526, 1524, 1236, 1236, 1236, 1236,
+ /* 240 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 250 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 260 */ 1236, 1236, 1236, 1343, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 270 */ 1236, 1236, 1236, 1236, 1236, 1586, 1236, 1499, 1325, 1343,
+ /* 280 */ 1343, 1343, 1343, 1345, 1326, 1324, 1337, 1270, 1243, 1633,
+ /* 290 */ 1403, 1392, 1344, 1392, 1630, 1390, 1403, 1403, 1390, 1403,
+ /* 300 */ 1344, 1630, 1286, 1608, 1281, 1377, 1377, 1377, 1367, 1367,
+ /* 310 */ 1367, 1367, 1371, 1371, 1467, 1344, 1337, 1236, 1633, 1633,
+ /* 320 */ 1353, 1353, 1632, 1632, 1353, 1487, 1616, 1412, 1314, 1320,
+ /* 330 */ 1320, 1320, 1320, 1353, 1254, 1390, 1616, 1616, 1390, 1412,
+ /* 340 */ 1314, 1390, 1314, 1390, 1353, 1254, 1503, 1627, 1353, 1254,
+ /* 350 */ 1477, 1353, 1254, 1353, 1254, 1477, 1312, 1312, 1312, 1301,
+ /* 360 */ 1236, 1236, 1477, 1312, 1286, 1312, 1301, 1312, 1312, 1575,
+ /* 370 */ 1236, 1481, 1481, 1477, 1353, 1567, 1567, 1380, 1380, 1385,
+ /* 380 */ 1371, 1472, 1353, 1236, 1385, 1383, 1381, 1390, 1304, 1589,
+ /* 390 */ 1589, 1585, 1585, 1585, 1638, 1638, 1536, 1601, 1269, 1269,
+ /* 400 */ 1269, 1269, 1601, 1288, 1288, 1270, 1270, 1269, 1601, 1236,
+ /* 410 */ 1236, 1236, 1236, 1236, 1236, 1596, 1236, 1531, 1488, 1357,
+ /* 420 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 430 */ 1236, 1236, 1236, 1236, 1542, 1236, 1236, 1236, 1236, 1236,
+ /* 440 */ 1236, 1236, 1236, 1236, 1236, 1417, 1236, 1239, 1533, 1236,
+ /* 450 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1394, 1395, 1358,
+ /* 460 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1409, 1236, 1236,
+ /* 470 */ 1236, 1404, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 480 */ 1629, 1236, 1236, 1236, 1236, 1236, 1236, 1502, 1501, 1236,
+ /* 490 */ 1236, 1355, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 500 */ 1236, 1236, 1236, 1236, 1236, 1284, 1236, 1236, 1236, 1236,
+ /* 510 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 520 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1382,
+ /* 530 */ 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 540 */ 1236, 1236, 1236, 1236, 1572, 1372, 1236, 1236, 1236, 1236,
+ /* 550 */ 1620, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236, 1236,
+ /* 560 */ 1236, 1236, 1236, 1236, 1236, 1612, 1328, 1418, 1236, 1421,
+ /* 570 */ 1258, 1236, 1248, 1236, 1236,
};
/********** End of lemon-generated parsing tables *****************************/
@@ -168718,233 +169714,231 @@ static const char *const yyRuleName[] = {
/* 175 */ "idlist ::= idlist COMMA nm",
/* 176 */ "idlist ::= nm",
/* 177 */ "expr ::= LP expr RP",
- /* 178 */ "expr ::= ID|INDEXED",
- /* 179 */ "expr ::= JOIN_KW",
- /* 180 */ "expr ::= nm DOT nm",
- /* 181 */ "expr ::= nm DOT nm DOT nm",
- /* 182 */ "term ::= NULL|FLOAT|BLOB",
- /* 183 */ "term ::= STRING",
- /* 184 */ "term ::= INTEGER",
- /* 185 */ "expr ::= VARIABLE",
- /* 186 */ "expr ::= expr COLLATE ID|STRING",
- /* 187 */ "expr ::= CAST LP expr AS typetoken RP",
- /* 188 */ "expr ::= ID|INDEXED LP distinct exprlist RP",
- /* 189 */ "expr ::= ID|INDEXED LP STAR RP",
- /* 190 */ "expr ::= ID|INDEXED LP distinct exprlist RP filter_over",
- /* 191 */ "expr ::= ID|INDEXED LP STAR RP filter_over",
- /* 192 */ "term ::= CTIME_KW",
- /* 193 */ "expr ::= LP nexprlist COMMA expr RP",
- /* 194 */ "expr ::= expr AND expr",
- /* 195 */ "expr ::= expr OR expr",
- /* 196 */ "expr ::= expr LT|GT|GE|LE expr",
- /* 197 */ "expr ::= expr EQ|NE expr",
- /* 198 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
- /* 199 */ "expr ::= expr PLUS|MINUS expr",
- /* 200 */ "expr ::= expr STAR|SLASH|REM expr",
- /* 201 */ "expr ::= expr CONCAT expr",
- /* 202 */ "likeop ::= NOT LIKE_KW|MATCH",
- /* 203 */ "expr ::= expr likeop expr",
- /* 204 */ "expr ::= expr likeop expr ESCAPE expr",
- /* 205 */ "expr ::= expr ISNULL|NOTNULL",
- /* 206 */ "expr ::= expr NOT NULL",
- /* 207 */ "expr ::= expr IS expr",
- /* 208 */ "expr ::= expr IS NOT expr",
- /* 209 */ "expr ::= expr IS NOT DISTINCT FROM expr",
- /* 210 */ "expr ::= expr IS DISTINCT FROM expr",
- /* 211 */ "expr ::= NOT expr",
- /* 212 */ "expr ::= BITNOT expr",
- /* 213 */ "expr ::= PLUS|MINUS expr",
- /* 214 */ "expr ::= expr PTR expr",
- /* 215 */ "between_op ::= BETWEEN",
- /* 216 */ "between_op ::= NOT BETWEEN",
- /* 217 */ "expr ::= expr between_op expr AND expr",
- /* 218 */ "in_op ::= IN",
- /* 219 */ "in_op ::= NOT IN",
- /* 220 */ "expr ::= expr in_op LP exprlist RP",
- /* 221 */ "expr ::= LP select RP",
- /* 222 */ "expr ::= expr in_op LP select RP",
- /* 223 */ "expr ::= expr in_op nm dbnm paren_exprlist",
- /* 224 */ "expr ::= EXISTS LP select RP",
- /* 225 */ "expr ::= CASE case_operand case_exprlist case_else END",
- /* 226 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
- /* 227 */ "case_exprlist ::= WHEN expr THEN expr",
- /* 228 */ "case_else ::= ELSE expr",
- /* 229 */ "case_else ::=",
- /* 230 */ "case_operand ::= expr",
- /* 231 */ "case_operand ::=",
- /* 232 */ "exprlist ::=",
- /* 233 */ "nexprlist ::= nexprlist COMMA expr",
- /* 234 */ "nexprlist ::= expr",
- /* 235 */ "paren_exprlist ::=",
- /* 236 */ "paren_exprlist ::= LP exprlist RP",
- /* 237 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
- /* 238 */ "uniqueflag ::= UNIQUE",
- /* 239 */ "uniqueflag ::=",
- /* 240 */ "eidlist_opt ::=",
- /* 241 */ "eidlist_opt ::= LP eidlist RP",
- /* 242 */ "eidlist ::= eidlist COMMA nm collate sortorder",
- /* 243 */ "eidlist ::= nm collate sortorder",
- /* 244 */ "collate ::=",
- /* 245 */ "collate ::= COLLATE ID|STRING",
- /* 246 */ "cmd ::= DROP INDEX ifexists fullname",
- /* 247 */ "cmd ::= VACUUM vinto",
- /* 248 */ "cmd ::= VACUUM nm vinto",
- /* 249 */ "vinto ::= INTO expr",
- /* 250 */ "vinto ::=",
- /* 251 */ "cmd ::= PRAGMA nm dbnm",
- /* 252 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
- /* 253 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
- /* 254 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
- /* 255 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
- /* 256 */ "plus_num ::= PLUS INTEGER|FLOAT",
- /* 257 */ "minus_num ::= MINUS INTEGER|FLOAT",
- /* 258 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
- /* 259 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
- /* 260 */ "trigger_time ::= BEFORE|AFTER",
- /* 261 */ "trigger_time ::= INSTEAD OF",
- /* 262 */ "trigger_time ::=",
- /* 263 */ "trigger_event ::= DELETE|INSERT",
- /* 264 */ "trigger_event ::= UPDATE",
- /* 265 */ "trigger_event ::= UPDATE OF idlist",
- /* 266 */ "when_clause ::=",
- /* 267 */ "when_clause ::= WHEN expr",
- /* 268 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
- /* 269 */ "trigger_cmd_list ::= trigger_cmd SEMI",
- /* 270 */ "trnm ::= nm DOT nm",
- /* 271 */ "tridxby ::= INDEXED BY nm",
- /* 272 */ "tridxby ::= NOT INDEXED",
- /* 273 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt",
- /* 274 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
- /* 275 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
- /* 276 */ "trigger_cmd ::= scanpt select scanpt",
- /* 277 */ "expr ::= RAISE LP IGNORE RP",
- /* 278 */ "expr ::= RAISE LP raisetype COMMA nm RP",
- /* 279 */ "raisetype ::= ROLLBACK",
- /* 280 */ "raisetype ::= ABORT",
- /* 281 */ "raisetype ::= FAIL",
- /* 282 */ "cmd ::= DROP TRIGGER ifexists fullname",
- /* 283 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
- /* 284 */ "cmd ::= DETACH database_kw_opt expr",
- /* 285 */ "key_opt ::=",
- /* 286 */ "key_opt ::= KEY expr",
- /* 287 */ "cmd ::= REINDEX",
- /* 288 */ "cmd ::= REINDEX nm dbnm",
- /* 289 */ "cmd ::= ANALYZE",
- /* 290 */ "cmd ::= ANALYZE nm dbnm",
- /* 291 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
- /* 292 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
- /* 293 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm",
- /* 294 */ "add_column_fullname ::= fullname",
- /* 295 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
- /* 296 */ "cmd ::= create_vtab",
- /* 297 */ "cmd ::= create_vtab LP vtabarglist RP",
- /* 298 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
- /* 299 */ "vtabarg ::=",
- /* 300 */ "vtabargtoken ::= ANY",
- /* 301 */ "vtabargtoken ::= lp anylist RP",
- /* 302 */ "lp ::= LP",
- /* 303 */ "with ::= WITH wqlist",
- /* 304 */ "with ::= WITH RECURSIVE wqlist",
- /* 305 */ "wqas ::= AS",
- /* 306 */ "wqas ::= AS MATERIALIZED",
- /* 307 */ "wqas ::= AS NOT MATERIALIZED",
- /* 308 */ "wqitem ::= nm eidlist_opt wqas LP select RP",
- /* 309 */ "wqlist ::= wqitem",
- /* 310 */ "wqlist ::= wqlist COMMA wqitem",
- /* 311 */ "windowdefn_list ::= windowdefn",
- /* 312 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
- /* 313 */ "windowdefn ::= nm AS LP window RP",
- /* 314 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
- /* 315 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
- /* 316 */ "window ::= ORDER BY sortlist frame_opt",
- /* 317 */ "window ::= nm ORDER BY sortlist frame_opt",
- /* 318 */ "window ::= frame_opt",
- /* 319 */ "window ::= nm frame_opt",
- /* 320 */ "frame_opt ::=",
- /* 321 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
- /* 322 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt",
- /* 323 */ "range_or_rows ::= RANGE|ROWS|GROUPS",
- /* 324 */ "frame_bound_s ::= frame_bound",
- /* 325 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
- /* 326 */ "frame_bound_e ::= frame_bound",
- /* 327 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
- /* 328 */ "frame_bound ::= expr PRECEDING|FOLLOWING",
- /* 329 */ "frame_bound ::= CURRENT ROW",
- /* 330 */ "frame_exclude_opt ::=",
- /* 331 */ "frame_exclude_opt ::= EXCLUDE frame_exclude",
- /* 332 */ "frame_exclude ::= NO OTHERS",
- /* 333 */ "frame_exclude ::= CURRENT ROW",
- /* 334 */ "frame_exclude ::= GROUP|TIES",
- /* 335 */ "window_clause ::= WINDOW windowdefn_list",
- /* 336 */ "filter_over ::= filter_clause over_clause",
- /* 337 */ "filter_over ::= over_clause",
- /* 338 */ "filter_over ::= filter_clause",
- /* 339 */ "over_clause ::= OVER LP window RP",
- /* 340 */ "over_clause ::= OVER nm",
- /* 341 */ "filter_clause ::= FILTER LP WHERE expr RP",
- /* 342 */ "input ::= cmdlist",
- /* 343 */ "cmdlist ::= cmdlist ecmd",
- /* 344 */ "cmdlist ::= ecmd",
- /* 345 */ "ecmd ::= SEMI",
- /* 346 */ "ecmd ::= cmdx SEMI",
- /* 347 */ "ecmd ::= explain cmdx SEMI",
- /* 348 */ "trans_opt ::=",
- /* 349 */ "trans_opt ::= TRANSACTION",
- /* 350 */ "trans_opt ::= TRANSACTION nm",
- /* 351 */ "savepoint_opt ::= SAVEPOINT",
- /* 352 */ "savepoint_opt ::=",
- /* 353 */ "cmd ::= create_table create_table_args",
- /* 354 */ "table_option_set ::= table_option",
- /* 355 */ "columnlist ::= columnlist COMMA columnname carglist",
- /* 356 */ "columnlist ::= columnname carglist",
- /* 357 */ "nm ::= ID|INDEXED",
- /* 358 */ "nm ::= STRING",
- /* 359 */ "nm ::= JOIN_KW",
- /* 360 */ "typetoken ::= typename",
- /* 361 */ "typename ::= ID|STRING",
- /* 362 */ "signed ::= plus_num",
- /* 363 */ "signed ::= minus_num",
- /* 364 */ "carglist ::= carglist ccons",
- /* 365 */ "carglist ::=",
- /* 366 */ "ccons ::= NULL onconf",
- /* 367 */ "ccons ::= GENERATED ALWAYS AS generated",
- /* 368 */ "ccons ::= AS generated",
- /* 369 */ "conslist_opt ::= COMMA conslist",
- /* 370 */ "conslist ::= conslist tconscomma tcons",
- /* 371 */ "conslist ::= tcons",
- /* 372 */ "tconscomma ::=",
- /* 373 */ "defer_subclause_opt ::= defer_subclause",
- /* 374 */ "resolvetype ::= raisetype",
- /* 375 */ "selectnowith ::= oneselect",
- /* 376 */ "oneselect ::= values",
- /* 377 */ "sclp ::= selcollist COMMA",
- /* 378 */ "as ::= ID|STRING",
- /* 379 */ "indexed_opt ::= indexed_by",
- /* 380 */ "returning ::=",
- /* 381 */ "expr ::= term",
- /* 382 */ "likeop ::= LIKE_KW|MATCH",
- /* 383 */ "exprlist ::= nexprlist",
- /* 384 */ "nmnum ::= plus_num",
- /* 385 */ "nmnum ::= nm",
- /* 386 */ "nmnum ::= ON",
- /* 387 */ "nmnum ::= DELETE",
- /* 388 */ "nmnum ::= DEFAULT",
- /* 389 */ "plus_num ::= INTEGER|FLOAT",
- /* 390 */ "foreach_clause ::=",
- /* 391 */ "foreach_clause ::= FOR EACH ROW",
- /* 392 */ "trnm ::= nm",
- /* 393 */ "tridxby ::=",
- /* 394 */ "database_kw_opt ::= DATABASE",
- /* 395 */ "database_kw_opt ::=",
- /* 396 */ "kwcolumn_opt ::=",
- /* 397 */ "kwcolumn_opt ::= COLUMNKW",
- /* 398 */ "vtabarglist ::= vtabarg",
- /* 399 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
- /* 400 */ "vtabarg ::= vtabarg vtabargtoken",
- /* 401 */ "anylist ::=",
- /* 402 */ "anylist ::= anylist LP anylist RP",
- /* 403 */ "anylist ::= anylist ANY",
- /* 404 */ "with ::=",
+ /* 178 */ "expr ::= ID|INDEXED|JOIN_KW",
+ /* 179 */ "expr ::= nm DOT nm",
+ /* 180 */ "expr ::= nm DOT nm DOT nm",
+ /* 181 */ "term ::= NULL|FLOAT|BLOB",
+ /* 182 */ "term ::= STRING",
+ /* 183 */ "term ::= INTEGER",
+ /* 184 */ "expr ::= VARIABLE",
+ /* 185 */ "expr ::= expr COLLATE ID|STRING",
+ /* 186 */ "expr ::= CAST LP expr AS typetoken RP",
+ /* 187 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP",
+ /* 188 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP",
+ /* 189 */ "expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over",
+ /* 190 */ "expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over",
+ /* 191 */ "term ::= CTIME_KW",
+ /* 192 */ "expr ::= LP nexprlist COMMA expr RP",
+ /* 193 */ "expr ::= expr AND expr",
+ /* 194 */ "expr ::= expr OR expr",
+ /* 195 */ "expr ::= expr LT|GT|GE|LE expr",
+ /* 196 */ "expr ::= expr EQ|NE expr",
+ /* 197 */ "expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr",
+ /* 198 */ "expr ::= expr PLUS|MINUS expr",
+ /* 199 */ "expr ::= expr STAR|SLASH|REM expr",
+ /* 200 */ "expr ::= expr CONCAT expr",
+ /* 201 */ "likeop ::= NOT LIKE_KW|MATCH",
+ /* 202 */ "expr ::= expr likeop expr",
+ /* 203 */ "expr ::= expr likeop expr ESCAPE expr",
+ /* 204 */ "expr ::= expr ISNULL|NOTNULL",
+ /* 205 */ "expr ::= expr NOT NULL",
+ /* 206 */ "expr ::= expr IS expr",
+ /* 207 */ "expr ::= expr IS NOT expr",
+ /* 208 */ "expr ::= expr IS NOT DISTINCT FROM expr",
+ /* 209 */ "expr ::= expr IS DISTINCT FROM expr",
+ /* 210 */ "expr ::= NOT expr",
+ /* 211 */ "expr ::= BITNOT expr",
+ /* 212 */ "expr ::= PLUS|MINUS expr",
+ /* 213 */ "expr ::= expr PTR expr",
+ /* 214 */ "between_op ::= BETWEEN",
+ /* 215 */ "between_op ::= NOT BETWEEN",
+ /* 216 */ "expr ::= expr between_op expr AND expr",
+ /* 217 */ "in_op ::= IN",
+ /* 218 */ "in_op ::= NOT IN",
+ /* 219 */ "expr ::= expr in_op LP exprlist RP",
+ /* 220 */ "expr ::= LP select RP",
+ /* 221 */ "expr ::= expr in_op LP select RP",
+ /* 222 */ "expr ::= expr in_op nm dbnm paren_exprlist",
+ /* 223 */ "expr ::= EXISTS LP select RP",
+ /* 224 */ "expr ::= CASE case_operand case_exprlist case_else END",
+ /* 225 */ "case_exprlist ::= case_exprlist WHEN expr THEN expr",
+ /* 226 */ "case_exprlist ::= WHEN expr THEN expr",
+ /* 227 */ "case_else ::= ELSE expr",
+ /* 228 */ "case_else ::=",
+ /* 229 */ "case_operand ::=",
+ /* 230 */ "exprlist ::=",
+ /* 231 */ "nexprlist ::= nexprlist COMMA expr",
+ /* 232 */ "nexprlist ::= expr",
+ /* 233 */ "paren_exprlist ::=",
+ /* 234 */ "paren_exprlist ::= LP exprlist RP",
+ /* 235 */ "cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt",
+ /* 236 */ "uniqueflag ::= UNIQUE",
+ /* 237 */ "uniqueflag ::=",
+ /* 238 */ "eidlist_opt ::=",
+ /* 239 */ "eidlist_opt ::= LP eidlist RP",
+ /* 240 */ "eidlist ::= eidlist COMMA nm collate sortorder",
+ /* 241 */ "eidlist ::= nm collate sortorder",
+ /* 242 */ "collate ::=",
+ /* 243 */ "collate ::= COLLATE ID|STRING",
+ /* 244 */ "cmd ::= DROP INDEX ifexists fullname",
+ /* 245 */ "cmd ::= VACUUM vinto",
+ /* 246 */ "cmd ::= VACUUM nm vinto",
+ /* 247 */ "vinto ::= INTO expr",
+ /* 248 */ "vinto ::=",
+ /* 249 */ "cmd ::= PRAGMA nm dbnm",
+ /* 250 */ "cmd ::= PRAGMA nm dbnm EQ nmnum",
+ /* 251 */ "cmd ::= PRAGMA nm dbnm LP nmnum RP",
+ /* 252 */ "cmd ::= PRAGMA nm dbnm EQ minus_num",
+ /* 253 */ "cmd ::= PRAGMA nm dbnm LP minus_num RP",
+ /* 254 */ "plus_num ::= PLUS INTEGER|FLOAT",
+ /* 255 */ "minus_num ::= MINUS INTEGER|FLOAT",
+ /* 256 */ "cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END",
+ /* 257 */ "trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause",
+ /* 258 */ "trigger_time ::= BEFORE|AFTER",
+ /* 259 */ "trigger_time ::= INSTEAD OF",
+ /* 260 */ "trigger_time ::=",
+ /* 261 */ "trigger_event ::= DELETE|INSERT",
+ /* 262 */ "trigger_event ::= UPDATE",
+ /* 263 */ "trigger_event ::= UPDATE OF idlist",
+ /* 264 */ "when_clause ::=",
+ /* 265 */ "when_clause ::= WHEN expr",
+ /* 266 */ "trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI",
+ /* 267 */ "trigger_cmd_list ::= trigger_cmd SEMI",
+ /* 268 */ "trnm ::= nm DOT nm",
+ /* 269 */ "tridxby ::= INDEXED BY nm",
+ /* 270 */ "tridxby ::= NOT INDEXED",
+ /* 271 */ "trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt",
+ /* 272 */ "trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt",
+ /* 273 */ "trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt",
+ /* 274 */ "trigger_cmd ::= scanpt select scanpt",
+ /* 275 */ "expr ::= RAISE LP IGNORE RP",
+ /* 276 */ "expr ::= RAISE LP raisetype COMMA nm RP",
+ /* 277 */ "raisetype ::= ROLLBACK",
+ /* 278 */ "raisetype ::= ABORT",
+ /* 279 */ "raisetype ::= FAIL",
+ /* 280 */ "cmd ::= DROP TRIGGER ifexists fullname",
+ /* 281 */ "cmd ::= ATTACH database_kw_opt expr AS expr key_opt",
+ /* 282 */ "cmd ::= DETACH database_kw_opt expr",
+ /* 283 */ "key_opt ::=",
+ /* 284 */ "key_opt ::= KEY expr",
+ /* 285 */ "cmd ::= REINDEX",
+ /* 286 */ "cmd ::= REINDEX nm dbnm",
+ /* 287 */ "cmd ::= ANALYZE",
+ /* 288 */ "cmd ::= ANALYZE nm dbnm",
+ /* 289 */ "cmd ::= ALTER TABLE fullname RENAME TO nm",
+ /* 290 */ "cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist",
+ /* 291 */ "cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm",
+ /* 292 */ "add_column_fullname ::= fullname",
+ /* 293 */ "cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm",
+ /* 294 */ "cmd ::= create_vtab",
+ /* 295 */ "cmd ::= create_vtab LP vtabarglist RP",
+ /* 296 */ "create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm",
+ /* 297 */ "vtabarg ::=",
+ /* 298 */ "vtabargtoken ::= ANY",
+ /* 299 */ "vtabargtoken ::= lp anylist RP",
+ /* 300 */ "lp ::= LP",
+ /* 301 */ "with ::= WITH wqlist",
+ /* 302 */ "with ::= WITH RECURSIVE wqlist",
+ /* 303 */ "wqas ::= AS",
+ /* 304 */ "wqas ::= AS MATERIALIZED",
+ /* 305 */ "wqas ::= AS NOT MATERIALIZED",
+ /* 306 */ "wqitem ::= nm eidlist_opt wqas LP select RP",
+ /* 307 */ "wqlist ::= wqitem",
+ /* 308 */ "wqlist ::= wqlist COMMA wqitem",
+ /* 309 */ "windowdefn_list ::= windowdefn",
+ /* 310 */ "windowdefn_list ::= windowdefn_list COMMA windowdefn",
+ /* 311 */ "windowdefn ::= nm AS LP window RP",
+ /* 312 */ "window ::= PARTITION BY nexprlist orderby_opt frame_opt",
+ /* 313 */ "window ::= nm PARTITION BY nexprlist orderby_opt frame_opt",
+ /* 314 */ "window ::= ORDER BY sortlist frame_opt",
+ /* 315 */ "window ::= nm ORDER BY sortlist frame_opt",
+ /* 316 */ "window ::= frame_opt",
+ /* 317 */ "window ::= nm frame_opt",
+ /* 318 */ "frame_opt ::=",
+ /* 319 */ "frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt",
+ /* 320 */ "frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt",
+ /* 321 */ "range_or_rows ::= RANGE|ROWS|GROUPS",
+ /* 322 */ "frame_bound_s ::= frame_bound",
+ /* 323 */ "frame_bound_s ::= UNBOUNDED PRECEDING",
+ /* 324 */ "frame_bound_e ::= frame_bound",
+ /* 325 */ "frame_bound_e ::= UNBOUNDED FOLLOWING",
+ /* 326 */ "frame_bound ::= expr PRECEDING|FOLLOWING",
+ /* 327 */ "frame_bound ::= CURRENT ROW",
+ /* 328 */ "frame_exclude_opt ::=",
+ /* 329 */ "frame_exclude_opt ::= EXCLUDE frame_exclude",
+ /* 330 */ "frame_exclude ::= NO OTHERS",
+ /* 331 */ "frame_exclude ::= CURRENT ROW",
+ /* 332 */ "frame_exclude ::= GROUP|TIES",
+ /* 333 */ "window_clause ::= WINDOW windowdefn_list",
+ /* 334 */ "filter_over ::= filter_clause over_clause",
+ /* 335 */ "filter_over ::= over_clause",
+ /* 336 */ "filter_over ::= filter_clause",
+ /* 337 */ "over_clause ::= OVER LP window RP",
+ /* 338 */ "over_clause ::= OVER nm",
+ /* 339 */ "filter_clause ::= FILTER LP WHERE expr RP",
+ /* 340 */ "input ::= cmdlist",
+ /* 341 */ "cmdlist ::= cmdlist ecmd",
+ /* 342 */ "cmdlist ::= ecmd",
+ /* 343 */ "ecmd ::= SEMI",
+ /* 344 */ "ecmd ::= cmdx SEMI",
+ /* 345 */ "ecmd ::= explain cmdx SEMI",
+ /* 346 */ "trans_opt ::=",
+ /* 347 */ "trans_opt ::= TRANSACTION",
+ /* 348 */ "trans_opt ::= TRANSACTION nm",
+ /* 349 */ "savepoint_opt ::= SAVEPOINT",
+ /* 350 */ "savepoint_opt ::=",
+ /* 351 */ "cmd ::= create_table create_table_args",
+ /* 352 */ "table_option_set ::= table_option",
+ /* 353 */ "columnlist ::= columnlist COMMA columnname carglist",
+ /* 354 */ "columnlist ::= columnname carglist",
+ /* 355 */ "nm ::= ID|INDEXED|JOIN_KW",
+ /* 356 */ "nm ::= STRING",
+ /* 357 */ "typetoken ::= typename",
+ /* 358 */ "typename ::= ID|STRING",
+ /* 359 */ "signed ::= plus_num",
+ /* 360 */ "signed ::= minus_num",
+ /* 361 */ "carglist ::= carglist ccons",
+ /* 362 */ "carglist ::=",
+ /* 363 */ "ccons ::= NULL onconf",
+ /* 364 */ "ccons ::= GENERATED ALWAYS AS generated",
+ /* 365 */ "ccons ::= AS generated",
+ /* 366 */ "conslist_opt ::= COMMA conslist",
+ /* 367 */ "conslist ::= conslist tconscomma tcons",
+ /* 368 */ "conslist ::= tcons",
+ /* 369 */ "tconscomma ::=",
+ /* 370 */ "defer_subclause_opt ::= defer_subclause",
+ /* 371 */ "resolvetype ::= raisetype",
+ /* 372 */ "selectnowith ::= oneselect",
+ /* 373 */ "oneselect ::= values",
+ /* 374 */ "sclp ::= selcollist COMMA",
+ /* 375 */ "as ::= ID|STRING",
+ /* 376 */ "indexed_opt ::= indexed_by",
+ /* 377 */ "returning ::=",
+ /* 378 */ "expr ::= term",
+ /* 379 */ "likeop ::= LIKE_KW|MATCH",
+ /* 380 */ "case_operand ::= expr",
+ /* 381 */ "exprlist ::= nexprlist",
+ /* 382 */ "nmnum ::= plus_num",
+ /* 383 */ "nmnum ::= nm",
+ /* 384 */ "nmnum ::= ON",
+ /* 385 */ "nmnum ::= DELETE",
+ /* 386 */ "nmnum ::= DEFAULT",
+ /* 387 */ "plus_num ::= INTEGER|FLOAT",
+ /* 388 */ "foreach_clause ::=",
+ /* 389 */ "foreach_clause ::= FOR EACH ROW",
+ /* 390 */ "trnm ::= nm",
+ /* 391 */ "tridxby ::=",
+ /* 392 */ "database_kw_opt ::= DATABASE",
+ /* 393 */ "database_kw_opt ::=",
+ /* 394 */ "kwcolumn_opt ::=",
+ /* 395 */ "kwcolumn_opt ::= COLUMNKW",
+ /* 396 */ "vtabarglist ::= vtabarg",
+ /* 397 */ "vtabarglist ::= vtabarglist COMMA vtabarg",
+ /* 398 */ "vtabarg ::= vtabarg vtabargtoken",
+ /* 399 */ "anylist ::=",
+ /* 400 */ "anylist ::= anylist LP anylist RP",
+ /* 401 */ "anylist ::= anylist ANY",
+ /* 402 */ "with ::=",
};
#endif /* NDEBUG */
@@ -169629,233 +170623,231 @@ static const YYCODETYPE yyRuleInfoLhs[] = {
263, /* (175) idlist ::= idlist COMMA nm */
263, /* (176) idlist ::= nm */
217, /* (177) expr ::= LP expr RP */
- 217, /* (178) expr ::= ID|INDEXED */
- 217, /* (179) expr ::= JOIN_KW */
- 217, /* (180) expr ::= nm DOT nm */
- 217, /* (181) expr ::= nm DOT nm DOT nm */
- 216, /* (182) term ::= NULL|FLOAT|BLOB */
- 216, /* (183) term ::= STRING */
- 216, /* (184) term ::= INTEGER */
- 217, /* (185) expr ::= VARIABLE */
- 217, /* (186) expr ::= expr COLLATE ID|STRING */
- 217, /* (187) expr ::= CAST LP expr AS typetoken RP */
- 217, /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */
- 217, /* (189) expr ::= ID|INDEXED LP STAR RP */
- 217, /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
- 217, /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */
- 216, /* (192) term ::= CTIME_KW */
- 217, /* (193) expr ::= LP nexprlist COMMA expr RP */
- 217, /* (194) expr ::= expr AND expr */
- 217, /* (195) expr ::= expr OR expr */
- 217, /* (196) expr ::= expr LT|GT|GE|LE expr */
- 217, /* (197) expr ::= expr EQ|NE expr */
- 217, /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
- 217, /* (199) expr ::= expr PLUS|MINUS expr */
- 217, /* (200) expr ::= expr STAR|SLASH|REM expr */
- 217, /* (201) expr ::= expr CONCAT expr */
- 274, /* (202) likeop ::= NOT LIKE_KW|MATCH */
- 217, /* (203) expr ::= expr likeop expr */
- 217, /* (204) expr ::= expr likeop expr ESCAPE expr */
- 217, /* (205) expr ::= expr ISNULL|NOTNULL */
- 217, /* (206) expr ::= expr NOT NULL */
- 217, /* (207) expr ::= expr IS expr */
- 217, /* (208) expr ::= expr IS NOT expr */
- 217, /* (209) expr ::= expr IS NOT DISTINCT FROM expr */
- 217, /* (210) expr ::= expr IS DISTINCT FROM expr */
- 217, /* (211) expr ::= NOT expr */
- 217, /* (212) expr ::= BITNOT expr */
- 217, /* (213) expr ::= PLUS|MINUS expr */
- 217, /* (214) expr ::= expr PTR expr */
- 275, /* (215) between_op ::= BETWEEN */
- 275, /* (216) between_op ::= NOT BETWEEN */
- 217, /* (217) expr ::= expr between_op expr AND expr */
- 276, /* (218) in_op ::= IN */
- 276, /* (219) in_op ::= NOT IN */
- 217, /* (220) expr ::= expr in_op LP exprlist RP */
- 217, /* (221) expr ::= LP select RP */
- 217, /* (222) expr ::= expr in_op LP select RP */
- 217, /* (223) expr ::= expr in_op nm dbnm paren_exprlist */
- 217, /* (224) expr ::= EXISTS LP select RP */
- 217, /* (225) expr ::= CASE case_operand case_exprlist case_else END */
- 279, /* (226) case_exprlist ::= case_exprlist WHEN expr THEN expr */
- 279, /* (227) case_exprlist ::= WHEN expr THEN expr */
- 280, /* (228) case_else ::= ELSE expr */
- 280, /* (229) case_else ::= */
- 278, /* (230) case_operand ::= expr */
- 278, /* (231) case_operand ::= */
- 261, /* (232) exprlist ::= */
- 253, /* (233) nexprlist ::= nexprlist COMMA expr */
- 253, /* (234) nexprlist ::= expr */
- 277, /* (235) paren_exprlist ::= */
- 277, /* (236) paren_exprlist ::= LP exprlist RP */
- 190, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
- 281, /* (238) uniqueflag ::= UNIQUE */
- 281, /* (239) uniqueflag ::= */
- 221, /* (240) eidlist_opt ::= */
- 221, /* (241) eidlist_opt ::= LP eidlist RP */
- 232, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */
- 232, /* (243) eidlist ::= nm collate sortorder */
- 282, /* (244) collate ::= */
- 282, /* (245) collate ::= COLLATE ID|STRING */
- 190, /* (246) cmd ::= DROP INDEX ifexists fullname */
- 190, /* (247) cmd ::= VACUUM vinto */
- 190, /* (248) cmd ::= VACUUM nm vinto */
- 283, /* (249) vinto ::= INTO expr */
- 283, /* (250) vinto ::= */
- 190, /* (251) cmd ::= PRAGMA nm dbnm */
- 190, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */
- 190, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */
- 190, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */
- 190, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */
- 211, /* (256) plus_num ::= PLUS INTEGER|FLOAT */
- 212, /* (257) minus_num ::= MINUS INTEGER|FLOAT */
- 190, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
- 285, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
- 287, /* (260) trigger_time ::= BEFORE|AFTER */
- 287, /* (261) trigger_time ::= INSTEAD OF */
- 287, /* (262) trigger_time ::= */
- 288, /* (263) trigger_event ::= DELETE|INSERT */
- 288, /* (264) trigger_event ::= UPDATE */
- 288, /* (265) trigger_event ::= UPDATE OF idlist */
- 290, /* (266) when_clause ::= */
- 290, /* (267) when_clause ::= WHEN expr */
- 286, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
- 286, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */
- 292, /* (270) trnm ::= nm DOT nm */
- 293, /* (271) tridxby ::= INDEXED BY nm */
- 293, /* (272) tridxby ::= NOT INDEXED */
- 291, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
- 291, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
- 291, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
- 291, /* (276) trigger_cmd ::= scanpt select scanpt */
- 217, /* (277) expr ::= RAISE LP IGNORE RP */
- 217, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */
- 236, /* (279) raisetype ::= ROLLBACK */
- 236, /* (280) raisetype ::= ABORT */
- 236, /* (281) raisetype ::= FAIL */
- 190, /* (282) cmd ::= DROP TRIGGER ifexists fullname */
- 190, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
- 190, /* (284) cmd ::= DETACH database_kw_opt expr */
- 295, /* (285) key_opt ::= */
- 295, /* (286) key_opt ::= KEY expr */
- 190, /* (287) cmd ::= REINDEX */
- 190, /* (288) cmd ::= REINDEX nm dbnm */
- 190, /* (289) cmd ::= ANALYZE */
- 190, /* (290) cmd ::= ANALYZE nm dbnm */
- 190, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */
- 190, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
- 190, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
- 296, /* (294) add_column_fullname ::= fullname */
- 190, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
- 190, /* (296) cmd ::= create_vtab */
- 190, /* (297) cmd ::= create_vtab LP vtabarglist RP */
- 298, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
- 300, /* (299) vtabarg ::= */
- 301, /* (300) vtabargtoken ::= ANY */
- 301, /* (301) vtabargtoken ::= lp anylist RP */
- 302, /* (302) lp ::= LP */
- 266, /* (303) with ::= WITH wqlist */
- 266, /* (304) with ::= WITH RECURSIVE wqlist */
- 305, /* (305) wqas ::= AS */
- 305, /* (306) wqas ::= AS MATERIALIZED */
- 305, /* (307) wqas ::= AS NOT MATERIALIZED */
- 304, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */
- 241, /* (309) wqlist ::= wqitem */
- 241, /* (310) wqlist ::= wqlist COMMA wqitem */
- 306, /* (311) windowdefn_list ::= windowdefn */
- 306, /* (312) windowdefn_list ::= windowdefn_list COMMA windowdefn */
- 307, /* (313) windowdefn ::= nm AS LP window RP */
- 308, /* (314) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
- 308, /* (315) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
- 308, /* (316) window ::= ORDER BY sortlist frame_opt */
- 308, /* (317) window ::= nm ORDER BY sortlist frame_opt */
- 308, /* (318) window ::= frame_opt */
- 308, /* (319) window ::= nm frame_opt */
- 309, /* (320) frame_opt ::= */
- 309, /* (321) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
- 309, /* (322) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
- 313, /* (323) range_or_rows ::= RANGE|ROWS|GROUPS */
- 315, /* (324) frame_bound_s ::= frame_bound */
- 315, /* (325) frame_bound_s ::= UNBOUNDED PRECEDING */
- 316, /* (326) frame_bound_e ::= frame_bound */
- 316, /* (327) frame_bound_e ::= UNBOUNDED FOLLOWING */
- 314, /* (328) frame_bound ::= expr PRECEDING|FOLLOWING */
- 314, /* (329) frame_bound ::= CURRENT ROW */
- 317, /* (330) frame_exclude_opt ::= */
- 317, /* (331) frame_exclude_opt ::= EXCLUDE frame_exclude */
- 318, /* (332) frame_exclude ::= NO OTHERS */
- 318, /* (333) frame_exclude ::= CURRENT ROW */
- 318, /* (334) frame_exclude ::= GROUP|TIES */
- 251, /* (335) window_clause ::= WINDOW windowdefn_list */
- 273, /* (336) filter_over ::= filter_clause over_clause */
- 273, /* (337) filter_over ::= over_clause */
- 273, /* (338) filter_over ::= filter_clause */
- 312, /* (339) over_clause ::= OVER LP window RP */
- 312, /* (340) over_clause ::= OVER nm */
- 311, /* (341) filter_clause ::= FILTER LP WHERE expr RP */
- 185, /* (342) input ::= cmdlist */
- 186, /* (343) cmdlist ::= cmdlist ecmd */
- 186, /* (344) cmdlist ::= ecmd */
- 187, /* (345) ecmd ::= SEMI */
- 187, /* (346) ecmd ::= cmdx SEMI */
- 187, /* (347) ecmd ::= explain cmdx SEMI */
- 192, /* (348) trans_opt ::= */
- 192, /* (349) trans_opt ::= TRANSACTION */
- 192, /* (350) trans_opt ::= TRANSACTION nm */
- 194, /* (351) savepoint_opt ::= SAVEPOINT */
- 194, /* (352) savepoint_opt ::= */
- 190, /* (353) cmd ::= create_table create_table_args */
- 203, /* (354) table_option_set ::= table_option */
- 201, /* (355) columnlist ::= columnlist COMMA columnname carglist */
- 201, /* (356) columnlist ::= columnname carglist */
- 193, /* (357) nm ::= ID|INDEXED */
- 193, /* (358) nm ::= STRING */
- 193, /* (359) nm ::= JOIN_KW */
- 208, /* (360) typetoken ::= typename */
- 209, /* (361) typename ::= ID|STRING */
- 210, /* (362) signed ::= plus_num */
- 210, /* (363) signed ::= minus_num */
- 207, /* (364) carglist ::= carglist ccons */
- 207, /* (365) carglist ::= */
- 215, /* (366) ccons ::= NULL onconf */
- 215, /* (367) ccons ::= GENERATED ALWAYS AS generated */
- 215, /* (368) ccons ::= AS generated */
- 202, /* (369) conslist_opt ::= COMMA conslist */
- 228, /* (370) conslist ::= conslist tconscomma tcons */
- 228, /* (371) conslist ::= tcons */
- 229, /* (372) tconscomma ::= */
- 233, /* (373) defer_subclause_opt ::= defer_subclause */
- 235, /* (374) resolvetype ::= raisetype */
- 239, /* (375) selectnowith ::= oneselect */
- 240, /* (376) oneselect ::= values */
- 254, /* (377) sclp ::= selcollist COMMA */
- 255, /* (378) as ::= ID|STRING */
- 264, /* (379) indexed_opt ::= indexed_by */
- 272, /* (380) returning ::= */
- 217, /* (381) expr ::= term */
- 274, /* (382) likeop ::= LIKE_KW|MATCH */
- 261, /* (383) exprlist ::= nexprlist */
- 284, /* (384) nmnum ::= plus_num */
- 284, /* (385) nmnum ::= nm */
- 284, /* (386) nmnum ::= ON */
- 284, /* (387) nmnum ::= DELETE */
- 284, /* (388) nmnum ::= DEFAULT */
- 211, /* (389) plus_num ::= INTEGER|FLOAT */
- 289, /* (390) foreach_clause ::= */
- 289, /* (391) foreach_clause ::= FOR EACH ROW */
- 292, /* (392) trnm ::= nm */
- 293, /* (393) tridxby ::= */
- 294, /* (394) database_kw_opt ::= DATABASE */
- 294, /* (395) database_kw_opt ::= */
- 297, /* (396) kwcolumn_opt ::= */
- 297, /* (397) kwcolumn_opt ::= COLUMNKW */
- 299, /* (398) vtabarglist ::= vtabarg */
- 299, /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */
- 300, /* (400) vtabarg ::= vtabarg vtabargtoken */
- 303, /* (401) anylist ::= */
- 303, /* (402) anylist ::= anylist LP anylist RP */
- 303, /* (403) anylist ::= anylist ANY */
- 266, /* (404) with ::= */
+ 217, /* (178) expr ::= ID|INDEXED|JOIN_KW */
+ 217, /* (179) expr ::= nm DOT nm */
+ 217, /* (180) expr ::= nm DOT nm DOT nm */
+ 216, /* (181) term ::= NULL|FLOAT|BLOB */
+ 216, /* (182) term ::= STRING */
+ 216, /* (183) term ::= INTEGER */
+ 217, /* (184) expr ::= VARIABLE */
+ 217, /* (185) expr ::= expr COLLATE ID|STRING */
+ 217, /* (186) expr ::= CAST LP expr AS typetoken RP */
+ 217, /* (187) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
+ 217, /* (188) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
+ 217, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
+ 217, /* (190) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
+ 216, /* (191) term ::= CTIME_KW */
+ 217, /* (192) expr ::= LP nexprlist COMMA expr RP */
+ 217, /* (193) expr ::= expr AND expr */
+ 217, /* (194) expr ::= expr OR expr */
+ 217, /* (195) expr ::= expr LT|GT|GE|LE expr */
+ 217, /* (196) expr ::= expr EQ|NE expr */
+ 217, /* (197) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ 217, /* (198) expr ::= expr PLUS|MINUS expr */
+ 217, /* (199) expr ::= expr STAR|SLASH|REM expr */
+ 217, /* (200) expr ::= expr CONCAT expr */
+ 274, /* (201) likeop ::= NOT LIKE_KW|MATCH */
+ 217, /* (202) expr ::= expr likeop expr */
+ 217, /* (203) expr ::= expr likeop expr ESCAPE expr */
+ 217, /* (204) expr ::= expr ISNULL|NOTNULL */
+ 217, /* (205) expr ::= expr NOT NULL */
+ 217, /* (206) expr ::= expr IS expr */
+ 217, /* (207) expr ::= expr IS NOT expr */
+ 217, /* (208) expr ::= expr IS NOT DISTINCT FROM expr */
+ 217, /* (209) expr ::= expr IS DISTINCT FROM expr */
+ 217, /* (210) expr ::= NOT expr */
+ 217, /* (211) expr ::= BITNOT expr */
+ 217, /* (212) expr ::= PLUS|MINUS expr */
+ 217, /* (213) expr ::= expr PTR expr */
+ 275, /* (214) between_op ::= BETWEEN */
+ 275, /* (215) between_op ::= NOT BETWEEN */
+ 217, /* (216) expr ::= expr between_op expr AND expr */
+ 276, /* (217) in_op ::= IN */
+ 276, /* (218) in_op ::= NOT IN */
+ 217, /* (219) expr ::= expr in_op LP exprlist RP */
+ 217, /* (220) expr ::= LP select RP */
+ 217, /* (221) expr ::= expr in_op LP select RP */
+ 217, /* (222) expr ::= expr in_op nm dbnm paren_exprlist */
+ 217, /* (223) expr ::= EXISTS LP select RP */
+ 217, /* (224) expr ::= CASE case_operand case_exprlist case_else END */
+ 279, /* (225) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ 279, /* (226) case_exprlist ::= WHEN expr THEN expr */
+ 280, /* (227) case_else ::= ELSE expr */
+ 280, /* (228) case_else ::= */
+ 278, /* (229) case_operand ::= */
+ 261, /* (230) exprlist ::= */
+ 253, /* (231) nexprlist ::= nexprlist COMMA expr */
+ 253, /* (232) nexprlist ::= expr */
+ 277, /* (233) paren_exprlist ::= */
+ 277, /* (234) paren_exprlist ::= LP exprlist RP */
+ 190, /* (235) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ 281, /* (236) uniqueflag ::= UNIQUE */
+ 281, /* (237) uniqueflag ::= */
+ 221, /* (238) eidlist_opt ::= */
+ 221, /* (239) eidlist_opt ::= LP eidlist RP */
+ 232, /* (240) eidlist ::= eidlist COMMA nm collate sortorder */
+ 232, /* (241) eidlist ::= nm collate sortorder */
+ 282, /* (242) collate ::= */
+ 282, /* (243) collate ::= COLLATE ID|STRING */
+ 190, /* (244) cmd ::= DROP INDEX ifexists fullname */
+ 190, /* (245) cmd ::= VACUUM vinto */
+ 190, /* (246) cmd ::= VACUUM nm vinto */
+ 283, /* (247) vinto ::= INTO expr */
+ 283, /* (248) vinto ::= */
+ 190, /* (249) cmd ::= PRAGMA nm dbnm */
+ 190, /* (250) cmd ::= PRAGMA nm dbnm EQ nmnum */
+ 190, /* (251) cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ 190, /* (252) cmd ::= PRAGMA nm dbnm EQ minus_num */
+ 190, /* (253) cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ 211, /* (254) plus_num ::= PLUS INTEGER|FLOAT */
+ 212, /* (255) minus_num ::= MINUS INTEGER|FLOAT */
+ 190, /* (256) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ 285, /* (257) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ 287, /* (258) trigger_time ::= BEFORE|AFTER */
+ 287, /* (259) trigger_time ::= INSTEAD OF */
+ 287, /* (260) trigger_time ::= */
+ 288, /* (261) trigger_event ::= DELETE|INSERT */
+ 288, /* (262) trigger_event ::= UPDATE */
+ 288, /* (263) trigger_event ::= UPDATE OF idlist */
+ 290, /* (264) when_clause ::= */
+ 290, /* (265) when_clause ::= WHEN expr */
+ 286, /* (266) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ 286, /* (267) trigger_cmd_list ::= trigger_cmd SEMI */
+ 292, /* (268) trnm ::= nm DOT nm */
+ 293, /* (269) tridxby ::= INDEXED BY nm */
+ 293, /* (270) tridxby ::= NOT INDEXED */
+ 291, /* (271) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+ 291, /* (272) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ 291, /* (273) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+ 291, /* (274) trigger_cmd ::= scanpt select scanpt */
+ 217, /* (275) expr ::= RAISE LP IGNORE RP */
+ 217, /* (276) expr ::= RAISE LP raisetype COMMA nm RP */
+ 236, /* (277) raisetype ::= ROLLBACK */
+ 236, /* (278) raisetype ::= ABORT */
+ 236, /* (279) raisetype ::= FAIL */
+ 190, /* (280) cmd ::= DROP TRIGGER ifexists fullname */
+ 190, /* (281) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ 190, /* (282) cmd ::= DETACH database_kw_opt expr */
+ 295, /* (283) key_opt ::= */
+ 295, /* (284) key_opt ::= KEY expr */
+ 190, /* (285) cmd ::= REINDEX */
+ 190, /* (286) cmd ::= REINDEX nm dbnm */
+ 190, /* (287) cmd ::= ANALYZE */
+ 190, /* (288) cmd ::= ANALYZE nm dbnm */
+ 190, /* (289) cmd ::= ALTER TABLE fullname RENAME TO nm */
+ 190, /* (290) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ 190, /* (291) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
+ 296, /* (292) add_column_fullname ::= fullname */
+ 190, /* (293) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ 190, /* (294) cmd ::= create_vtab */
+ 190, /* (295) cmd ::= create_vtab LP vtabarglist RP */
+ 298, /* (296) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ 300, /* (297) vtabarg ::= */
+ 301, /* (298) vtabargtoken ::= ANY */
+ 301, /* (299) vtabargtoken ::= lp anylist RP */
+ 302, /* (300) lp ::= LP */
+ 266, /* (301) with ::= WITH wqlist */
+ 266, /* (302) with ::= WITH RECURSIVE wqlist */
+ 305, /* (303) wqas ::= AS */
+ 305, /* (304) wqas ::= AS MATERIALIZED */
+ 305, /* (305) wqas ::= AS NOT MATERIALIZED */
+ 304, /* (306) wqitem ::= nm eidlist_opt wqas LP select RP */
+ 241, /* (307) wqlist ::= wqitem */
+ 241, /* (308) wqlist ::= wqlist COMMA wqitem */
+ 306, /* (309) windowdefn_list ::= windowdefn */
+ 306, /* (310) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ 307, /* (311) windowdefn ::= nm AS LP window RP */
+ 308, /* (312) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ 308, /* (313) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ 308, /* (314) window ::= ORDER BY sortlist frame_opt */
+ 308, /* (315) window ::= nm ORDER BY sortlist frame_opt */
+ 308, /* (316) window ::= frame_opt */
+ 308, /* (317) window ::= nm frame_opt */
+ 309, /* (318) frame_opt ::= */
+ 309, /* (319) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ 309, /* (320) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ 313, /* (321) range_or_rows ::= RANGE|ROWS|GROUPS */
+ 315, /* (322) frame_bound_s ::= frame_bound */
+ 315, /* (323) frame_bound_s ::= UNBOUNDED PRECEDING */
+ 316, /* (324) frame_bound_e ::= frame_bound */
+ 316, /* (325) frame_bound_e ::= UNBOUNDED FOLLOWING */
+ 314, /* (326) frame_bound ::= expr PRECEDING|FOLLOWING */
+ 314, /* (327) frame_bound ::= CURRENT ROW */
+ 317, /* (328) frame_exclude_opt ::= */
+ 317, /* (329) frame_exclude_opt ::= EXCLUDE frame_exclude */
+ 318, /* (330) frame_exclude ::= NO OTHERS */
+ 318, /* (331) frame_exclude ::= CURRENT ROW */
+ 318, /* (332) frame_exclude ::= GROUP|TIES */
+ 251, /* (333) window_clause ::= WINDOW windowdefn_list */
+ 273, /* (334) filter_over ::= filter_clause over_clause */
+ 273, /* (335) filter_over ::= over_clause */
+ 273, /* (336) filter_over ::= filter_clause */
+ 312, /* (337) over_clause ::= OVER LP window RP */
+ 312, /* (338) over_clause ::= OVER nm */
+ 311, /* (339) filter_clause ::= FILTER LP WHERE expr RP */
+ 185, /* (340) input ::= cmdlist */
+ 186, /* (341) cmdlist ::= cmdlist ecmd */
+ 186, /* (342) cmdlist ::= ecmd */
+ 187, /* (343) ecmd ::= SEMI */
+ 187, /* (344) ecmd ::= cmdx SEMI */
+ 187, /* (345) ecmd ::= explain cmdx SEMI */
+ 192, /* (346) trans_opt ::= */
+ 192, /* (347) trans_opt ::= TRANSACTION */
+ 192, /* (348) trans_opt ::= TRANSACTION nm */
+ 194, /* (349) savepoint_opt ::= SAVEPOINT */
+ 194, /* (350) savepoint_opt ::= */
+ 190, /* (351) cmd ::= create_table create_table_args */
+ 203, /* (352) table_option_set ::= table_option */
+ 201, /* (353) columnlist ::= columnlist COMMA columnname carglist */
+ 201, /* (354) columnlist ::= columnname carglist */
+ 193, /* (355) nm ::= ID|INDEXED|JOIN_KW */
+ 193, /* (356) nm ::= STRING */
+ 208, /* (357) typetoken ::= typename */
+ 209, /* (358) typename ::= ID|STRING */
+ 210, /* (359) signed ::= plus_num */
+ 210, /* (360) signed ::= minus_num */
+ 207, /* (361) carglist ::= carglist ccons */
+ 207, /* (362) carglist ::= */
+ 215, /* (363) ccons ::= NULL onconf */
+ 215, /* (364) ccons ::= GENERATED ALWAYS AS generated */
+ 215, /* (365) ccons ::= AS generated */
+ 202, /* (366) conslist_opt ::= COMMA conslist */
+ 228, /* (367) conslist ::= conslist tconscomma tcons */
+ 228, /* (368) conslist ::= tcons */
+ 229, /* (369) tconscomma ::= */
+ 233, /* (370) defer_subclause_opt ::= defer_subclause */
+ 235, /* (371) resolvetype ::= raisetype */
+ 239, /* (372) selectnowith ::= oneselect */
+ 240, /* (373) oneselect ::= values */
+ 254, /* (374) sclp ::= selcollist COMMA */
+ 255, /* (375) as ::= ID|STRING */
+ 264, /* (376) indexed_opt ::= indexed_by */
+ 272, /* (377) returning ::= */
+ 217, /* (378) expr ::= term */
+ 274, /* (379) likeop ::= LIKE_KW|MATCH */
+ 278, /* (380) case_operand ::= expr */
+ 261, /* (381) exprlist ::= nexprlist */
+ 284, /* (382) nmnum ::= plus_num */
+ 284, /* (383) nmnum ::= nm */
+ 284, /* (384) nmnum ::= ON */
+ 284, /* (385) nmnum ::= DELETE */
+ 284, /* (386) nmnum ::= DEFAULT */
+ 211, /* (387) plus_num ::= INTEGER|FLOAT */
+ 289, /* (388) foreach_clause ::= */
+ 289, /* (389) foreach_clause ::= FOR EACH ROW */
+ 292, /* (390) trnm ::= nm */
+ 293, /* (391) tridxby ::= */
+ 294, /* (392) database_kw_opt ::= DATABASE */
+ 294, /* (393) database_kw_opt ::= */
+ 297, /* (394) kwcolumn_opt ::= */
+ 297, /* (395) kwcolumn_opt ::= COLUMNKW */
+ 299, /* (396) vtabarglist ::= vtabarg */
+ 299, /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */
+ 300, /* (398) vtabarg ::= vtabarg vtabargtoken */
+ 303, /* (399) anylist ::= */
+ 303, /* (400) anylist ::= anylist LP anylist RP */
+ 303, /* (401) anylist ::= anylist ANY */
+ 266, /* (402) with ::= */
};
/* For rule J, yyRuleInfoNRhs[J] contains the negative of the number
@@ -170039,233 +171031,231 @@ static const signed char yyRuleInfoNRhs[] = {
-3, /* (175) idlist ::= idlist COMMA nm */
-1, /* (176) idlist ::= nm */
-3, /* (177) expr ::= LP expr RP */
- -1, /* (178) expr ::= ID|INDEXED */
- -1, /* (179) expr ::= JOIN_KW */
- -3, /* (180) expr ::= nm DOT nm */
- -5, /* (181) expr ::= nm DOT nm DOT nm */
- -1, /* (182) term ::= NULL|FLOAT|BLOB */
- -1, /* (183) term ::= STRING */
- -1, /* (184) term ::= INTEGER */
- -1, /* (185) expr ::= VARIABLE */
- -3, /* (186) expr ::= expr COLLATE ID|STRING */
- -6, /* (187) expr ::= CAST LP expr AS typetoken RP */
- -5, /* (188) expr ::= ID|INDEXED LP distinct exprlist RP */
- -4, /* (189) expr ::= ID|INDEXED LP STAR RP */
- -6, /* (190) expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
- -5, /* (191) expr ::= ID|INDEXED LP STAR RP filter_over */
- -1, /* (192) term ::= CTIME_KW */
- -5, /* (193) expr ::= LP nexprlist COMMA expr RP */
- -3, /* (194) expr ::= expr AND expr */
- -3, /* (195) expr ::= expr OR expr */
- -3, /* (196) expr ::= expr LT|GT|GE|LE expr */
- -3, /* (197) expr ::= expr EQ|NE expr */
- -3, /* (198) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
- -3, /* (199) expr ::= expr PLUS|MINUS expr */
- -3, /* (200) expr ::= expr STAR|SLASH|REM expr */
- -3, /* (201) expr ::= expr CONCAT expr */
- -2, /* (202) likeop ::= NOT LIKE_KW|MATCH */
- -3, /* (203) expr ::= expr likeop expr */
- -5, /* (204) expr ::= expr likeop expr ESCAPE expr */
- -2, /* (205) expr ::= expr ISNULL|NOTNULL */
- -3, /* (206) expr ::= expr NOT NULL */
- -3, /* (207) expr ::= expr IS expr */
- -4, /* (208) expr ::= expr IS NOT expr */
- -6, /* (209) expr ::= expr IS NOT DISTINCT FROM expr */
- -5, /* (210) expr ::= expr IS DISTINCT FROM expr */
- -2, /* (211) expr ::= NOT expr */
- -2, /* (212) expr ::= BITNOT expr */
- -2, /* (213) expr ::= PLUS|MINUS expr */
- -3, /* (214) expr ::= expr PTR expr */
- -1, /* (215) between_op ::= BETWEEN */
- -2, /* (216) between_op ::= NOT BETWEEN */
- -5, /* (217) expr ::= expr between_op expr AND expr */
- -1, /* (218) in_op ::= IN */
- -2, /* (219) in_op ::= NOT IN */
- -5, /* (220) expr ::= expr in_op LP exprlist RP */
- -3, /* (221) expr ::= LP select RP */
- -5, /* (222) expr ::= expr in_op LP select RP */
- -5, /* (223) expr ::= expr in_op nm dbnm paren_exprlist */
- -4, /* (224) expr ::= EXISTS LP select RP */
- -5, /* (225) expr ::= CASE case_operand case_exprlist case_else END */
- -5, /* (226) case_exprlist ::= case_exprlist WHEN expr THEN expr */
- -4, /* (227) case_exprlist ::= WHEN expr THEN expr */
- -2, /* (228) case_else ::= ELSE expr */
- 0, /* (229) case_else ::= */
- -1, /* (230) case_operand ::= expr */
- 0, /* (231) case_operand ::= */
- 0, /* (232) exprlist ::= */
- -3, /* (233) nexprlist ::= nexprlist COMMA expr */
- -1, /* (234) nexprlist ::= expr */
- 0, /* (235) paren_exprlist ::= */
- -3, /* (236) paren_exprlist ::= LP exprlist RP */
- -12, /* (237) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
- -1, /* (238) uniqueflag ::= UNIQUE */
- 0, /* (239) uniqueflag ::= */
- 0, /* (240) eidlist_opt ::= */
- -3, /* (241) eidlist_opt ::= LP eidlist RP */
- -5, /* (242) eidlist ::= eidlist COMMA nm collate sortorder */
- -3, /* (243) eidlist ::= nm collate sortorder */
- 0, /* (244) collate ::= */
- -2, /* (245) collate ::= COLLATE ID|STRING */
- -4, /* (246) cmd ::= DROP INDEX ifexists fullname */
- -2, /* (247) cmd ::= VACUUM vinto */
- -3, /* (248) cmd ::= VACUUM nm vinto */
- -2, /* (249) vinto ::= INTO expr */
- 0, /* (250) vinto ::= */
- -3, /* (251) cmd ::= PRAGMA nm dbnm */
- -5, /* (252) cmd ::= PRAGMA nm dbnm EQ nmnum */
- -6, /* (253) cmd ::= PRAGMA nm dbnm LP nmnum RP */
- -5, /* (254) cmd ::= PRAGMA nm dbnm EQ minus_num */
- -6, /* (255) cmd ::= PRAGMA nm dbnm LP minus_num RP */
- -2, /* (256) plus_num ::= PLUS INTEGER|FLOAT */
- -2, /* (257) minus_num ::= MINUS INTEGER|FLOAT */
- -5, /* (258) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
- -11, /* (259) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
- -1, /* (260) trigger_time ::= BEFORE|AFTER */
- -2, /* (261) trigger_time ::= INSTEAD OF */
- 0, /* (262) trigger_time ::= */
- -1, /* (263) trigger_event ::= DELETE|INSERT */
- -1, /* (264) trigger_event ::= UPDATE */
- -3, /* (265) trigger_event ::= UPDATE OF idlist */
- 0, /* (266) when_clause ::= */
- -2, /* (267) when_clause ::= WHEN expr */
- -3, /* (268) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
- -2, /* (269) trigger_cmd_list ::= trigger_cmd SEMI */
- -3, /* (270) trnm ::= nm DOT nm */
- -3, /* (271) tridxby ::= INDEXED BY nm */
- -2, /* (272) tridxby ::= NOT INDEXED */
- -9, /* (273) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
- -8, /* (274) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
- -6, /* (275) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
- -3, /* (276) trigger_cmd ::= scanpt select scanpt */
- -4, /* (277) expr ::= RAISE LP IGNORE RP */
- -6, /* (278) expr ::= RAISE LP raisetype COMMA nm RP */
- -1, /* (279) raisetype ::= ROLLBACK */
- -1, /* (280) raisetype ::= ABORT */
- -1, /* (281) raisetype ::= FAIL */
- -4, /* (282) cmd ::= DROP TRIGGER ifexists fullname */
- -6, /* (283) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
- -3, /* (284) cmd ::= DETACH database_kw_opt expr */
- 0, /* (285) key_opt ::= */
- -2, /* (286) key_opt ::= KEY expr */
- -1, /* (287) cmd ::= REINDEX */
- -3, /* (288) cmd ::= REINDEX nm dbnm */
- -1, /* (289) cmd ::= ANALYZE */
- -3, /* (290) cmd ::= ANALYZE nm dbnm */
- -6, /* (291) cmd ::= ALTER TABLE fullname RENAME TO nm */
- -7, /* (292) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
- -6, /* (293) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
- -1, /* (294) add_column_fullname ::= fullname */
- -8, /* (295) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
- -1, /* (296) cmd ::= create_vtab */
- -4, /* (297) cmd ::= create_vtab LP vtabarglist RP */
- -8, /* (298) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
- 0, /* (299) vtabarg ::= */
- -1, /* (300) vtabargtoken ::= ANY */
- -3, /* (301) vtabargtoken ::= lp anylist RP */
- -1, /* (302) lp ::= LP */
- -2, /* (303) with ::= WITH wqlist */
- -3, /* (304) with ::= WITH RECURSIVE wqlist */
- -1, /* (305) wqas ::= AS */
- -2, /* (306) wqas ::= AS MATERIALIZED */
- -3, /* (307) wqas ::= AS NOT MATERIALIZED */
- -6, /* (308) wqitem ::= nm eidlist_opt wqas LP select RP */
- -1, /* (309) wqlist ::= wqitem */
- -3, /* (310) wqlist ::= wqlist COMMA wqitem */
- -1, /* (311) windowdefn_list ::= windowdefn */
- -3, /* (312) windowdefn_list ::= windowdefn_list COMMA windowdefn */
- -5, /* (313) windowdefn ::= nm AS LP window RP */
- -5, /* (314) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
- -6, /* (315) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
- -4, /* (316) window ::= ORDER BY sortlist frame_opt */
- -5, /* (317) window ::= nm ORDER BY sortlist frame_opt */
- -1, /* (318) window ::= frame_opt */
- -2, /* (319) window ::= nm frame_opt */
- 0, /* (320) frame_opt ::= */
- -3, /* (321) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
- -6, /* (322) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
- -1, /* (323) range_or_rows ::= RANGE|ROWS|GROUPS */
- -1, /* (324) frame_bound_s ::= frame_bound */
- -2, /* (325) frame_bound_s ::= UNBOUNDED PRECEDING */
- -1, /* (326) frame_bound_e ::= frame_bound */
- -2, /* (327) frame_bound_e ::= UNBOUNDED FOLLOWING */
- -2, /* (328) frame_bound ::= expr PRECEDING|FOLLOWING */
- -2, /* (329) frame_bound ::= CURRENT ROW */
- 0, /* (330) frame_exclude_opt ::= */
- -2, /* (331) frame_exclude_opt ::= EXCLUDE frame_exclude */
- -2, /* (332) frame_exclude ::= NO OTHERS */
- -2, /* (333) frame_exclude ::= CURRENT ROW */
- -1, /* (334) frame_exclude ::= GROUP|TIES */
- -2, /* (335) window_clause ::= WINDOW windowdefn_list */
- -2, /* (336) filter_over ::= filter_clause over_clause */
- -1, /* (337) filter_over ::= over_clause */
- -1, /* (338) filter_over ::= filter_clause */
- -4, /* (339) over_clause ::= OVER LP window RP */
- -2, /* (340) over_clause ::= OVER nm */
- -5, /* (341) filter_clause ::= FILTER LP WHERE expr RP */
- -1, /* (342) input ::= cmdlist */
- -2, /* (343) cmdlist ::= cmdlist ecmd */
- -1, /* (344) cmdlist ::= ecmd */
- -1, /* (345) ecmd ::= SEMI */
- -2, /* (346) ecmd ::= cmdx SEMI */
- -3, /* (347) ecmd ::= explain cmdx SEMI */
- 0, /* (348) trans_opt ::= */
- -1, /* (349) trans_opt ::= TRANSACTION */
- -2, /* (350) trans_opt ::= TRANSACTION nm */
- -1, /* (351) savepoint_opt ::= SAVEPOINT */
- 0, /* (352) savepoint_opt ::= */
- -2, /* (353) cmd ::= create_table create_table_args */
- -1, /* (354) table_option_set ::= table_option */
- -4, /* (355) columnlist ::= columnlist COMMA columnname carglist */
- -2, /* (356) columnlist ::= columnname carglist */
- -1, /* (357) nm ::= ID|INDEXED */
- -1, /* (358) nm ::= STRING */
- -1, /* (359) nm ::= JOIN_KW */
- -1, /* (360) typetoken ::= typename */
- -1, /* (361) typename ::= ID|STRING */
- -1, /* (362) signed ::= plus_num */
- -1, /* (363) signed ::= minus_num */
- -2, /* (364) carglist ::= carglist ccons */
- 0, /* (365) carglist ::= */
- -2, /* (366) ccons ::= NULL onconf */
- -4, /* (367) ccons ::= GENERATED ALWAYS AS generated */
- -2, /* (368) ccons ::= AS generated */
- -2, /* (369) conslist_opt ::= COMMA conslist */
- -3, /* (370) conslist ::= conslist tconscomma tcons */
- -1, /* (371) conslist ::= tcons */
- 0, /* (372) tconscomma ::= */
- -1, /* (373) defer_subclause_opt ::= defer_subclause */
- -1, /* (374) resolvetype ::= raisetype */
- -1, /* (375) selectnowith ::= oneselect */
- -1, /* (376) oneselect ::= values */
- -2, /* (377) sclp ::= selcollist COMMA */
- -1, /* (378) as ::= ID|STRING */
- -1, /* (379) indexed_opt ::= indexed_by */
- 0, /* (380) returning ::= */
- -1, /* (381) expr ::= term */
- -1, /* (382) likeop ::= LIKE_KW|MATCH */
- -1, /* (383) exprlist ::= nexprlist */
- -1, /* (384) nmnum ::= plus_num */
- -1, /* (385) nmnum ::= nm */
- -1, /* (386) nmnum ::= ON */
- -1, /* (387) nmnum ::= DELETE */
- -1, /* (388) nmnum ::= DEFAULT */
- -1, /* (389) plus_num ::= INTEGER|FLOAT */
- 0, /* (390) foreach_clause ::= */
- -3, /* (391) foreach_clause ::= FOR EACH ROW */
- -1, /* (392) trnm ::= nm */
- 0, /* (393) tridxby ::= */
- -1, /* (394) database_kw_opt ::= DATABASE */
- 0, /* (395) database_kw_opt ::= */
- 0, /* (396) kwcolumn_opt ::= */
- -1, /* (397) kwcolumn_opt ::= COLUMNKW */
- -1, /* (398) vtabarglist ::= vtabarg */
- -3, /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */
- -2, /* (400) vtabarg ::= vtabarg vtabargtoken */
- 0, /* (401) anylist ::= */
- -4, /* (402) anylist ::= anylist LP anylist RP */
- -2, /* (403) anylist ::= anylist ANY */
- 0, /* (404) with ::= */
+ -1, /* (178) expr ::= ID|INDEXED|JOIN_KW */
+ -3, /* (179) expr ::= nm DOT nm */
+ -5, /* (180) expr ::= nm DOT nm DOT nm */
+ -1, /* (181) term ::= NULL|FLOAT|BLOB */
+ -1, /* (182) term ::= STRING */
+ -1, /* (183) term ::= INTEGER */
+ -1, /* (184) expr ::= VARIABLE */
+ -3, /* (185) expr ::= expr COLLATE ID|STRING */
+ -6, /* (186) expr ::= CAST LP expr AS typetoken RP */
+ -5, /* (187) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
+ -4, /* (188) expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
+ -6, /* (189) expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
+ -5, /* (190) expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
+ -1, /* (191) term ::= CTIME_KW */
+ -5, /* (192) expr ::= LP nexprlist COMMA expr RP */
+ -3, /* (193) expr ::= expr AND expr */
+ -3, /* (194) expr ::= expr OR expr */
+ -3, /* (195) expr ::= expr LT|GT|GE|LE expr */
+ -3, /* (196) expr ::= expr EQ|NE expr */
+ -3, /* (197) expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */
+ -3, /* (198) expr ::= expr PLUS|MINUS expr */
+ -3, /* (199) expr ::= expr STAR|SLASH|REM expr */
+ -3, /* (200) expr ::= expr CONCAT expr */
+ -2, /* (201) likeop ::= NOT LIKE_KW|MATCH */
+ -3, /* (202) expr ::= expr likeop expr */
+ -5, /* (203) expr ::= expr likeop expr ESCAPE expr */
+ -2, /* (204) expr ::= expr ISNULL|NOTNULL */
+ -3, /* (205) expr ::= expr NOT NULL */
+ -3, /* (206) expr ::= expr IS expr */
+ -4, /* (207) expr ::= expr IS NOT expr */
+ -6, /* (208) expr ::= expr IS NOT DISTINCT FROM expr */
+ -5, /* (209) expr ::= expr IS DISTINCT FROM expr */
+ -2, /* (210) expr ::= NOT expr */
+ -2, /* (211) expr ::= BITNOT expr */
+ -2, /* (212) expr ::= PLUS|MINUS expr */
+ -3, /* (213) expr ::= expr PTR expr */
+ -1, /* (214) between_op ::= BETWEEN */
+ -2, /* (215) between_op ::= NOT BETWEEN */
+ -5, /* (216) expr ::= expr between_op expr AND expr */
+ -1, /* (217) in_op ::= IN */
+ -2, /* (218) in_op ::= NOT IN */
+ -5, /* (219) expr ::= expr in_op LP exprlist RP */
+ -3, /* (220) expr ::= LP select RP */
+ -5, /* (221) expr ::= expr in_op LP select RP */
+ -5, /* (222) expr ::= expr in_op nm dbnm paren_exprlist */
+ -4, /* (223) expr ::= EXISTS LP select RP */
+ -5, /* (224) expr ::= CASE case_operand case_exprlist case_else END */
+ -5, /* (225) case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ -4, /* (226) case_exprlist ::= WHEN expr THEN expr */
+ -2, /* (227) case_else ::= ELSE expr */
+ 0, /* (228) case_else ::= */
+ 0, /* (229) case_operand ::= */
+ 0, /* (230) exprlist ::= */
+ -3, /* (231) nexprlist ::= nexprlist COMMA expr */
+ -1, /* (232) nexprlist ::= expr */
+ 0, /* (233) paren_exprlist ::= */
+ -3, /* (234) paren_exprlist ::= LP exprlist RP */
+ -12, /* (235) cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ -1, /* (236) uniqueflag ::= UNIQUE */
+ 0, /* (237) uniqueflag ::= */
+ 0, /* (238) eidlist_opt ::= */
+ -3, /* (239) eidlist_opt ::= LP eidlist RP */
+ -5, /* (240) eidlist ::= eidlist COMMA nm collate sortorder */
+ -3, /* (241) eidlist ::= nm collate sortorder */
+ 0, /* (242) collate ::= */
+ -2, /* (243) collate ::= COLLATE ID|STRING */
+ -4, /* (244) cmd ::= DROP INDEX ifexists fullname */
+ -2, /* (245) cmd ::= VACUUM vinto */
+ -3, /* (246) cmd ::= VACUUM nm vinto */
+ -2, /* (247) vinto ::= INTO expr */
+ 0, /* (248) vinto ::= */
+ -3, /* (249) cmd ::= PRAGMA nm dbnm */
+ -5, /* (250) cmd ::= PRAGMA nm dbnm EQ nmnum */
+ -6, /* (251) cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ -5, /* (252) cmd ::= PRAGMA nm dbnm EQ minus_num */
+ -6, /* (253) cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ -2, /* (254) plus_num ::= PLUS INTEGER|FLOAT */
+ -2, /* (255) minus_num ::= MINUS INTEGER|FLOAT */
+ -5, /* (256) cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ -11, /* (257) trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ -1, /* (258) trigger_time ::= BEFORE|AFTER */
+ -2, /* (259) trigger_time ::= INSTEAD OF */
+ 0, /* (260) trigger_time ::= */
+ -1, /* (261) trigger_event ::= DELETE|INSERT */
+ -1, /* (262) trigger_event ::= UPDATE */
+ -3, /* (263) trigger_event ::= UPDATE OF idlist */
+ 0, /* (264) when_clause ::= */
+ -2, /* (265) when_clause ::= WHEN expr */
+ -3, /* (266) trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ -2, /* (267) trigger_cmd_list ::= trigger_cmd SEMI */
+ -3, /* (268) trnm ::= nm DOT nm */
+ -3, /* (269) tridxby ::= INDEXED BY nm */
+ -2, /* (270) tridxby ::= NOT INDEXED */
+ -9, /* (271) trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+ -8, /* (272) trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ -6, /* (273) trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+ -3, /* (274) trigger_cmd ::= scanpt select scanpt */
+ -4, /* (275) expr ::= RAISE LP IGNORE RP */
+ -6, /* (276) expr ::= RAISE LP raisetype COMMA nm RP */
+ -1, /* (277) raisetype ::= ROLLBACK */
+ -1, /* (278) raisetype ::= ABORT */
+ -1, /* (279) raisetype ::= FAIL */
+ -4, /* (280) cmd ::= DROP TRIGGER ifexists fullname */
+ -6, /* (281) cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ -3, /* (282) cmd ::= DETACH database_kw_opt expr */
+ 0, /* (283) key_opt ::= */
+ -2, /* (284) key_opt ::= KEY expr */
+ -1, /* (285) cmd ::= REINDEX */
+ -3, /* (286) cmd ::= REINDEX nm dbnm */
+ -1, /* (287) cmd ::= ANALYZE */
+ -3, /* (288) cmd ::= ANALYZE nm dbnm */
+ -6, /* (289) cmd ::= ALTER TABLE fullname RENAME TO nm */
+ -7, /* (290) cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ -6, /* (291) cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
+ -1, /* (292) add_column_fullname ::= fullname */
+ -8, /* (293) cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ -1, /* (294) cmd ::= create_vtab */
+ -4, /* (295) cmd ::= create_vtab LP vtabarglist RP */
+ -8, /* (296) create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ 0, /* (297) vtabarg ::= */
+ -1, /* (298) vtabargtoken ::= ANY */
+ -3, /* (299) vtabargtoken ::= lp anylist RP */
+ -1, /* (300) lp ::= LP */
+ -2, /* (301) with ::= WITH wqlist */
+ -3, /* (302) with ::= WITH RECURSIVE wqlist */
+ -1, /* (303) wqas ::= AS */
+ -2, /* (304) wqas ::= AS MATERIALIZED */
+ -3, /* (305) wqas ::= AS NOT MATERIALIZED */
+ -6, /* (306) wqitem ::= nm eidlist_opt wqas LP select RP */
+ -1, /* (307) wqlist ::= wqitem */
+ -3, /* (308) wqlist ::= wqlist COMMA wqitem */
+ -1, /* (309) windowdefn_list ::= windowdefn */
+ -3, /* (310) windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ -5, /* (311) windowdefn ::= nm AS LP window RP */
+ -5, /* (312) window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ -6, /* (313) window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ -4, /* (314) window ::= ORDER BY sortlist frame_opt */
+ -5, /* (315) window ::= nm ORDER BY sortlist frame_opt */
+ -1, /* (316) window ::= frame_opt */
+ -2, /* (317) window ::= nm frame_opt */
+ 0, /* (318) frame_opt ::= */
+ -3, /* (319) frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ -6, /* (320) frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ -1, /* (321) range_or_rows ::= RANGE|ROWS|GROUPS */
+ -1, /* (322) frame_bound_s ::= frame_bound */
+ -2, /* (323) frame_bound_s ::= UNBOUNDED PRECEDING */
+ -1, /* (324) frame_bound_e ::= frame_bound */
+ -2, /* (325) frame_bound_e ::= UNBOUNDED FOLLOWING */
+ -2, /* (326) frame_bound ::= expr PRECEDING|FOLLOWING */
+ -2, /* (327) frame_bound ::= CURRENT ROW */
+ 0, /* (328) frame_exclude_opt ::= */
+ -2, /* (329) frame_exclude_opt ::= EXCLUDE frame_exclude */
+ -2, /* (330) frame_exclude ::= NO OTHERS */
+ -2, /* (331) frame_exclude ::= CURRENT ROW */
+ -1, /* (332) frame_exclude ::= GROUP|TIES */
+ -2, /* (333) window_clause ::= WINDOW windowdefn_list */
+ -2, /* (334) filter_over ::= filter_clause over_clause */
+ -1, /* (335) filter_over ::= over_clause */
+ -1, /* (336) filter_over ::= filter_clause */
+ -4, /* (337) over_clause ::= OVER LP window RP */
+ -2, /* (338) over_clause ::= OVER nm */
+ -5, /* (339) filter_clause ::= FILTER LP WHERE expr RP */
+ -1, /* (340) input ::= cmdlist */
+ -2, /* (341) cmdlist ::= cmdlist ecmd */
+ -1, /* (342) cmdlist ::= ecmd */
+ -1, /* (343) ecmd ::= SEMI */
+ -2, /* (344) ecmd ::= cmdx SEMI */
+ -3, /* (345) ecmd ::= explain cmdx SEMI */
+ 0, /* (346) trans_opt ::= */
+ -1, /* (347) trans_opt ::= TRANSACTION */
+ -2, /* (348) trans_opt ::= TRANSACTION nm */
+ -1, /* (349) savepoint_opt ::= SAVEPOINT */
+ 0, /* (350) savepoint_opt ::= */
+ -2, /* (351) cmd ::= create_table create_table_args */
+ -1, /* (352) table_option_set ::= table_option */
+ -4, /* (353) columnlist ::= columnlist COMMA columnname carglist */
+ -2, /* (354) columnlist ::= columnname carglist */
+ -1, /* (355) nm ::= ID|INDEXED|JOIN_KW */
+ -1, /* (356) nm ::= STRING */
+ -1, /* (357) typetoken ::= typename */
+ -1, /* (358) typename ::= ID|STRING */
+ -1, /* (359) signed ::= plus_num */
+ -1, /* (360) signed ::= minus_num */
+ -2, /* (361) carglist ::= carglist ccons */
+ 0, /* (362) carglist ::= */
+ -2, /* (363) ccons ::= NULL onconf */
+ -4, /* (364) ccons ::= GENERATED ALWAYS AS generated */
+ -2, /* (365) ccons ::= AS generated */
+ -2, /* (366) conslist_opt ::= COMMA conslist */
+ -3, /* (367) conslist ::= conslist tconscomma tcons */
+ -1, /* (368) conslist ::= tcons */
+ 0, /* (369) tconscomma ::= */
+ -1, /* (370) defer_subclause_opt ::= defer_subclause */
+ -1, /* (371) resolvetype ::= raisetype */
+ -1, /* (372) selectnowith ::= oneselect */
+ -1, /* (373) oneselect ::= values */
+ -2, /* (374) sclp ::= selcollist COMMA */
+ -1, /* (375) as ::= ID|STRING */
+ -1, /* (376) indexed_opt ::= indexed_by */
+ 0, /* (377) returning ::= */
+ -1, /* (378) expr ::= term */
+ -1, /* (379) likeop ::= LIKE_KW|MATCH */
+ -1, /* (380) case_operand ::= expr */
+ -1, /* (381) exprlist ::= nexprlist */
+ -1, /* (382) nmnum ::= plus_num */
+ -1, /* (383) nmnum ::= nm */
+ -1, /* (384) nmnum ::= ON */
+ -1, /* (385) nmnum ::= DELETE */
+ -1, /* (386) nmnum ::= DEFAULT */
+ -1, /* (387) plus_num ::= INTEGER|FLOAT */
+ 0, /* (388) foreach_clause ::= */
+ -3, /* (389) foreach_clause ::= FOR EACH ROW */
+ -1, /* (390) trnm ::= nm */
+ 0, /* (391) tridxby ::= */
+ -1, /* (392) database_kw_opt ::= DATABASE */
+ 0, /* (393) database_kw_opt ::= */
+ 0, /* (394) kwcolumn_opt ::= */
+ -1, /* (395) kwcolumn_opt ::= COLUMNKW */
+ -1, /* (396) vtabarglist ::= vtabarg */
+ -3, /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */
+ -2, /* (398) vtabarg ::= vtabarg vtabargtoken */
+ 0, /* (399) anylist ::= */
+ -4, /* (400) anylist ::= anylist LP anylist RP */
+ -2, /* (401) anylist ::= anylist ANY */
+ 0, /* (402) with ::= */
};
static void yy_accept(yyParser*); /* Forward Declaration */
@@ -170325,7 +171315,7 @@ static YYACTIONTYPE yy_reduce(
case 5: /* transtype ::= DEFERRED */
case 6: /* transtype ::= IMMEDIATE */ yytestcase(yyruleno==6);
case 7: /* transtype ::= EXCLUSIVE */ yytestcase(yyruleno==7);
- case 323: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==323);
+ case 321: /* range_or_rows ::= RANGE|ROWS|GROUPS */ yytestcase(yyruleno==321);
{yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/}
break;
case 8: /* cmd ::= COMMIT|END trans_opt */
@@ -170362,7 +171352,7 @@ static YYACTIONTYPE yy_reduce(
case 72: /* defer_subclause_opt ::= */ yytestcase(yyruleno==72);
case 81: /* ifexists ::= */ yytestcase(yyruleno==81);
case 98: /* distinct ::= */ yytestcase(yyruleno==98);
- case 244: /* collate ::= */ yytestcase(yyruleno==244);
+ case 242: /* collate ::= */ yytestcase(yyruleno==242);
{yymsp[1].minor.yy394 = 0;}
break;
case 16: /* ifnotexists ::= IF NOT EXISTS */
@@ -170546,9 +171536,9 @@ static YYACTIONTYPE yy_reduce(
break;
case 63: /* init_deferred_pred_opt ::= INITIALLY DEFERRED */
case 80: /* ifexists ::= IF EXISTS */ yytestcase(yyruleno==80);
- case 216: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==216);
- case 219: /* in_op ::= NOT IN */ yytestcase(yyruleno==219);
- case 245: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==245);
+ case 215: /* between_op ::= NOT BETWEEN */ yytestcase(yyruleno==215);
+ case 218: /* in_op ::= NOT IN */ yytestcase(yyruleno==218);
+ case 243: /* collate ::= COLLATE ID|STRING */ yytestcase(yyruleno==243);
{yymsp[-1].minor.yy394 = 1;}
break;
case 64: /* init_deferred_pred_opt ::= INITIALLY IMMEDIATE */
@@ -170698,9 +171688,9 @@ static YYACTIONTYPE yy_reduce(
case 99: /* sclp ::= */
case 132: /* orderby_opt ::= */ yytestcase(yyruleno==132);
case 142: /* groupby_opt ::= */ yytestcase(yyruleno==142);
- case 232: /* exprlist ::= */ yytestcase(yyruleno==232);
- case 235: /* paren_exprlist ::= */ yytestcase(yyruleno==235);
- case 240: /* eidlist_opt ::= */ yytestcase(yyruleno==240);
+ case 230: /* exprlist ::= */ yytestcase(yyruleno==230);
+ case 233: /* paren_exprlist ::= */ yytestcase(yyruleno==233);
+ case 238: /* eidlist_opt ::= */ yytestcase(yyruleno==238);
{yymsp[1].minor.yy322 = 0;}
break;
case 100: /* selcollist ::= sclp scanpt expr scanpt as */
@@ -170726,8 +171716,8 @@ static YYACTIONTYPE yy_reduce(
break;
case 103: /* as ::= AS nm */
case 115: /* dbnm ::= DOT nm */ yytestcase(yyruleno==115);
- case 256: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==256);
- case 257: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==257);
+ case 254: /* plus_num ::= PLUS INTEGER|FLOAT */ yytestcase(yyruleno==254);
+ case 255: /* minus_num ::= MINUS INTEGER|FLOAT */ yytestcase(yyruleno==255);
{yymsp[-1].minor.yy0 = yymsp[0].minor.yy0;}
break;
case 105: /* from ::= */
@@ -170771,7 +171761,7 @@ static YYACTIONTYPE yy_reduce(
{
if( yymsp[-5].minor.yy131==0 && yymsp[-1].minor.yy0.n==0 && yymsp[0].minor.yy561.pOn==0 && yymsp[0].minor.yy561.pUsing==0 ){
yymsp[-5].minor.yy131 = yymsp[-3].minor.yy131;
- }else if( yymsp[-3].minor.yy131->nSrc==1 ){
+ }else if( ALWAYS(yymsp[-3].minor.yy131!=0) && yymsp[-3].minor.yy131->nSrc==1 ){
yymsp[-5].minor.yy131 = sqlite3SrcListAppendFromTerm(pParse,yymsp[-5].minor.yy131,0,0,&yymsp[-1].minor.yy0,0,&yymsp[0].minor.yy561);
if( yymsp[-5].minor.yy131 ){
SrcItem *pNew = &yymsp[-5].minor.yy131->a[yymsp[-5].minor.yy131->nSrc-1];
@@ -170899,16 +171889,16 @@ static YYACTIONTYPE yy_reduce(
case 146: /* limit_opt ::= */ yytestcase(yyruleno==146);
case 151: /* where_opt ::= */ yytestcase(yyruleno==151);
case 153: /* where_opt_ret ::= */ yytestcase(yyruleno==153);
- case 229: /* case_else ::= */ yytestcase(yyruleno==229);
- case 231: /* case_operand ::= */ yytestcase(yyruleno==231);
- case 250: /* vinto ::= */ yytestcase(yyruleno==250);
+ case 228: /* case_else ::= */ yytestcase(yyruleno==228);
+ case 229: /* case_operand ::= */ yytestcase(yyruleno==229);
+ case 248: /* vinto ::= */ yytestcase(yyruleno==248);
{yymsp[1].minor.yy528 = 0;}
break;
case 145: /* having_opt ::= HAVING expr */
case 152: /* where_opt ::= WHERE expr */ yytestcase(yyruleno==152);
case 154: /* where_opt_ret ::= WHERE expr */ yytestcase(yyruleno==154);
- case 228: /* case_else ::= ELSE expr */ yytestcase(yyruleno==228);
- case 249: /* vinto ::= INTO expr */ yytestcase(yyruleno==249);
+ case 227: /* case_else ::= ELSE expr */ yytestcase(yyruleno==227);
+ case 247: /* vinto ::= INTO expr */ yytestcase(yyruleno==247);
{yymsp[-1].minor.yy528 = yymsp[0].minor.yy528;}
break;
case 147: /* limit_opt ::= LIMIT expr */
@@ -171020,11 +172010,10 @@ static YYACTIONTYPE yy_reduce(
case 177: /* expr ::= LP expr RP */
{yymsp[-2].minor.yy528 = yymsp[-1].minor.yy528;}
break;
- case 178: /* expr ::= ID|INDEXED */
- case 179: /* expr ::= JOIN_KW */ yytestcase(yyruleno==179);
+ case 178: /* expr ::= ID|INDEXED|JOIN_KW */
{yymsp[0].minor.yy528=tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
- case 180: /* expr ::= nm DOT nm */
+ case 179: /* expr ::= nm DOT nm */
{
Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0);
Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[0].minor.yy0);
@@ -171032,7 +172021,7 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[-2].minor.yy528 = yylhsminor.yy528;
break;
- case 181: /* expr ::= nm DOT nm DOT nm */
+ case 180: /* expr ::= nm DOT nm DOT nm */
{
Expr *temp1 = tokenExpr(pParse,TK_ID,yymsp[-4].minor.yy0);
Expr *temp2 = tokenExpr(pParse,TK_ID,yymsp[-2].minor.yy0);
@@ -171045,18 +172034,18 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[-4].minor.yy528 = yylhsminor.yy528;
break;
- case 182: /* term ::= NULL|FLOAT|BLOB */
- case 183: /* term ::= STRING */ yytestcase(yyruleno==183);
+ case 181: /* term ::= NULL|FLOAT|BLOB */
+ case 182: /* term ::= STRING */ yytestcase(yyruleno==182);
{yymsp[0].minor.yy528=tokenExpr(pParse,yymsp[0].major,yymsp[0].minor.yy0); /*A-overwrites-X*/}
break;
- case 184: /* term ::= INTEGER */
+ case 183: /* term ::= INTEGER */
{
yylhsminor.yy528 = sqlite3ExprAlloc(pParse->db, TK_INTEGER, &yymsp[0].minor.yy0, 1);
if( yylhsminor.yy528 ) yylhsminor.yy528->w.iOfst = (int)(yymsp[0].minor.yy0.z - pParse->zTail);
}
yymsp[0].minor.yy528 = yylhsminor.yy528;
break;
- case 185: /* expr ::= VARIABLE */
+ case 184: /* expr ::= VARIABLE */
{
if( !(yymsp[0].minor.yy0.z[0]=='#' && sqlite3Isdigit(yymsp[0].minor.yy0.z[1])) ){
u32 n = yymsp[0].minor.yy0.n;
@@ -171078,50 +172067,50 @@ static YYACTIONTYPE yy_reduce(
}
}
break;
- case 186: /* expr ::= expr COLLATE ID|STRING */
+ case 185: /* expr ::= expr COLLATE ID|STRING */
{
yymsp[-2].minor.yy528 = sqlite3ExprAddCollateToken(pParse, yymsp[-2].minor.yy528, &yymsp[0].minor.yy0, 1);
}
break;
- case 187: /* expr ::= CAST LP expr AS typetoken RP */
+ case 186: /* expr ::= CAST LP expr AS typetoken RP */
{
yymsp[-5].minor.yy528 = sqlite3ExprAlloc(pParse->db, TK_CAST, &yymsp[-1].minor.yy0, 1);
sqlite3ExprAttachSubtrees(pParse->db, yymsp[-5].minor.yy528, yymsp[-3].minor.yy528, 0);
}
break;
- case 188: /* expr ::= ID|INDEXED LP distinct exprlist RP */
+ case 187: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP */
{
yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0, yymsp[-2].minor.yy394);
}
yymsp[-4].minor.yy528 = yylhsminor.yy528;
break;
- case 189: /* expr ::= ID|INDEXED LP STAR RP */
+ case 188: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP */
{
yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-3].minor.yy0, 0);
}
yymsp[-3].minor.yy528 = yylhsminor.yy528;
break;
- case 190: /* expr ::= ID|INDEXED LP distinct exprlist RP filter_over */
+ case 189: /* expr ::= ID|INDEXED|JOIN_KW LP distinct exprlist RP filter_over */
{
yylhsminor.yy528 = sqlite3ExprFunction(pParse, yymsp[-2].minor.yy322, &yymsp[-5].minor.yy0, yymsp[-3].minor.yy394);
sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41);
}
yymsp[-5].minor.yy528 = yylhsminor.yy528;
break;
- case 191: /* expr ::= ID|INDEXED LP STAR RP filter_over */
+ case 190: /* expr ::= ID|INDEXED|JOIN_KW LP STAR RP filter_over */
{
yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[-4].minor.yy0, 0);
sqlite3WindowAttach(pParse, yylhsminor.yy528, yymsp[0].minor.yy41);
}
yymsp[-4].minor.yy528 = yylhsminor.yy528;
break;
- case 192: /* term ::= CTIME_KW */
+ case 191: /* term ::= CTIME_KW */
{
yylhsminor.yy528 = sqlite3ExprFunction(pParse, 0, &yymsp[0].minor.yy0, 0);
}
yymsp[0].minor.yy528 = yylhsminor.yy528;
break;
- case 193: /* expr ::= LP nexprlist COMMA expr RP */
+ case 192: /* expr ::= LP nexprlist COMMA expr RP */
{
ExprList *pList = sqlite3ExprListAppend(pParse, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528);
yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_VECTOR, 0, 0);
@@ -171135,22 +172124,22 @@ static YYACTIONTYPE yy_reduce(
}
}
break;
- case 194: /* expr ::= expr AND expr */
+ case 193: /* expr ::= expr AND expr */
{yymsp[-2].minor.yy528=sqlite3ExprAnd(pParse,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);}
break;
- case 195: /* expr ::= expr OR expr */
- case 196: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==196);
- case 197: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==197);
- case 198: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==198);
- case 199: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==199);
- case 200: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==200);
- case 201: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==201);
+ case 194: /* expr ::= expr OR expr */
+ case 195: /* expr ::= expr LT|GT|GE|LE expr */ yytestcase(yyruleno==195);
+ case 196: /* expr ::= expr EQ|NE expr */ yytestcase(yyruleno==196);
+ case 197: /* expr ::= expr BITAND|BITOR|LSHIFT|RSHIFT expr */ yytestcase(yyruleno==197);
+ case 198: /* expr ::= expr PLUS|MINUS expr */ yytestcase(yyruleno==198);
+ case 199: /* expr ::= expr STAR|SLASH|REM expr */ yytestcase(yyruleno==199);
+ case 200: /* expr ::= expr CONCAT expr */ yytestcase(yyruleno==200);
{yymsp[-2].minor.yy528=sqlite3PExpr(pParse,yymsp[-1].major,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);}
break;
- case 202: /* likeop ::= NOT LIKE_KW|MATCH */
+ case 201: /* likeop ::= NOT LIKE_KW|MATCH */
{yymsp[-1].minor.yy0=yymsp[0].minor.yy0; yymsp[-1].minor.yy0.n|=0x80000000; /*yymsp[-1].minor.yy0-overwrite-yymsp[0].minor.yy0*/}
break;
- case 203: /* expr ::= expr likeop expr */
+ case 202: /* expr ::= expr likeop expr */
{
ExprList *pList;
int bNot = yymsp[-1].minor.yy0.n & 0x80000000;
@@ -171162,7 +172151,7 @@ static YYACTIONTYPE yy_reduce(
if( yymsp[-2].minor.yy528 ) yymsp[-2].minor.yy528->flags |= EP_InfixFunc;
}
break;
- case 204: /* expr ::= expr likeop expr ESCAPE expr */
+ case 203: /* expr ::= expr likeop expr ESCAPE expr */
{
ExprList *pList;
int bNot = yymsp[-3].minor.yy0.n & 0x80000000;
@@ -171175,47 +172164,47 @@ static YYACTIONTYPE yy_reduce(
if( yymsp[-4].minor.yy528 ) yymsp[-4].minor.yy528->flags |= EP_InfixFunc;
}
break;
- case 205: /* expr ::= expr ISNULL|NOTNULL */
+ case 204: /* expr ::= expr ISNULL|NOTNULL */
{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse,yymsp[0].major,yymsp[-1].minor.yy528,0);}
break;
- case 206: /* expr ::= expr NOT NULL */
+ case 205: /* expr ::= expr NOT NULL */
{yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_NOTNULL,yymsp[-2].minor.yy528,0);}
break;
- case 207: /* expr ::= expr IS expr */
+ case 206: /* expr ::= expr IS expr */
{
yymsp[-2].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-2].minor.yy528,yymsp[0].minor.yy528);
binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-2].minor.yy528, TK_ISNULL);
}
break;
- case 208: /* expr ::= expr IS NOT expr */
+ case 207: /* expr ::= expr IS NOT expr */
{
yymsp[-3].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-3].minor.yy528,yymsp[0].minor.yy528);
binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-3].minor.yy528, TK_NOTNULL);
}
break;
- case 209: /* expr ::= expr IS NOT DISTINCT FROM expr */
+ case 208: /* expr ::= expr IS NOT DISTINCT FROM expr */
{
yymsp[-5].minor.yy528 = sqlite3PExpr(pParse,TK_IS,yymsp[-5].minor.yy528,yymsp[0].minor.yy528);
binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-5].minor.yy528, TK_ISNULL);
}
break;
- case 210: /* expr ::= expr IS DISTINCT FROM expr */
+ case 209: /* expr ::= expr IS DISTINCT FROM expr */
{
yymsp[-4].minor.yy528 = sqlite3PExpr(pParse,TK_ISNOT,yymsp[-4].minor.yy528,yymsp[0].minor.yy528);
binaryToUnaryIfNull(pParse, yymsp[0].minor.yy528, yymsp[-4].minor.yy528, TK_NOTNULL);
}
break;
- case 211: /* expr ::= NOT expr */
- case 212: /* expr ::= BITNOT expr */ yytestcase(yyruleno==212);
+ case 210: /* expr ::= NOT expr */
+ case 211: /* expr ::= BITNOT expr */ yytestcase(yyruleno==211);
{yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major, yymsp[0].minor.yy528, 0);/*A-overwrites-B*/}
break;
- case 213: /* expr ::= PLUS|MINUS expr */
+ case 212: /* expr ::= PLUS|MINUS expr */
{
yymsp[-1].minor.yy528 = sqlite3PExpr(pParse, yymsp[-1].major==TK_PLUS ? TK_UPLUS : TK_UMINUS, yymsp[0].minor.yy528, 0);
/*A-overwrites-B*/
}
break;
- case 214: /* expr ::= expr PTR expr */
+ case 213: /* expr ::= expr PTR expr */
{
ExprList *pList = sqlite3ExprListAppend(pParse, 0, yymsp[-2].minor.yy528);
pList = sqlite3ExprListAppend(pParse, pList, yymsp[0].minor.yy528);
@@ -171223,11 +172212,11 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[-2].minor.yy528 = yylhsminor.yy528;
break;
- case 215: /* between_op ::= BETWEEN */
- case 218: /* in_op ::= IN */ yytestcase(yyruleno==218);
+ case 214: /* between_op ::= BETWEEN */
+ case 217: /* in_op ::= IN */ yytestcase(yyruleno==217);
{yymsp[0].minor.yy394 = 0;}
break;
- case 217: /* expr ::= expr between_op expr AND expr */
+ case 216: /* expr ::= expr between_op expr AND expr */
{
ExprList *pList = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528);
pList = sqlite3ExprListAppend(pParse,pList, yymsp[0].minor.yy528);
@@ -171240,7 +172229,7 @@ static YYACTIONTYPE yy_reduce(
if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
}
break;
- case 220: /* expr ::= expr in_op LP exprlist RP */
+ case 219: /* expr ::= expr in_op LP exprlist RP */
{
if( yymsp[-1].minor.yy322==0 ){
/* Expressions of the form
@@ -171286,20 +172275,20 @@ static YYACTIONTYPE yy_reduce(
}
}
break;
- case 221: /* expr ::= LP select RP */
+ case 220: /* expr ::= LP select RP */
{
yymsp[-2].minor.yy528 = sqlite3PExpr(pParse, TK_SELECT, 0, 0);
sqlite3PExprAddSelect(pParse, yymsp[-2].minor.yy528, yymsp[-1].minor.yy47);
}
break;
- case 222: /* expr ::= expr in_op LP select RP */
+ case 221: /* expr ::= expr in_op LP select RP */
{
yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_IN, yymsp[-4].minor.yy528, 0);
sqlite3PExprAddSelect(pParse, yymsp[-4].minor.yy528, yymsp[-1].minor.yy47);
if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
}
break;
- case 223: /* expr ::= expr in_op nm dbnm paren_exprlist */
+ case 222: /* expr ::= expr in_op nm dbnm paren_exprlist */
{
SrcList *pSrc = sqlite3SrcListAppend(pParse, 0,&yymsp[-2].minor.yy0,&yymsp[-1].minor.yy0);
Select *pSelect = sqlite3SelectNew(pParse, 0,pSrc,0,0,0,0,0,0);
@@ -171309,14 +172298,14 @@ static YYACTIONTYPE yy_reduce(
if( yymsp[-3].minor.yy394 ) yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_NOT, yymsp[-4].minor.yy528, 0);
}
break;
- case 224: /* expr ::= EXISTS LP select RP */
+ case 223: /* expr ::= EXISTS LP select RP */
{
Expr *p;
p = yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_EXISTS, 0, 0);
sqlite3PExprAddSelect(pParse, p, yymsp[-1].minor.yy47);
}
break;
- case 225: /* expr ::= CASE case_operand case_exprlist case_else END */
+ case 224: /* expr ::= CASE case_operand case_exprlist case_else END */
{
yymsp[-4].minor.yy528 = sqlite3PExpr(pParse, TK_CASE, yymsp[-3].minor.yy528, 0);
if( yymsp[-4].minor.yy528 ){
@@ -171328,32 +172317,29 @@ static YYACTIONTYPE yy_reduce(
}
}
break;
- case 226: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
+ case 225: /* case_exprlist ::= case_exprlist WHEN expr THEN expr */
{
yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[-2].minor.yy528);
yymsp[-4].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-4].minor.yy322, yymsp[0].minor.yy528);
}
break;
- case 227: /* case_exprlist ::= WHEN expr THEN expr */
+ case 226: /* case_exprlist ::= WHEN expr THEN expr */
{
yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,0, yymsp[-2].minor.yy528);
yymsp[-3].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-3].minor.yy322, yymsp[0].minor.yy528);
}
break;
- case 230: /* case_operand ::= expr */
-{yymsp[0].minor.yy528 = yymsp[0].minor.yy528; /*A-overwrites-X*/}
- break;
- case 233: /* nexprlist ::= nexprlist COMMA expr */
+ case 231: /* nexprlist ::= nexprlist COMMA expr */
{yymsp[-2].minor.yy322 = sqlite3ExprListAppend(pParse,yymsp[-2].minor.yy322,yymsp[0].minor.yy528);}
break;
- case 234: /* nexprlist ::= expr */
+ case 232: /* nexprlist ::= expr */
{yymsp[0].minor.yy322 = sqlite3ExprListAppend(pParse,0,yymsp[0].minor.yy528); /*A-overwrites-Y*/}
break;
- case 236: /* paren_exprlist ::= LP exprlist RP */
- case 241: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==241);
+ case 234: /* paren_exprlist ::= LP exprlist RP */
+ case 239: /* eidlist_opt ::= LP eidlist RP */ yytestcase(yyruleno==239);
{yymsp[-2].minor.yy322 = yymsp[-1].minor.yy322;}
break;
- case 237: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
+ case 235: /* cmd ::= createkw uniqueflag INDEX ifnotexists nm dbnm ON nm LP sortlist RP where_opt */
{
sqlite3CreateIndex(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0,
sqlite3SrcListAppend(pParse,0,&yymsp[-4].minor.yy0,0), yymsp[-2].minor.yy322, yymsp[-10].minor.yy394,
@@ -171363,48 +172349,48 @@ static YYACTIONTYPE yy_reduce(
}
}
break;
- case 238: /* uniqueflag ::= UNIQUE */
- case 280: /* raisetype ::= ABORT */ yytestcase(yyruleno==280);
+ case 236: /* uniqueflag ::= UNIQUE */
+ case 278: /* raisetype ::= ABORT */ yytestcase(yyruleno==278);
{yymsp[0].minor.yy394 = OE_Abort;}
break;
- case 239: /* uniqueflag ::= */
+ case 237: /* uniqueflag ::= */
{yymsp[1].minor.yy394 = OE_None;}
break;
- case 242: /* eidlist ::= eidlist COMMA nm collate sortorder */
+ case 240: /* eidlist ::= eidlist COMMA nm collate sortorder */
{
yymsp[-4].minor.yy322 = parserAddExprIdListTerm(pParse, yymsp[-4].minor.yy322, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394);
}
break;
- case 243: /* eidlist ::= nm collate sortorder */
+ case 241: /* eidlist ::= nm collate sortorder */
{
yymsp[-2].minor.yy322 = parserAddExprIdListTerm(pParse, 0, &yymsp[-2].minor.yy0, yymsp[-1].minor.yy394, yymsp[0].minor.yy394); /*A-overwrites-Y*/
}
break;
- case 246: /* cmd ::= DROP INDEX ifexists fullname */
+ case 244: /* cmd ::= DROP INDEX ifexists fullname */
{sqlite3DropIndex(pParse, yymsp[0].minor.yy131, yymsp[-1].minor.yy394);}
break;
- case 247: /* cmd ::= VACUUM vinto */
+ case 245: /* cmd ::= VACUUM vinto */
{sqlite3Vacuum(pParse,0,yymsp[0].minor.yy528);}
break;
- case 248: /* cmd ::= VACUUM nm vinto */
+ case 246: /* cmd ::= VACUUM nm vinto */
{sqlite3Vacuum(pParse,&yymsp[-1].minor.yy0,yymsp[0].minor.yy528);}
break;
- case 251: /* cmd ::= PRAGMA nm dbnm */
+ case 249: /* cmd ::= PRAGMA nm dbnm */
{sqlite3Pragma(pParse,&yymsp[-1].minor.yy0,&yymsp[0].minor.yy0,0,0);}
break;
- case 252: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
+ case 250: /* cmd ::= PRAGMA nm dbnm EQ nmnum */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,0);}
break;
- case 253: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
+ case 251: /* cmd ::= PRAGMA nm dbnm LP nmnum RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,0);}
break;
- case 254: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
+ case 252: /* cmd ::= PRAGMA nm dbnm EQ minus_num */
{sqlite3Pragma(pParse,&yymsp[-3].minor.yy0,&yymsp[-2].minor.yy0,&yymsp[0].minor.yy0,1);}
break;
- case 255: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
+ case 253: /* cmd ::= PRAGMA nm dbnm LP minus_num RP */
{sqlite3Pragma(pParse,&yymsp[-4].minor.yy0,&yymsp[-3].minor.yy0,&yymsp[-1].minor.yy0,1);}
break;
- case 258: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
+ case 256: /* cmd ::= createkw trigger_decl BEGIN trigger_cmd_list END */
{
Token all;
all.z = yymsp[-3].minor.yy0.z;
@@ -171412,50 +172398,50 @@ static YYACTIONTYPE yy_reduce(
sqlite3FinishTrigger(pParse, yymsp[-1].minor.yy33, &all);
}
break;
- case 259: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
+ case 257: /* trigger_decl ::= temp TRIGGER ifnotexists nm dbnm trigger_time trigger_event ON fullname foreach_clause when_clause */
{
sqlite3BeginTrigger(pParse, &yymsp[-7].minor.yy0, &yymsp[-6].minor.yy0, yymsp[-5].minor.yy394, yymsp[-4].minor.yy180.a, yymsp[-4].minor.yy180.b, yymsp[-2].minor.yy131, yymsp[0].minor.yy528, yymsp[-10].minor.yy394, yymsp[-8].minor.yy394);
yymsp[-10].minor.yy0 = (yymsp[-6].minor.yy0.n==0?yymsp[-7].minor.yy0:yymsp[-6].minor.yy0); /*A-overwrites-T*/
}
break;
- case 260: /* trigger_time ::= BEFORE|AFTER */
+ case 258: /* trigger_time ::= BEFORE|AFTER */
{ yymsp[0].minor.yy394 = yymsp[0].major; /*A-overwrites-X*/ }
break;
- case 261: /* trigger_time ::= INSTEAD OF */
+ case 259: /* trigger_time ::= INSTEAD OF */
{ yymsp[-1].minor.yy394 = TK_INSTEAD;}
break;
- case 262: /* trigger_time ::= */
+ case 260: /* trigger_time ::= */
{ yymsp[1].minor.yy394 = TK_BEFORE; }
break;
- case 263: /* trigger_event ::= DELETE|INSERT */
- case 264: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==264);
+ case 261: /* trigger_event ::= DELETE|INSERT */
+ case 262: /* trigger_event ::= UPDATE */ yytestcase(yyruleno==262);
{yymsp[0].minor.yy180.a = yymsp[0].major; /*A-overwrites-X*/ yymsp[0].minor.yy180.b = 0;}
break;
- case 265: /* trigger_event ::= UPDATE OF idlist */
+ case 263: /* trigger_event ::= UPDATE OF idlist */
{yymsp[-2].minor.yy180.a = TK_UPDATE; yymsp[-2].minor.yy180.b = yymsp[0].minor.yy254;}
break;
- case 266: /* when_clause ::= */
- case 285: /* key_opt ::= */ yytestcase(yyruleno==285);
+ case 264: /* when_clause ::= */
+ case 283: /* key_opt ::= */ yytestcase(yyruleno==283);
{ yymsp[1].minor.yy528 = 0; }
break;
- case 267: /* when_clause ::= WHEN expr */
- case 286: /* key_opt ::= KEY expr */ yytestcase(yyruleno==286);
+ case 265: /* when_clause ::= WHEN expr */
+ case 284: /* key_opt ::= KEY expr */ yytestcase(yyruleno==284);
{ yymsp[-1].minor.yy528 = yymsp[0].minor.yy528; }
break;
- case 268: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
+ case 266: /* trigger_cmd_list ::= trigger_cmd_list trigger_cmd SEMI */
{
assert( yymsp[-2].minor.yy33!=0 );
yymsp[-2].minor.yy33->pLast->pNext = yymsp[-1].minor.yy33;
yymsp[-2].minor.yy33->pLast = yymsp[-1].minor.yy33;
}
break;
- case 269: /* trigger_cmd_list ::= trigger_cmd SEMI */
+ case 267: /* trigger_cmd_list ::= trigger_cmd SEMI */
{
assert( yymsp[-1].minor.yy33!=0 );
yymsp[-1].minor.yy33->pLast = yymsp[-1].minor.yy33;
}
break;
- case 270: /* trnm ::= nm DOT nm */
+ case 268: /* trnm ::= nm DOT nm */
{
yymsp[-2].minor.yy0 = yymsp[0].minor.yy0;
sqlite3ErrorMsg(pParse,
@@ -171463,39 +172449,39 @@ static YYACTIONTYPE yy_reduce(
"statements within triggers");
}
break;
- case 271: /* tridxby ::= INDEXED BY nm */
+ case 269: /* tridxby ::= INDEXED BY nm */
{
sqlite3ErrorMsg(pParse,
"the INDEXED BY clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 272: /* tridxby ::= NOT INDEXED */
+ case 270: /* tridxby ::= NOT INDEXED */
{
sqlite3ErrorMsg(pParse,
"the NOT INDEXED clause is not allowed on UPDATE or DELETE statements "
"within triggers");
}
break;
- case 273: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
+ case 271: /* trigger_cmd ::= UPDATE orconf trnm tridxby SET setlist from where_opt scanpt */
{yylhsminor.yy33 = sqlite3TriggerUpdateStep(pParse, &yymsp[-6].minor.yy0, yymsp[-2].minor.yy131, yymsp[-3].minor.yy322, yymsp[-1].minor.yy528, yymsp[-7].minor.yy394, yymsp[-8].minor.yy0.z, yymsp[0].minor.yy522);}
yymsp[-8].minor.yy33 = yylhsminor.yy33;
break;
- case 274: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
+ case 272: /* trigger_cmd ::= scanpt insert_cmd INTO trnm idlist_opt select upsert scanpt */
{
yylhsminor.yy33 = sqlite3TriggerInsertStep(pParse,&yymsp[-4].minor.yy0,yymsp[-3].minor.yy254,yymsp[-2].minor.yy47,yymsp[-6].minor.yy394,yymsp[-1].minor.yy444,yymsp[-7].minor.yy522,yymsp[0].minor.yy522);/*yylhsminor.yy33-overwrites-yymsp[-6].minor.yy394*/
}
yymsp[-7].minor.yy33 = yylhsminor.yy33;
break;
- case 275: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
+ case 273: /* trigger_cmd ::= DELETE FROM trnm tridxby where_opt scanpt */
{yylhsminor.yy33 = sqlite3TriggerDeleteStep(pParse, &yymsp[-3].minor.yy0, yymsp[-1].minor.yy528, yymsp[-5].minor.yy0.z, yymsp[0].minor.yy522);}
yymsp[-5].minor.yy33 = yylhsminor.yy33;
break;
- case 276: /* trigger_cmd ::= scanpt select scanpt */
+ case 274: /* trigger_cmd ::= scanpt select scanpt */
{yylhsminor.yy33 = sqlite3TriggerSelectStep(pParse->db, yymsp[-1].minor.yy47, yymsp[-2].minor.yy522, yymsp[0].minor.yy522); /*yylhsminor.yy33-overwrites-yymsp[-1].minor.yy47*/}
yymsp[-2].minor.yy33 = yylhsminor.yy33;
break;
- case 277: /* expr ::= RAISE LP IGNORE RP */
+ case 275: /* expr ::= RAISE LP IGNORE RP */
{
yymsp[-3].minor.yy528 = sqlite3PExpr(pParse, TK_RAISE, 0, 0);
if( yymsp[-3].minor.yy528 ){
@@ -171503,7 +172489,7 @@ static YYACTIONTYPE yy_reduce(
}
}
break;
- case 278: /* expr ::= RAISE LP raisetype COMMA nm RP */
+ case 276: /* expr ::= RAISE LP raisetype COMMA nm RP */
{
yymsp[-5].minor.yy528 = sqlite3ExprAlloc(pParse->db, TK_RAISE, &yymsp[-1].minor.yy0, 1);
if( yymsp[-5].minor.yy528 ) {
@@ -171511,118 +172497,118 @@ static YYACTIONTYPE yy_reduce(
}
}
break;
- case 279: /* raisetype ::= ROLLBACK */
+ case 277: /* raisetype ::= ROLLBACK */
{yymsp[0].minor.yy394 = OE_Rollback;}
break;
- case 281: /* raisetype ::= FAIL */
+ case 279: /* raisetype ::= FAIL */
{yymsp[0].minor.yy394 = OE_Fail;}
break;
- case 282: /* cmd ::= DROP TRIGGER ifexists fullname */
+ case 280: /* cmd ::= DROP TRIGGER ifexists fullname */
{
sqlite3DropTrigger(pParse,yymsp[0].minor.yy131,yymsp[-1].minor.yy394);
}
break;
- case 283: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
+ case 281: /* cmd ::= ATTACH database_kw_opt expr AS expr key_opt */
{
sqlite3Attach(pParse, yymsp[-3].minor.yy528, yymsp[-1].minor.yy528, yymsp[0].minor.yy528);
}
break;
- case 284: /* cmd ::= DETACH database_kw_opt expr */
+ case 282: /* cmd ::= DETACH database_kw_opt expr */
{
sqlite3Detach(pParse, yymsp[0].minor.yy528);
}
break;
- case 287: /* cmd ::= REINDEX */
+ case 285: /* cmd ::= REINDEX */
{sqlite3Reindex(pParse, 0, 0);}
break;
- case 288: /* cmd ::= REINDEX nm dbnm */
+ case 286: /* cmd ::= REINDEX nm dbnm */
{sqlite3Reindex(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 289: /* cmd ::= ANALYZE */
+ case 287: /* cmd ::= ANALYZE */
{sqlite3Analyze(pParse, 0, 0);}
break;
- case 290: /* cmd ::= ANALYZE nm dbnm */
+ case 288: /* cmd ::= ANALYZE nm dbnm */
{sqlite3Analyze(pParse, &yymsp[-1].minor.yy0, &yymsp[0].minor.yy0);}
break;
- case 291: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
+ case 289: /* cmd ::= ALTER TABLE fullname RENAME TO nm */
{
sqlite3AlterRenameTable(pParse,yymsp[-3].minor.yy131,&yymsp[0].minor.yy0);
}
break;
- case 292: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
+ case 290: /* cmd ::= ALTER TABLE add_column_fullname ADD kwcolumn_opt columnname carglist */
{
yymsp[-1].minor.yy0.n = (int)(pParse->sLastToken.z-yymsp[-1].minor.yy0.z) + pParse->sLastToken.n;
sqlite3AlterFinishAddColumn(pParse, &yymsp[-1].minor.yy0);
}
break;
- case 293: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
+ case 291: /* cmd ::= ALTER TABLE fullname DROP kwcolumn_opt nm */
{
sqlite3AlterDropColumn(pParse, yymsp[-3].minor.yy131, &yymsp[0].minor.yy0);
}
break;
- case 294: /* add_column_fullname ::= fullname */
+ case 292: /* add_column_fullname ::= fullname */
{
disableLookaside(pParse);
sqlite3AlterBeginAddColumn(pParse, yymsp[0].minor.yy131);
}
break;
- case 295: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
+ case 293: /* cmd ::= ALTER TABLE fullname RENAME kwcolumn_opt nm TO nm */
{
sqlite3AlterRenameColumn(pParse, yymsp[-5].minor.yy131, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0);
}
break;
- case 296: /* cmd ::= create_vtab */
+ case 294: /* cmd ::= create_vtab */
{sqlite3VtabFinishParse(pParse,0);}
break;
- case 297: /* cmd ::= create_vtab LP vtabarglist RP */
+ case 295: /* cmd ::= create_vtab LP vtabarglist RP */
{sqlite3VtabFinishParse(pParse,&yymsp[0].minor.yy0);}
break;
- case 298: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
+ case 296: /* create_vtab ::= createkw VIRTUAL TABLE ifnotexists nm dbnm USING nm */
{
sqlite3VtabBeginParse(pParse, &yymsp[-3].minor.yy0, &yymsp[-2].minor.yy0, &yymsp[0].minor.yy0, yymsp[-4].minor.yy394);
}
break;
- case 299: /* vtabarg ::= */
+ case 297: /* vtabarg ::= */
{sqlite3VtabArgInit(pParse);}
break;
- case 300: /* vtabargtoken ::= ANY */
- case 301: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==301);
- case 302: /* lp ::= LP */ yytestcase(yyruleno==302);
+ case 298: /* vtabargtoken ::= ANY */
+ case 299: /* vtabargtoken ::= lp anylist RP */ yytestcase(yyruleno==299);
+ case 300: /* lp ::= LP */ yytestcase(yyruleno==300);
{sqlite3VtabArgExtend(pParse,&yymsp[0].minor.yy0);}
break;
- case 303: /* with ::= WITH wqlist */
- case 304: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==304);
+ case 301: /* with ::= WITH wqlist */
+ case 302: /* with ::= WITH RECURSIVE wqlist */ yytestcase(yyruleno==302);
{ sqlite3WithPush(pParse, yymsp[0].minor.yy521, 1); }
break;
- case 305: /* wqas ::= AS */
+ case 303: /* wqas ::= AS */
{yymsp[0].minor.yy516 = M10d_Any;}
break;
- case 306: /* wqas ::= AS MATERIALIZED */
+ case 304: /* wqas ::= AS MATERIALIZED */
{yymsp[-1].minor.yy516 = M10d_Yes;}
break;
- case 307: /* wqas ::= AS NOT MATERIALIZED */
+ case 305: /* wqas ::= AS NOT MATERIALIZED */
{yymsp[-2].minor.yy516 = M10d_No;}
break;
- case 308: /* wqitem ::= nm eidlist_opt wqas LP select RP */
+ case 306: /* wqitem ::= nm eidlist_opt wqas LP select RP */
{
yymsp[-5].minor.yy385 = sqlite3CteNew(pParse, &yymsp[-5].minor.yy0, yymsp[-4].minor.yy322, yymsp[-1].minor.yy47, yymsp[-3].minor.yy516); /*A-overwrites-X*/
}
break;
- case 309: /* wqlist ::= wqitem */
+ case 307: /* wqlist ::= wqitem */
{
yymsp[0].minor.yy521 = sqlite3WithAdd(pParse, 0, yymsp[0].minor.yy385); /*A-overwrites-X*/
}
break;
- case 310: /* wqlist ::= wqlist COMMA wqitem */
+ case 308: /* wqlist ::= wqlist COMMA wqitem */
{
yymsp[-2].minor.yy521 = sqlite3WithAdd(pParse, yymsp[-2].minor.yy521, yymsp[0].minor.yy385);
}
break;
- case 311: /* windowdefn_list ::= windowdefn */
+ case 309: /* windowdefn_list ::= windowdefn */
{ yylhsminor.yy41 = yymsp[0].minor.yy41; }
yymsp[0].minor.yy41 = yylhsminor.yy41;
break;
- case 312: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
+ case 310: /* windowdefn_list ::= windowdefn_list COMMA windowdefn */
{
assert( yymsp[0].minor.yy41!=0 );
sqlite3WindowChain(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy41);
@@ -171631,7 +172617,7 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[-2].minor.yy41 = yylhsminor.yy41;
break;
- case 313: /* windowdefn ::= nm AS LP window RP */
+ case 311: /* windowdefn ::= nm AS LP window RP */
{
if( ALWAYS(yymsp[-1].minor.yy41) ){
yymsp[-1].minor.yy41->zName = sqlite3DbStrNDup(pParse->db, yymsp[-4].minor.yy0.z, yymsp[-4].minor.yy0.n);
@@ -171640,90 +172626,90 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[-4].minor.yy41 = yylhsminor.yy41;
break;
- case 314: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
+ case 312: /* window ::= PARTITION BY nexprlist orderby_opt frame_opt */
{
yymsp[-4].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, 0);
}
break;
- case 315: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
+ case 313: /* window ::= nm PARTITION BY nexprlist orderby_opt frame_opt */
{
yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, yymsp[-2].minor.yy322, yymsp[-1].minor.yy322, &yymsp[-5].minor.yy0);
}
yymsp[-5].minor.yy41 = yylhsminor.yy41;
break;
- case 316: /* window ::= ORDER BY sortlist frame_opt */
+ case 314: /* window ::= ORDER BY sortlist frame_opt */
{
yymsp[-3].minor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, 0);
}
break;
- case 317: /* window ::= nm ORDER BY sortlist frame_opt */
+ case 315: /* window ::= nm ORDER BY sortlist frame_opt */
{
yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, yymsp[-1].minor.yy322, &yymsp[-4].minor.yy0);
}
yymsp[-4].minor.yy41 = yylhsminor.yy41;
break;
- case 318: /* window ::= frame_opt */
- case 337: /* filter_over ::= over_clause */ yytestcase(yyruleno==337);
+ case 316: /* window ::= frame_opt */
+ case 335: /* filter_over ::= over_clause */ yytestcase(yyruleno==335);
{
yylhsminor.yy41 = yymsp[0].minor.yy41;
}
yymsp[0].minor.yy41 = yylhsminor.yy41;
break;
- case 319: /* window ::= nm frame_opt */
+ case 317: /* window ::= nm frame_opt */
{
yylhsminor.yy41 = sqlite3WindowAssemble(pParse, yymsp[0].minor.yy41, 0, 0, &yymsp[-1].minor.yy0);
}
yymsp[-1].minor.yy41 = yylhsminor.yy41;
break;
- case 320: /* frame_opt ::= */
+ case 318: /* frame_opt ::= */
{
yymsp[1].minor.yy41 = sqlite3WindowAlloc(pParse, 0, TK_UNBOUNDED, 0, TK_CURRENT, 0, 0);
}
break;
- case 321: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
+ case 319: /* frame_opt ::= range_or_rows frame_bound_s frame_exclude_opt */
{
yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-2].minor.yy394, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, TK_CURRENT, 0, yymsp[0].minor.yy516);
}
yymsp[-2].minor.yy41 = yylhsminor.yy41;
break;
- case 322: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
+ case 320: /* frame_opt ::= range_or_rows BETWEEN frame_bound_s AND frame_bound_e frame_exclude_opt */
{
yylhsminor.yy41 = sqlite3WindowAlloc(pParse, yymsp[-5].minor.yy394, yymsp[-3].minor.yy595.eType, yymsp[-3].minor.yy595.pExpr, yymsp[-1].minor.yy595.eType, yymsp[-1].minor.yy595.pExpr, yymsp[0].minor.yy516);
}
yymsp[-5].minor.yy41 = yylhsminor.yy41;
break;
- case 324: /* frame_bound_s ::= frame_bound */
- case 326: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==326);
+ case 322: /* frame_bound_s ::= frame_bound */
+ case 324: /* frame_bound_e ::= frame_bound */ yytestcase(yyruleno==324);
{yylhsminor.yy595 = yymsp[0].minor.yy595;}
yymsp[0].minor.yy595 = yylhsminor.yy595;
break;
- case 325: /* frame_bound_s ::= UNBOUNDED PRECEDING */
- case 327: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==327);
- case 329: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==329);
+ case 323: /* frame_bound_s ::= UNBOUNDED PRECEDING */
+ case 325: /* frame_bound_e ::= UNBOUNDED FOLLOWING */ yytestcase(yyruleno==325);
+ case 327: /* frame_bound ::= CURRENT ROW */ yytestcase(yyruleno==327);
{yylhsminor.yy595.eType = yymsp[-1].major; yylhsminor.yy595.pExpr = 0;}
yymsp[-1].minor.yy595 = yylhsminor.yy595;
break;
- case 328: /* frame_bound ::= expr PRECEDING|FOLLOWING */
+ case 326: /* frame_bound ::= expr PRECEDING|FOLLOWING */
{yylhsminor.yy595.eType = yymsp[0].major; yylhsminor.yy595.pExpr = yymsp[-1].minor.yy528;}
yymsp[-1].minor.yy595 = yylhsminor.yy595;
break;
- case 330: /* frame_exclude_opt ::= */
+ case 328: /* frame_exclude_opt ::= */
{yymsp[1].minor.yy516 = 0;}
break;
- case 331: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
+ case 329: /* frame_exclude_opt ::= EXCLUDE frame_exclude */
{yymsp[-1].minor.yy516 = yymsp[0].minor.yy516;}
break;
- case 332: /* frame_exclude ::= NO OTHERS */
- case 333: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==333);
+ case 330: /* frame_exclude ::= NO OTHERS */
+ case 331: /* frame_exclude ::= CURRENT ROW */ yytestcase(yyruleno==331);
{yymsp[-1].minor.yy516 = yymsp[-1].major; /*A-overwrites-X*/}
break;
- case 334: /* frame_exclude ::= GROUP|TIES */
+ case 332: /* frame_exclude ::= GROUP|TIES */
{yymsp[0].minor.yy516 = yymsp[0].major; /*A-overwrites-X*/}
break;
- case 335: /* window_clause ::= WINDOW windowdefn_list */
+ case 333: /* window_clause ::= WINDOW windowdefn_list */
{ yymsp[-1].minor.yy41 = yymsp[0].minor.yy41; }
break;
- case 336: /* filter_over ::= filter_clause over_clause */
+ case 334: /* filter_over ::= filter_clause over_clause */
{
if( yymsp[0].minor.yy41 ){
yymsp[0].minor.yy41->pFilter = yymsp[-1].minor.yy528;
@@ -171734,7 +172720,7 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[-1].minor.yy41 = yylhsminor.yy41;
break;
- case 338: /* filter_over ::= filter_clause */
+ case 336: /* filter_over ::= filter_clause */
{
yylhsminor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
if( yylhsminor.yy41 ){
@@ -171746,13 +172732,13 @@ static YYACTIONTYPE yy_reduce(
}
yymsp[0].minor.yy41 = yylhsminor.yy41;
break;
- case 339: /* over_clause ::= OVER LP window RP */
+ case 337: /* over_clause ::= OVER LP window RP */
{
yymsp[-3].minor.yy41 = yymsp[-1].minor.yy41;
assert( yymsp[-3].minor.yy41!=0 );
}
break;
- case 340: /* over_clause ::= OVER nm */
+ case 338: /* over_clause ::= OVER nm */
{
yymsp[-1].minor.yy41 = (Window*)sqlite3DbMallocZero(pParse->db, sizeof(Window));
if( yymsp[-1].minor.yy41 ){
@@ -171760,73 +172746,73 @@ static YYACTIONTYPE yy_reduce(
}
}
break;
- case 341: /* filter_clause ::= FILTER LP WHERE expr RP */
+ case 339: /* filter_clause ::= FILTER LP WHERE expr RP */
{ yymsp[-4].minor.yy528 = yymsp[-1].minor.yy528; }
break;
default:
- /* (342) input ::= cmdlist */ yytestcase(yyruleno==342);
- /* (343) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==343);
- /* (344) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=344);
- /* (345) ecmd ::= SEMI */ yytestcase(yyruleno==345);
- /* (346) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==346);
- /* (347) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=347);
- /* (348) trans_opt ::= */ yytestcase(yyruleno==348);
- /* (349) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==349);
- /* (350) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==350);
- /* (351) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==351);
- /* (352) savepoint_opt ::= */ yytestcase(yyruleno==352);
- /* (353) cmd ::= create_table create_table_args */ yytestcase(yyruleno==353);
- /* (354) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=354);
- /* (355) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==355);
- /* (356) columnlist ::= columnname carglist */ yytestcase(yyruleno==356);
- /* (357) nm ::= ID|INDEXED */ yytestcase(yyruleno==357);
- /* (358) nm ::= STRING */ yytestcase(yyruleno==358);
- /* (359) nm ::= JOIN_KW */ yytestcase(yyruleno==359);
- /* (360) typetoken ::= typename */ yytestcase(yyruleno==360);
- /* (361) typename ::= ID|STRING */ yytestcase(yyruleno==361);
- /* (362) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=362);
- /* (363) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=363);
- /* (364) carglist ::= carglist ccons */ yytestcase(yyruleno==364);
- /* (365) carglist ::= */ yytestcase(yyruleno==365);
- /* (366) ccons ::= NULL onconf */ yytestcase(yyruleno==366);
- /* (367) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==367);
- /* (368) ccons ::= AS generated */ yytestcase(yyruleno==368);
- /* (369) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==369);
- /* (370) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==370);
- /* (371) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=371);
- /* (372) tconscomma ::= */ yytestcase(yyruleno==372);
- /* (373) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=373);
- /* (374) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=374);
- /* (375) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=375);
- /* (376) oneselect ::= values */ yytestcase(yyruleno==376);
- /* (377) sclp ::= selcollist COMMA */ yytestcase(yyruleno==377);
- /* (378) as ::= ID|STRING */ yytestcase(yyruleno==378);
- /* (379) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=379);
- /* (380) returning ::= */ yytestcase(yyruleno==380);
- /* (381) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=381);
- /* (382) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==382);
- /* (383) exprlist ::= nexprlist */ yytestcase(yyruleno==383);
- /* (384) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=384);
- /* (385) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=385);
- /* (386) nmnum ::= ON */ yytestcase(yyruleno==386);
- /* (387) nmnum ::= DELETE */ yytestcase(yyruleno==387);
- /* (388) nmnum ::= DEFAULT */ yytestcase(yyruleno==388);
- /* (389) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==389);
- /* (390) foreach_clause ::= */ yytestcase(yyruleno==390);
- /* (391) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==391);
- /* (392) trnm ::= nm */ yytestcase(yyruleno==392);
- /* (393) tridxby ::= */ yytestcase(yyruleno==393);
- /* (394) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==394);
- /* (395) database_kw_opt ::= */ yytestcase(yyruleno==395);
- /* (396) kwcolumn_opt ::= */ yytestcase(yyruleno==396);
- /* (397) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==397);
- /* (398) vtabarglist ::= vtabarg */ yytestcase(yyruleno==398);
- /* (399) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==399);
- /* (400) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==400);
- /* (401) anylist ::= */ yytestcase(yyruleno==401);
- /* (402) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==402);
- /* (403) anylist ::= anylist ANY */ yytestcase(yyruleno==403);
- /* (404) with ::= */ yytestcase(yyruleno==404);
+ /* (340) input ::= cmdlist */ yytestcase(yyruleno==340);
+ /* (341) cmdlist ::= cmdlist ecmd */ yytestcase(yyruleno==341);
+ /* (342) cmdlist ::= ecmd (OPTIMIZED OUT) */ assert(yyruleno!=342);
+ /* (343) ecmd ::= SEMI */ yytestcase(yyruleno==343);
+ /* (344) ecmd ::= cmdx SEMI */ yytestcase(yyruleno==344);
+ /* (345) ecmd ::= explain cmdx SEMI (NEVER REDUCES) */ assert(yyruleno!=345);
+ /* (346) trans_opt ::= */ yytestcase(yyruleno==346);
+ /* (347) trans_opt ::= TRANSACTION */ yytestcase(yyruleno==347);
+ /* (348) trans_opt ::= TRANSACTION nm */ yytestcase(yyruleno==348);
+ /* (349) savepoint_opt ::= SAVEPOINT */ yytestcase(yyruleno==349);
+ /* (350) savepoint_opt ::= */ yytestcase(yyruleno==350);
+ /* (351) cmd ::= create_table create_table_args */ yytestcase(yyruleno==351);
+ /* (352) table_option_set ::= table_option (OPTIMIZED OUT) */ assert(yyruleno!=352);
+ /* (353) columnlist ::= columnlist COMMA columnname carglist */ yytestcase(yyruleno==353);
+ /* (354) columnlist ::= columnname carglist */ yytestcase(yyruleno==354);
+ /* (355) nm ::= ID|INDEXED|JOIN_KW */ yytestcase(yyruleno==355);
+ /* (356) nm ::= STRING */ yytestcase(yyruleno==356);
+ /* (357) typetoken ::= typename */ yytestcase(yyruleno==357);
+ /* (358) typename ::= ID|STRING */ yytestcase(yyruleno==358);
+ /* (359) signed ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=359);
+ /* (360) signed ::= minus_num (OPTIMIZED OUT) */ assert(yyruleno!=360);
+ /* (361) carglist ::= carglist ccons */ yytestcase(yyruleno==361);
+ /* (362) carglist ::= */ yytestcase(yyruleno==362);
+ /* (363) ccons ::= NULL onconf */ yytestcase(yyruleno==363);
+ /* (364) ccons ::= GENERATED ALWAYS AS generated */ yytestcase(yyruleno==364);
+ /* (365) ccons ::= AS generated */ yytestcase(yyruleno==365);
+ /* (366) conslist_opt ::= COMMA conslist */ yytestcase(yyruleno==366);
+ /* (367) conslist ::= conslist tconscomma tcons */ yytestcase(yyruleno==367);
+ /* (368) conslist ::= tcons (OPTIMIZED OUT) */ assert(yyruleno!=368);
+ /* (369) tconscomma ::= */ yytestcase(yyruleno==369);
+ /* (370) defer_subclause_opt ::= defer_subclause (OPTIMIZED OUT) */ assert(yyruleno!=370);
+ /* (371) resolvetype ::= raisetype (OPTIMIZED OUT) */ assert(yyruleno!=371);
+ /* (372) selectnowith ::= oneselect (OPTIMIZED OUT) */ assert(yyruleno!=372);
+ /* (373) oneselect ::= values */ yytestcase(yyruleno==373);
+ /* (374) sclp ::= selcollist COMMA */ yytestcase(yyruleno==374);
+ /* (375) as ::= ID|STRING */ yytestcase(yyruleno==375);
+ /* (376) indexed_opt ::= indexed_by (OPTIMIZED OUT) */ assert(yyruleno!=376);
+ /* (377) returning ::= */ yytestcase(yyruleno==377);
+ /* (378) expr ::= term (OPTIMIZED OUT) */ assert(yyruleno!=378);
+ /* (379) likeop ::= LIKE_KW|MATCH */ yytestcase(yyruleno==379);
+ /* (380) case_operand ::= expr */ yytestcase(yyruleno==380);
+ /* (381) exprlist ::= nexprlist */ yytestcase(yyruleno==381);
+ /* (382) nmnum ::= plus_num (OPTIMIZED OUT) */ assert(yyruleno!=382);
+ /* (383) nmnum ::= nm (OPTIMIZED OUT) */ assert(yyruleno!=383);
+ /* (384) nmnum ::= ON */ yytestcase(yyruleno==384);
+ /* (385) nmnum ::= DELETE */ yytestcase(yyruleno==385);
+ /* (386) nmnum ::= DEFAULT */ yytestcase(yyruleno==386);
+ /* (387) plus_num ::= INTEGER|FLOAT */ yytestcase(yyruleno==387);
+ /* (388) foreach_clause ::= */ yytestcase(yyruleno==388);
+ /* (389) foreach_clause ::= FOR EACH ROW */ yytestcase(yyruleno==389);
+ /* (390) trnm ::= nm */ yytestcase(yyruleno==390);
+ /* (391) tridxby ::= */ yytestcase(yyruleno==391);
+ /* (392) database_kw_opt ::= DATABASE */ yytestcase(yyruleno==392);
+ /* (393) database_kw_opt ::= */ yytestcase(yyruleno==393);
+ /* (394) kwcolumn_opt ::= */ yytestcase(yyruleno==394);
+ /* (395) kwcolumn_opt ::= COLUMNKW */ yytestcase(yyruleno==395);
+ /* (396) vtabarglist ::= vtabarg */ yytestcase(yyruleno==396);
+ /* (397) vtabarglist ::= vtabarglist COMMA vtabarg */ yytestcase(yyruleno==397);
+ /* (398) vtabarg ::= vtabarg vtabargtoken */ yytestcase(yyruleno==398);
+ /* (399) anylist ::= */ yytestcase(yyruleno==399);
+ /* (400) anylist ::= anylist LP anylist RP */ yytestcase(yyruleno==400);
+ /* (401) anylist ::= anylist ANY */ yytestcase(yyruleno==401);
+ /* (402) with ::= */ yytestcase(yyruleno==402);
break;
/********** End reduce actions ************************************************/
};
@@ -172402,7 +173388,7 @@ static const unsigned char aKWHash[127] = {
/* aKWNext[] forms the hash collision chain. If aKWHash[i]==0
** then the i-th keyword has no more hash collisions. Otherwise,
** the next keyword with the same hash is aKWHash[i]-1. */
-static const unsigned char aKWNext[147] = {
+static const unsigned char aKWNext[148] = {0,
0, 0, 0, 0, 4, 0, 43, 0, 0, 106, 114, 0, 0,
0, 2, 0, 0, 143, 0, 0, 0, 13, 0, 0, 0, 0,
141, 0, 0, 119, 52, 0, 0, 137, 12, 0, 0, 62, 0,
@@ -172417,7 +173403,7 @@ static const unsigned char aKWNext[147] = {
102, 0, 0, 87,
};
/* aKWLen[i] is the length (in bytes) of the i-th keyword */
-static const unsigned char aKWLen[147] = {
+static const unsigned char aKWLen[148] = {0,
7, 7, 5, 4, 6, 4, 5, 3, 6, 7, 3, 6, 6,
7, 7, 3, 8, 2, 6, 5, 4, 4, 3, 10, 4, 7,
6, 9, 4, 2, 6, 5, 9, 9, 4, 7, 3, 2, 4,
@@ -172433,7 +173419,7 @@ static const unsigned char aKWLen[147] = {
};
/* aKWOffset[i] is the index into zKWText[] of the start of
** the text for the i-th keyword. */
-static const unsigned short int aKWOffset[147] = {
+static const unsigned short int aKWOffset[148] = {0,
0, 2, 2, 8, 9, 14, 16, 20, 23, 25, 25, 29, 33,
36, 41, 46, 48, 53, 54, 59, 62, 65, 67, 69, 78, 81,
86, 90, 90, 94, 99, 101, 105, 111, 119, 123, 123, 123, 126,
@@ -172448,7 +173434,7 @@ static const unsigned short int aKWOffset[147] = {
648, 650, 655, 659,
};
/* aKWCode[i] is the parser symbol code for the i-th keyword */
-static const unsigned char aKWCode[147] = {
+static const unsigned char aKWCode[148] = {0,
TK_REINDEX, TK_INDEXED, TK_INDEX, TK_DESC, TK_ESCAPE,
TK_EACH, TK_CHECK, TK_KEY, TK_BEFORE, TK_FOREIGN,
TK_FOR, TK_IGNORE, TK_LIKE_KW, TK_EXPLAIN, TK_INSTEAD,
@@ -172617,7 +173603,7 @@ static int keywordCode(const char *z, int n, int *pType){
const char *zKW;
if( n>=2 ){
i = ((charMap(z[0])*4) ^ (charMap(z[n-1])*3) ^ n*1) % 127;
- for(i=((int)aKWHash[i])-1; i>=0; i=((int)aKWNext[i])-1){
+ for(i=(int)aKWHash[i]; i>0; i=aKWNext[i]){
if( aKWLen[i]!=n ) continue;
zKW = &zKWText[aKWOffset[i]];
#ifdef SQLITE_ASCII
@@ -172633,153 +173619,153 @@ static int keywordCode(const char *z, int n, int *pType){
while( j<n && toupper(z[j])==zKW[j] ){ j++; }
#endif
if( j<n ) continue;
- testcase( i==0 ); /* REINDEX */
- testcase( i==1 ); /* INDEXED */
- testcase( i==2 ); /* INDEX */
- testcase( i==3 ); /* DESC */
- testcase( i==4 ); /* ESCAPE */
- testcase( i==5 ); /* EACH */
- testcase( i==6 ); /* CHECK */
- testcase( i==7 ); /* KEY */
- testcase( i==8 ); /* BEFORE */
- testcase( i==9 ); /* FOREIGN */
- testcase( i==10 ); /* FOR */
- testcase( i==11 ); /* IGNORE */
- testcase( i==12 ); /* REGEXP */
- testcase( i==13 ); /* EXPLAIN */
- testcase( i==14 ); /* INSTEAD */
- testcase( i==15 ); /* ADD */
- testcase( i==16 ); /* DATABASE */
- testcase( i==17 ); /* AS */
- testcase( i==18 ); /* SELECT */
- testcase( i==19 ); /* TABLE */
- testcase( i==20 ); /* LEFT */
- testcase( i==21 ); /* THEN */
- testcase( i==22 ); /* END */
- testcase( i==23 ); /* DEFERRABLE */
- testcase( i==24 ); /* ELSE */
- testcase( i==25 ); /* EXCLUDE */
- testcase( i==26 ); /* DELETE */
- testcase( i==27 ); /* TEMPORARY */
- testcase( i==28 ); /* TEMP */
- testcase( i==29 ); /* OR */
- testcase( i==30 ); /* ISNULL */
- testcase( i==31 ); /* NULLS */
- testcase( i==32 ); /* SAVEPOINT */
- testcase( i==33 ); /* INTERSECT */
- testcase( i==34 ); /* TIES */
- testcase( i==35 ); /* NOTNULL */
- testcase( i==36 ); /* NOT */
- testcase( i==37 ); /* NO */
- testcase( i==38 ); /* NULL */
- testcase( i==39 ); /* LIKE */
- testcase( i==40 ); /* EXCEPT */
- testcase( i==41 ); /* TRANSACTION */
- testcase( i==42 ); /* ACTION */
- testcase( i==43 ); /* ON */
- testcase( i==44 ); /* NATURAL */
- testcase( i==45 ); /* ALTER */
- testcase( i==46 ); /* RAISE */
- testcase( i==47 ); /* EXCLUSIVE */
- testcase( i==48 ); /* EXISTS */
- testcase( i==49 ); /* CONSTRAINT */
- testcase( i==50 ); /* INTO */
- testcase( i==51 ); /* OFFSET */
- testcase( i==52 ); /* OF */
- testcase( i==53 ); /* SET */
- testcase( i==54 ); /* TRIGGER */
- testcase( i==55 ); /* RANGE */
- testcase( i==56 ); /* GENERATED */
- testcase( i==57 ); /* DETACH */
- testcase( i==58 ); /* HAVING */
- testcase( i==59 ); /* GLOB */
- testcase( i==60 ); /* BEGIN */
- testcase( i==61 ); /* INNER */
- testcase( i==62 ); /* REFERENCES */
- testcase( i==63 ); /* UNIQUE */
- testcase( i==64 ); /* QUERY */
- testcase( i==65 ); /* WITHOUT */
- testcase( i==66 ); /* WITH */
- testcase( i==67 ); /* OUTER */
- testcase( i==68 ); /* RELEASE */
- testcase( i==69 ); /* ATTACH */
- testcase( i==70 ); /* BETWEEN */
- testcase( i==71 ); /* NOTHING */
- testcase( i==72 ); /* GROUPS */
- testcase( i==73 ); /* GROUP */
- testcase( i==74 ); /* CASCADE */
- testcase( i==75 ); /* ASC */
- testcase( i==76 ); /* DEFAULT */
- testcase( i==77 ); /* CASE */
- testcase( i==78 ); /* COLLATE */
- testcase( i==79 ); /* CREATE */
- testcase( i==80 ); /* CURRENT_DATE */
- testcase( i==81 ); /* IMMEDIATE */
- testcase( i==82 ); /* JOIN */
- testcase( i==83 ); /* INSERT */
- testcase( i==84 ); /* MATCH */
- testcase( i==85 ); /* PLAN */
- testcase( i==86 ); /* ANALYZE */
- testcase( i==87 ); /* PRAGMA */
- testcase( i==88 ); /* MATERIALIZED */
- testcase( i==89 ); /* DEFERRED */
- testcase( i==90 ); /* DISTINCT */
- testcase( i==91 ); /* IS */
- testcase( i==92 ); /* UPDATE */
- testcase( i==93 ); /* VALUES */
- testcase( i==94 ); /* VIRTUAL */
- testcase( i==95 ); /* ALWAYS */
- testcase( i==96 ); /* WHEN */
- testcase( i==97 ); /* WHERE */
- testcase( i==98 ); /* RECURSIVE */
- testcase( i==99 ); /* ABORT */
- testcase( i==100 ); /* AFTER */
- testcase( i==101 ); /* RENAME */
- testcase( i==102 ); /* AND */
- testcase( i==103 ); /* DROP */
- testcase( i==104 ); /* PARTITION */
- testcase( i==105 ); /* AUTOINCREMENT */
- testcase( i==106 ); /* TO */
- testcase( i==107 ); /* IN */
- testcase( i==108 ); /* CAST */
- testcase( i==109 ); /* COLUMN */
- testcase( i==110 ); /* COMMIT */
- testcase( i==111 ); /* CONFLICT */
- testcase( i==112 ); /* CROSS */
- testcase( i==113 ); /* CURRENT_TIMESTAMP */
- testcase( i==114 ); /* CURRENT_TIME */
- testcase( i==115 ); /* CURRENT */
- testcase( i==116 ); /* PRECEDING */
- testcase( i==117 ); /* FAIL */
- testcase( i==118 ); /* LAST */
- testcase( i==119 ); /* FILTER */
- testcase( i==120 ); /* REPLACE */
- testcase( i==121 ); /* FIRST */
- testcase( i==122 ); /* FOLLOWING */
- testcase( i==123 ); /* FROM */
- testcase( i==124 ); /* FULL */
- testcase( i==125 ); /* LIMIT */
- testcase( i==126 ); /* IF */
- testcase( i==127 ); /* ORDER */
- testcase( i==128 ); /* RESTRICT */
- testcase( i==129 ); /* OTHERS */
- testcase( i==130 ); /* OVER */
- testcase( i==131 ); /* RETURNING */
- testcase( i==132 ); /* RIGHT */
- testcase( i==133 ); /* ROLLBACK */
- testcase( i==134 ); /* ROWS */
- testcase( i==135 ); /* ROW */
- testcase( i==136 ); /* UNBOUNDED */
- testcase( i==137 ); /* UNION */
- testcase( i==138 ); /* USING */
- testcase( i==139 ); /* VACUUM */
- testcase( i==140 ); /* VIEW */
- testcase( i==141 ); /* WINDOW */
- testcase( i==142 ); /* DO */
- testcase( i==143 ); /* BY */
- testcase( i==144 ); /* INITIALLY */
- testcase( i==145 ); /* ALL */
- testcase( i==146 ); /* PRIMARY */
+ testcase( i==1 ); /* REINDEX */
+ testcase( i==2 ); /* INDEXED */
+ testcase( i==3 ); /* INDEX */
+ testcase( i==4 ); /* DESC */
+ testcase( i==5 ); /* ESCAPE */
+ testcase( i==6 ); /* EACH */
+ testcase( i==7 ); /* CHECK */
+ testcase( i==8 ); /* KEY */
+ testcase( i==9 ); /* BEFORE */
+ testcase( i==10 ); /* FOREIGN */
+ testcase( i==11 ); /* FOR */
+ testcase( i==12 ); /* IGNORE */
+ testcase( i==13 ); /* REGEXP */
+ testcase( i==14 ); /* EXPLAIN */
+ testcase( i==15 ); /* INSTEAD */
+ testcase( i==16 ); /* ADD */
+ testcase( i==17 ); /* DATABASE */
+ testcase( i==18 ); /* AS */
+ testcase( i==19 ); /* SELECT */
+ testcase( i==20 ); /* TABLE */
+ testcase( i==21 ); /* LEFT */
+ testcase( i==22 ); /* THEN */
+ testcase( i==23 ); /* END */
+ testcase( i==24 ); /* DEFERRABLE */
+ testcase( i==25 ); /* ELSE */
+ testcase( i==26 ); /* EXCLUDE */
+ testcase( i==27 ); /* DELETE */
+ testcase( i==28 ); /* TEMPORARY */
+ testcase( i==29 ); /* TEMP */
+ testcase( i==30 ); /* OR */
+ testcase( i==31 ); /* ISNULL */
+ testcase( i==32 ); /* NULLS */
+ testcase( i==33 ); /* SAVEPOINT */
+ testcase( i==34 ); /* INTERSECT */
+ testcase( i==35 ); /* TIES */
+ testcase( i==36 ); /* NOTNULL */
+ testcase( i==37 ); /* NOT */
+ testcase( i==38 ); /* NO */
+ testcase( i==39 ); /* NULL */
+ testcase( i==40 ); /* LIKE */
+ testcase( i==41 ); /* EXCEPT */
+ testcase( i==42 ); /* TRANSACTION */
+ testcase( i==43 ); /* ACTION */
+ testcase( i==44 ); /* ON */
+ testcase( i==45 ); /* NATURAL */
+ testcase( i==46 ); /* ALTER */
+ testcase( i==47 ); /* RAISE */
+ testcase( i==48 ); /* EXCLUSIVE */
+ testcase( i==49 ); /* EXISTS */
+ testcase( i==50 ); /* CONSTRAINT */
+ testcase( i==51 ); /* INTO */
+ testcase( i==52 ); /* OFFSET */
+ testcase( i==53 ); /* OF */
+ testcase( i==54 ); /* SET */
+ testcase( i==55 ); /* TRIGGER */
+ testcase( i==56 ); /* RANGE */
+ testcase( i==57 ); /* GENERATED */
+ testcase( i==58 ); /* DETACH */
+ testcase( i==59 ); /* HAVING */
+ testcase( i==60 ); /* GLOB */
+ testcase( i==61 ); /* BEGIN */
+ testcase( i==62 ); /* INNER */
+ testcase( i==63 ); /* REFERENCES */
+ testcase( i==64 ); /* UNIQUE */
+ testcase( i==65 ); /* QUERY */
+ testcase( i==66 ); /* WITHOUT */
+ testcase( i==67 ); /* WITH */
+ testcase( i==68 ); /* OUTER */
+ testcase( i==69 ); /* RELEASE */
+ testcase( i==70 ); /* ATTACH */
+ testcase( i==71 ); /* BETWEEN */
+ testcase( i==72 ); /* NOTHING */
+ testcase( i==73 ); /* GROUPS */
+ testcase( i==74 ); /* GROUP */
+ testcase( i==75 ); /* CASCADE */
+ testcase( i==76 ); /* ASC */
+ testcase( i==77 ); /* DEFAULT */
+ testcase( i==78 ); /* CASE */
+ testcase( i==79 ); /* COLLATE */
+ testcase( i==80 ); /* CREATE */
+ testcase( i==81 ); /* CURRENT_DATE */
+ testcase( i==82 ); /* IMMEDIATE */
+ testcase( i==83 ); /* JOIN */
+ testcase( i==84 ); /* INSERT */
+ testcase( i==85 ); /* MATCH */
+ testcase( i==86 ); /* PLAN */
+ testcase( i==87 ); /* ANALYZE */
+ testcase( i==88 ); /* PRAGMA */
+ testcase( i==89 ); /* MATERIALIZED */
+ testcase( i==90 ); /* DEFERRED */
+ testcase( i==91 ); /* DISTINCT */
+ testcase( i==92 ); /* IS */
+ testcase( i==93 ); /* UPDATE */
+ testcase( i==94 ); /* VALUES */
+ testcase( i==95 ); /* VIRTUAL */
+ testcase( i==96 ); /* ALWAYS */
+ testcase( i==97 ); /* WHEN */
+ testcase( i==98 ); /* WHERE */
+ testcase( i==99 ); /* RECURSIVE */
+ testcase( i==100 ); /* ABORT */
+ testcase( i==101 ); /* AFTER */
+ testcase( i==102 ); /* RENAME */
+ testcase( i==103 ); /* AND */
+ testcase( i==104 ); /* DROP */
+ testcase( i==105 ); /* PARTITION */
+ testcase( i==106 ); /* AUTOINCREMENT */
+ testcase( i==107 ); /* TO */
+ testcase( i==108 ); /* IN */
+ testcase( i==109 ); /* CAST */
+ testcase( i==110 ); /* COLUMN */
+ testcase( i==111 ); /* COMMIT */
+ testcase( i==112 ); /* CONFLICT */
+ testcase( i==113 ); /* CROSS */
+ testcase( i==114 ); /* CURRENT_TIMESTAMP */
+ testcase( i==115 ); /* CURRENT_TIME */
+ testcase( i==116 ); /* CURRENT */
+ testcase( i==117 ); /* PRECEDING */
+ testcase( i==118 ); /* FAIL */
+ testcase( i==119 ); /* LAST */
+ testcase( i==120 ); /* FILTER */
+ testcase( i==121 ); /* REPLACE */
+ testcase( i==122 ); /* FIRST */
+ testcase( i==123 ); /* FOLLOWING */
+ testcase( i==124 ); /* FROM */
+ testcase( i==125 ); /* FULL */
+ testcase( i==126 ); /* LIMIT */
+ testcase( i==127 ); /* IF */
+ testcase( i==128 ); /* ORDER */
+ testcase( i==129 ); /* RESTRICT */
+ testcase( i==130 ); /* OTHERS */
+ testcase( i==131 ); /* OVER */
+ testcase( i==132 ); /* RETURNING */
+ testcase( i==133 ); /* RIGHT */
+ testcase( i==134 ); /* ROLLBACK */
+ testcase( i==135 ); /* ROWS */
+ testcase( i==136 ); /* ROW */
+ testcase( i==137 ); /* UNBOUNDED */
+ testcase( i==138 ); /* UNION */
+ testcase( i==139 ); /* USING */
+ testcase( i==140 ); /* VACUUM */
+ testcase( i==141 ); /* VIEW */
+ testcase( i==142 ); /* WINDOW */
+ testcase( i==143 ); /* DO */
+ testcase( i==144 ); /* BY */
+ testcase( i==145 ); /* INITIALLY */
+ testcase( i==146 ); /* ALL */
+ testcase( i==147 ); /* PRIMARY */
*pType = aKWCode[i];
break;
}
@@ -172794,6 +173780,7 @@ SQLITE_PRIVATE int sqlite3KeywordCode(const unsigned char *z, int n){
#define SQLITE_N_KEYWORD 147
SQLITE_API int sqlite3_keyword_name(int i,const char **pzName,int *pnName){
if( i<0 || i>=SQLITE_N_KEYWORD ) return SQLITE_ERROR;
+ i++;
*pzName = zKWText + aKWOffset[i];
*pnName = aKWLen[i];
return SQLITE_OK;
@@ -174332,9 +175319,21 @@ SQLITE_API int sqlite3_config(int op, ...){
va_list ap;
int rc = SQLITE_OK;
- /* sqlite3_config() shall return SQLITE_MISUSE if it is invoked while
- ** the SQLite library is in use. */
- if( sqlite3GlobalConfig.isInit ) return SQLITE_MISUSE_BKPT;
+ /* sqlite3_config() normally returns SQLITE_MISUSE if it is invoked while
+ ** the SQLite library is in use. Except, a few selected opcodes
+ ** are allowed.
+ */
+ if( sqlite3GlobalConfig.isInit ){
+ static const u64 mAnytimeConfigOption = 0
+ | MASKBIT64( SQLITE_CONFIG_LOG )
+ | MASKBIT64( SQLITE_CONFIG_PCACHE_HDRSZ )
+ ;
+ if( op<0 || op>63 || (MASKBIT64(op) & mAnytimeConfigOption)==0 ){
+ return SQLITE_MISUSE_BKPT;
+ }
+ testcase( op==SQLITE_CONFIG_LOG );
+ testcase( op==SQLITE_CONFIG_PCACHE_HDRSZ );
+ }
va_start(ap, op);
switch( op ){
@@ -174403,6 +175402,7 @@ SQLITE_API int sqlite3_config(int op, ...){
break;
}
case SQLITE_CONFIG_MEMSTATUS: {
+ assert( !sqlite3GlobalConfig.isInit ); /* Cannot change at runtime */
/* EVIDENCE-OF: R-61275-35157 The SQLITE_CONFIG_MEMSTATUS option takes
** single argument of type int, interpreted as a boolean, which enables
** or disables the collection of memory allocation statistics. */
@@ -174526,8 +175526,10 @@ SQLITE_API int sqlite3_config(int op, ...){
** sqlite3GlobalConfig.xLog = va_arg(ap, void(*)(void*,int,const char*));
*/
typedef void(*LOGFUNC_t)(void*,int,const char*);
- sqlite3GlobalConfig.xLog = va_arg(ap, LOGFUNC_t);
- sqlite3GlobalConfig.pLogArg = va_arg(ap, void*);
+ LOGFUNC_t xLog = va_arg(ap, LOGFUNC_t);
+ void *pLogArg = va_arg(ap, void*);
+ AtomicStore(&sqlite3GlobalConfig.xLog, xLog);
+ AtomicStore(&sqlite3GlobalConfig.pLogArg, pLogArg);
break;
}
@@ -174541,7 +175543,8 @@ SQLITE_API int sqlite3_config(int op, ...){
** argument of type int. If non-zero, then URI handling is globally
** enabled. If the parameter is zero, then URI handling is globally
** disabled. */
- sqlite3GlobalConfig.bOpenUri = va_arg(ap, int);
+ int bOpenUri = va_arg(ap, int);
+ AtomicStore(&sqlite3GlobalConfig.bOpenUri, bOpenUri);
break;
}
@@ -174856,6 +175859,8 @@ SQLITE_API int sqlite3_db_config(sqlite3 *db, int op, ...){
{ SQLITE_DBCONFIG_DQS_DML, SQLITE_DqsDML },
{ SQLITE_DBCONFIG_LEGACY_FILE_FORMAT, SQLITE_LegacyFileFmt },
{ SQLITE_DBCONFIG_TRUSTED_SCHEMA, SQLITE_TrustedSchema },
+ { SQLITE_DBCONFIG_STMT_SCANSTATUS, SQLITE_StmtScanStatus },
+ { SQLITE_DBCONFIG_REVERSE_SCANORDER, SQLITE_ReverseOrder },
};
unsigned int i;
rc = SQLITE_ERROR; /* IMP: R-42790-23372 */
@@ -176841,9 +177846,9 @@ SQLITE_PRIVATE int sqlite3ParseUri(
assert( *pzErrMsg==0 );
- if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */
- || sqlite3GlobalConfig.bOpenUri) /* IMP: R-51689-46548 */
- && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
+ if( ((flags & SQLITE_OPEN_URI) /* IMP: R-48725-32206 */
+ || AtomicLoad(&sqlite3GlobalConfig.bOpenUri)) /* IMP: R-51689-46548 */
+ && nUri>=5 && memcmp(zUri, "file:", 5)==0 /* IMP: R-57884-37496 */
){
char *zOpt;
int eState; /* Parser state when parsing URI */
@@ -177250,6 +178255,9 @@ static int openDatabase(
#if defined(SQLITE_DEFAULT_LEGACY_ALTER_TABLE)
| SQLITE_LegacyAlter
#endif
+#if defined(SQLITE_ENABLE_STMT_SCANSTATUS)
+ | SQLITE_StmtScanStatus
+#endif
;
sqlite3HashInit(&db->aCollSeq);
#ifndef SQLITE_OMIT_VIRTUALTABLE
@@ -177814,7 +178822,7 @@ SQLITE_API int sqlite3_sleep(int ms){
/* This function works in milliseconds, but the underlying OsSleep()
** API uses microseconds. Hence the 1000's.
*/
- rc = (sqlite3OsSleep(pVfs, 1000*ms)/1000);
+ rc = (sqlite3OsSleep(pVfs, ms<0 ? 0 : 1000*ms)/1000);
return rc;
}
@@ -193018,16 +194026,18 @@ static int fts3MsrBufferData(
char *pList,
i64 nList
){
- if( nList>pMsr->nBuffer ){
+ if( (nList+FTS3_NODE_PADDING)>pMsr->nBuffer ){
char *pNew;
- pMsr->nBuffer = nList*2;
- pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, pMsr->nBuffer);
+ int nNew = nList*2 + FTS3_NODE_PADDING;
+ pNew = (char *)sqlite3_realloc64(pMsr->aBuffer, nNew);
if( !pNew ) return SQLITE_NOMEM;
pMsr->aBuffer = pNew;
+ pMsr->nBuffer = nNew;
}
assert( nList>0 );
memcpy(pMsr->aBuffer, pList, nList);
+ memset(&pMsr->aBuffer[nList], 0, FTS3_NODE_PADDING);
return SQLITE_OK;
}
@@ -198816,6 +199826,7 @@ static const char * const jsonType[] = {
#define JNODE_PATCH 0x10 /* Patch with JsonNode.u.pPatch */
#define JNODE_APPEND 0x20 /* More ARRAY/OBJECT entries at u.iAppend */
#define JNODE_LABEL 0x40 /* Is a label of an object */
+#define JNODE_JSON5 0x80 /* Node contains JSON5 enhancements */
/* A single node of parsed JSON
@@ -198842,10 +199853,12 @@ struct JsonParse {
JsonNode *aNode; /* Array of nodes containing the parse */
const char *zJson; /* Original JSON string */
u32 *aUp; /* Index of parent of each node */
- u8 oom; /* Set to true if out of memory */
- u8 nErr; /* Number of errors seen */
u16 iDepth; /* Nesting depth */
+ u8 nErr; /* Number of errors seen */
+ u8 oom; /* Set to true if out of memory */
+ u8 hasNonstd; /* True if input uses non-standard features like JSON5 */
int nJson; /* Length of the zJson string in bytes */
+ u32 iErr; /* Error location in zJson[] */
u32 iHold; /* Replace cache line with the lowest iHold value */
};
@@ -198853,10 +199866,10 @@ struct JsonParse {
** Maximum nesting depth of JSON for this implementation.
**
** This limit is needed to avoid a stack overflow in the recursive
-** descent parser. A depth of 2000 is far deeper than any sane JSON
-** should go.
+** descent parser. A depth of 1000 is far deeper than any sane JSON
+** should go. Historical note: This limit was 2000 prior to version 3.42.0
*/
-#define JSON_MAX_DEPTH 2000
+#define JSON_MAX_DEPTH 1000
/**************************************************************************
** Utility routines for dealing with JsonString objects
@@ -199007,6 +200020,129 @@ static void jsonAppendString(JsonString *p, const char *zIn, u32 N){
}
/*
+** The zIn[0..N] string is a JSON5 string literal. Append to p a translation
+** of the string literal that standard JSON and that omits all JSON5
+** features.
+*/
+static void jsonAppendNormalizedString(JsonString *p, const char *zIn, u32 N){
+ u32 i;
+ jsonAppendChar(p, '"');
+ zIn++;
+ N -= 2;
+ while( N>0 ){
+ for(i=0; i<N && zIn[i]!='\\'; i++){}
+ if( i>0 ){
+ jsonAppendRaw(p, zIn, i);
+ zIn += i;
+ N -= i;
+ if( N==0 ) break;
+ }
+ assert( zIn[0]=='\\' );
+ switch( (u8)zIn[1] ){
+ case '\'':
+ jsonAppendChar(p, '\'');
+ break;
+ case 'v':
+ jsonAppendRaw(p, "\\u0009", 6);
+ break;
+ case 'x':
+ jsonAppendRaw(p, "\\u00", 4);
+ jsonAppendRaw(p, &zIn[2], 2);
+ zIn += 2;
+ N -= 2;
+ break;
+ case '0':
+ jsonAppendRaw(p, "\\u0000", 6);
+ break;
+ case '\r':
+ if( zIn[2]=='\n' ){
+ zIn++;
+ N--;
+ }
+ break;
+ case '\n':
+ break;
+ case 0xe2:
+ assert( N>=4 );
+ assert( 0x80==(u8)zIn[2] );
+ assert( 0xa8==(u8)zIn[3] || 0xa9==(u8)zIn[3] );
+ zIn += 2;
+ N -= 2;
+ break;
+ default:
+ jsonAppendRaw(p, zIn, 2);
+ break;
+ }
+ zIn += 2;
+ N -= 2;
+ }
+ jsonAppendChar(p, '"');
+}
+
+/*
+** The zIn[0..N] string is a JSON5 integer literal. Append to p a translation
+** of the string literal that standard JSON and that omits all JSON5
+** features.
+*/
+static void jsonAppendNormalizedInt(JsonString *p, const char *zIn, u32 N){
+ if( zIn[0]=='+' ){
+ zIn++;
+ N--;
+ }else if( zIn[0]=='-' ){
+ jsonAppendChar(p, '-');
+ zIn++;
+ N--;
+ }
+ if( zIn[0]=='0' && (zIn[1]=='x' || zIn[1]=='X') ){
+ sqlite3_int64 i = 0;
+ int rc = sqlite3DecOrHexToI64(zIn, &i);
+ if( rc<=1 ){
+ jsonPrintf(100,p,"%lld",i);
+ }else{
+ assert( rc==2 );
+ jsonAppendRaw(p, "9.0e999", 7);
+ }
+ return;
+ }
+ jsonAppendRaw(p, zIn, N);
+}
+
+/*
+** The zIn[0..N] string is a JSON5 real literal. Append to p a translation
+** of the string literal that standard JSON and that omits all JSON5
+** features.
+*/
+static void jsonAppendNormalizedReal(JsonString *p, const char *zIn, u32 N){
+ u32 i;
+ if( zIn[0]=='+' ){
+ zIn++;
+ N--;
+ }else if( zIn[0]=='-' ){
+ jsonAppendChar(p, '-');
+ zIn++;
+ N--;
+ }
+ if( zIn[0]=='.' ){
+ jsonAppendChar(p, '0');
+ }
+ for(i=0; i<N; i++){
+ if( zIn[i]=='.' && (i+1==N || !sqlite3Isdigit(zIn[i+1])) ){
+ i++;
+ jsonAppendRaw(p, zIn, i);
+ zIn += i;
+ N -= i;
+ jsonAppendChar(p, '0');
+ break;
+ }
+ }
+ if( N>0 ){
+ jsonAppendRaw(p, zIn, N);
+ }
+}
+
+
+
+/*
** Append a function parameter value to the JSON string under
** construction.
*/
@@ -199019,8 +200155,11 @@ static void jsonAppendValue(
jsonAppendRaw(p, "null", 4);
break;
}
- case SQLITE_INTEGER:
case SQLITE_FLOAT: {
+ jsonPrintf(100, p, "%!0.15g", sqlite3_value_double(pValue));
+ break;
+ }
+ case SQLITE_INTEGER: {
const char *z = (const char*)sqlite3_value_text(pValue);
u32 n = (u32)sqlite3_value_bytes(pValue);
jsonAppendRaw(p, z, n);
@@ -199133,17 +200272,38 @@ static void jsonRenderNode(
break;
}
case JSON_STRING: {
+ assert( pNode->eU==1 );
if( pNode->jnFlags & JNODE_RAW ){
- assert( pNode->eU==1 );
- jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
- break;
+ if( pNode->jnFlags & JNODE_LABEL ){
+ jsonAppendChar(pOut, '"');
+ jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
+ jsonAppendChar(pOut, '"');
+ }else{
+ jsonAppendString(pOut, pNode->u.zJContent, pNode->n);
+ }
+ }else if( pNode->jnFlags & JNODE_JSON5 ){
+ jsonAppendNormalizedString(pOut, pNode->u.zJContent, pNode->n);
+ }else{
+ jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
}
- /* no break */ deliberate_fall_through
+ break;
+ }
+ case JSON_REAL: {
+ assert( pNode->eU==1 );
+ if( pNode->jnFlags & JNODE_JSON5 ){
+ jsonAppendNormalizedReal(pOut, pNode->u.zJContent, pNode->n);
+ }else{
+ jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
+ }
+ break;
}
- case JSON_REAL:
case JSON_INT: {
assert( pNode->eU==1 );
- jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
+ if( pNode->jnFlags & JNODE_JSON5 ){
+ jsonAppendNormalizedInt(pOut, pNode->u.zJContent, pNode->n);
+ }else{
+ jsonAppendRaw(pOut, pNode->u.zJContent, pNode->n);
+ }
break;
}
case JSON_ARRAY: {
@@ -199259,59 +200419,41 @@ static void jsonReturn(
}
case JSON_INT: {
sqlite3_int64 i = 0;
+ int rc;
+ int bNeg = 0;
const char *z;
+
+
assert( pNode->eU==1 );
z = pNode->u.zJContent;
- if( z[0]=='-' ){ z++; }
- while( z[0]>='0' && z[0]<='9' ){
- unsigned v = *(z++) - '0';
- if( i>=LARGEST_INT64/10 ){
- if( i>LARGEST_INT64/10 ) goto int_as_real;
- if( z[0]>='0' && z[0]<='9' ) goto int_as_real;
- if( v==9 ) goto int_as_real;
- if( v==8 ){
- if( pNode->u.zJContent[0]=='-' ){
- sqlite3_result_int64(pCtx, SMALLEST_INT64);
- goto int_done;
- }else{
- goto int_as_real;
- }
- }
- }
- i = i*10 + v;
+ if( z[0]=='-' ){ z++; bNeg = 1; }
+ else if( z[0]=='+' ){ z++; }
+ rc = sqlite3DecOrHexToI64(z, &i);
+ if( rc<=1 ){
+ sqlite3_result_int64(pCtx, bNeg ? -i : i);
+ }else if( rc==3 && bNeg ){
+ sqlite3_result_int64(pCtx, SMALLEST_INT64);
+ }else{
+ goto to_double;
}
- if( pNode->u.zJContent[0]=='-' ){ i = -i; }
- sqlite3_result_int64(pCtx, i);
- int_done:
break;
- int_as_real: ; /* no break */ deliberate_fall_through
}
case JSON_REAL: {
double r;
-#ifdef SQLITE_AMALGAMATION
const char *z;
assert( pNode->eU==1 );
+ to_double:
z = pNode->u.zJContent;
sqlite3AtoF(z, &r, sqlite3Strlen30(z), SQLITE_UTF8);
-#else
- assert( pNode->eU==1 );
- r = strtod(pNode->u.zJContent, 0);
-#endif
sqlite3_result_double(pCtx, r);
break;
}
case JSON_STRING: {
-#if 0 /* Never happens because JNODE_RAW is only set by json_set(),
- ** json_insert() and json_replace() and those routines do not
- ** call jsonReturn() */
if( pNode->jnFlags & JNODE_RAW ){
assert( pNode->eU==1 );
sqlite3_result_text(pCtx, pNode->u.zJContent, pNode->n,
SQLITE_TRANSIENT);
- }else
-#endif
- assert( (pNode->jnFlags & JNODE_RAW)==0 );
- if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
+ }else if( (pNode->jnFlags & JNODE_ESCAPE)==0 ){
/* JSON formatted without any backslash-escapes */
assert( pNode->eU==1 );
sqlite3_result_text(pCtx, pNode->u.zJContent+1, pNode->n-2,
@@ -199323,18 +200465,17 @@ static void jsonReturn(
const char *z;
char *zOut;
u32 j;
+ u32 nOut = n;
assert( pNode->eU==1 );
z = pNode->u.zJContent;
- zOut = sqlite3_malloc( n+1 );
+ zOut = sqlite3_malloc( nOut+1 );
if( zOut==0 ){
sqlite3_result_error_nomem(pCtx);
break;
}
for(i=1, j=0; i<n-1; i++){
char c = z[i];
- if( c!='\\' ){
- zOut[j++] = c;
- }else{
+ if( c=='\\' ){
c = z[++i];
if( c=='u' ){
u32 v = jsonHexToInt4(z+i+1);
@@ -199366,22 +200507,40 @@ static void jsonReturn(
zOut[j++] = 0x80 | (v&0x3f);
}
}
+ continue;
+ }else if( c=='b' ){
+ c = '\b';
+ }else if( c=='f' ){
+ c = '\f';
+ }else if( c=='n' ){
+ c = '\n';
+ }else if( c=='r' ){
+ c = '\r';
+ }else if( c=='t' ){
+ c = '\t';
+ }else if( c=='v' ){
+ c = '\v';
+ }else if( c=='\'' || c=='"' || c=='/' || c=='\\' ){
+ /* pass through unchanged */
+ }else if( c=='0' ){
+ c = 0;
+ }else if( c=='x' ){
+ c = (jsonHexToInt(z[i+1])<<4) | jsonHexToInt(z[i+2]);
+ i += 2;
+ }else if( c=='\r' && z[i+1]=='\n' ){
+ i++;
+ continue;
+ }else if( 0xe2==(u8)c ){
+ assert( 0x80==(u8)z[i+1] );
+ assert( 0xa8==(u8)z[i+2] || 0xa9==(u8)z[i+2] );
+ i += 2;
+ continue;
}else{
- if( c=='b' ){
- c = '\b';
- }else if( c=='f' ){
- c = '\f';
- }else if( c=='n' ){
- c = '\n';
- }else if( c=='r' ){
- c = '\r';
- }else if( c=='t' ){
- c = '\t';
- }
- zOut[j++] = c;
+ continue;
}
- }
- }
+ } /* end if( c=='\\' ) */
+ zOut[j++] = c;
+ } /* end for() */
zOut[j] = 0;
sqlite3_result_text(pCtx, zOut, j, sqlite3_free);
}
@@ -199449,8 +200608,8 @@ static int jsonParseAddNode(
return jsonParseAddNodeExpand(pParse, eType, n, zContent);
}
p = &pParse->aNode[pParse->nNode];
- p->eType = (u8)eType;
- p->jnFlags = 0;
+ p->eType = (u8)(eType & 0xff);
+ p->jnFlags = (u8)(eType >> 8);
VVA( p->eU = zContent ? 1 : 0 );
p->n = n;
p->u.zJContent = zContent;
@@ -199458,21 +200617,177 @@ static int jsonParseAddNode(
}
/*
+** Return true if z[] begins with 2 (or more) hexadecimal digits
+*/
+static int jsonIs2Hex(const char *z){
+ return sqlite3Isxdigit(z[0]) && sqlite3Isxdigit(z[1]);
+}
+
+/*
** Return true if z[] begins with 4 (or more) hexadecimal digits
*/
static int jsonIs4Hex(const char *z){
- int i;
- for(i=0; i<4; i++) if( !sqlite3Isxdigit(z[i]) ) return 0;
- return 1;
+ return jsonIs2Hex(z) && jsonIs2Hex(&z[2]);
+}
+
+/*
+** Return the number of bytes of JSON5 whitespace at the beginning of
+** the input string z[].
+**
+** JSON5 whitespace consists of any of the following characters:
+**
+** Unicode UTF-8 Name
+** U+0009 09 horizontal tab
+** U+000a 0a line feed
+** U+000b 0b vertical tab
+** U+000c 0c form feed
+** U+000d 0d carriage return
+** U+0020 20 space
+** U+00a0 c2 a0 non-breaking space
+** U+1680 e1 9a 80 ogham space mark
+** U+2000 e2 80 80 en quad
+** U+2001 e2 80 81 em quad
+** U+2002 e2 80 82 en space
+** U+2003 e2 80 83 em space
+** U+2004 e2 80 84 three-per-em space
+** U+2005 e2 80 85 four-per-em space
+** U+2006 e2 80 86 six-per-em space
+** U+2007 e2 80 87 figure space
+** U+2008 e2 80 88 punctuation space
+** U+2009 e2 80 89 thin space
+** U+200a e2 80 8a hair space
+** U+2028 e2 80 a8 line separator
+** U+2029 e2 80 a9 paragraph separator
+** U+202f e2 80 af narrow no-break space (NNBSP)
+** U+205f e2 81 9f medium mathematical space (MMSP)
+** U+3000 e3 80 80 ideographical space
+** U+FEFF ef bb bf byte order mark
+**
+** In addition, comments between '/', '*' and '*', '/' and
+** from '/', '/' to end-of-line are also considered to be whitespace.
+*/
+static int json5Whitespace(const char *zIn){
+ int n = 0;
+ const u8 *z = (u8*)zIn;
+ while( 1 /*exit by "goto whitespace_done"*/ ){
+ switch( z[n] ){
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x20: {
+ n++;
+ break;
+ }
+ case '/': {
+ if( z[n+1]=='*' && z[n+2]!=0 ){
+ int j;
+ for(j=n+3; z[j]!='/' || z[j-1]!='*'; j++){
+ if( z[j]==0 ) goto whitespace_done;
+ }
+ n = j+1;
+ break;
+ }else if( z[n+1]=='/' ){
+ int j;
+ char c;
+ for(j=n+2; (c = z[j])!=0; j++){
+ if( c=='\n' || c=='\r' ) break;
+ if( 0xe2==(u8)c && 0x80==(u8)z[j+1]
+ && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2])
+ ){
+ j += 2;
+ break;
+ }
+ }
+ n = j;
+ if( z[n] ) n++;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xc2: {
+ if( z[n+1]==0xa0 ){
+ n += 2;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xe1: {
+ if( z[n+1]==0x9a && z[n+2]==0x80 ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xe2: {
+ if( z[n+1]==0x80 ){
+ u8 c = z[n+2];
+ if( c<0x80 ) goto whitespace_done;
+ if( c<=0x8a || c==0xa8 || c==0xa9 || c==0xaf ){
+ n += 3;
+ break;
+ }
+ }else if( z[n+1]==0x81 && z[n+2]==0x9f ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xe3: {
+ if( z[n+1]==0x80 && z[n+2]==0x80 ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ case 0xef: {
+ if( z[n+1]==0xbb && z[n+2]==0xbf ){
+ n += 3;
+ break;
+ }
+ goto whitespace_done;
+ }
+ default: {
+ goto whitespace_done;
+ }
+ }
+ }
+ whitespace_done:
+ return n;
}
/*
+** Extra floating-point literals to allow in JSON.
+*/
+static const struct NanInfName {
+ char c1;
+ char c2;
+ char n;
+ char eType;
+ char nRepl;
+ char *zMatch;
+ char *zRepl;
+} aNanInfName[] = {
+ { 'i', 'I', 3, JSON_REAL, 7, "inf", "9.0e999" },
+ { 'i', 'I', 8, JSON_REAL, 7, "infinity", "9.0e999" },
+ { 'n', 'N', 3, JSON_NULL, 4, "NaN", "null" },
+ { 'q', 'Q', 4, JSON_NULL, 4, "QNaN", "null" },
+ { 's', 'S', 4, JSON_NULL, 4, "SNaN", "null" },
+};
+
+/*
** Parse a single JSON value which begins at pParse->zJson[i]. Return the
** index of the first character past the end of the value parsed.
**
-** Return negative for a syntax error. Special cases: return -2 if the
-** first non-whitespace character is '}' and return -3 if the first
-** non-whitespace character is ']'.
+** Special return values:
+**
+** 0 End if input
+** -1 Syntax error
+** -2 '}' seen
+** -3 ']' seen
+** -4 ',' seen
+** -5 ':' seen
*/
static int jsonParseValue(JsonParse *pParse, u32 i){
char c;
@@ -199481,151 +200796,430 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
int x;
JsonNode *pNode;
const char *z = pParse->zJson;
- while( fast_isspace(z[i]) ){ i++; }
- if( (c = z[i])=='{' ){
+json_parse_restart:
+ switch( (u8)z[i] ){
+ case '{': {
/* Parse object */
iThis = jsonParseAddNode(pParse, JSON_OBJECT, 0, 0);
if( iThis<0 ) return -1;
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ){
+ pParse->iErr = i;
+ return -1;
+ }
for(j=i+1;;j++){
- while( fast_isspace(z[j]) ){ j++; }
- if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
+ u32 nNode = pParse->nNode;
x = jsonParseValue(pParse, j);
- if( x<0 ){
- pParse->iDepth--;
- if( x==(-2) && pParse->nNode==(u32)iThis+1 ) return j+1;
- return -1;
+ if( x<=0 ){
+ if( x==(-2) ){
+ j = pParse->iErr;
+ if( pParse->nNode!=(u32)iThis+1 ) pParse->hasNonstd = 1;
+ break;
+ }
+ j += json5Whitespace(&z[j]);
+ if( sqlite3JsonId1(z[j])
+ || (z[j]=='\\' && z[j+1]=='u' && jsonIs4Hex(&z[j+2]))
+ ){
+ int k = j+1;
+ while( (sqlite3JsonId2(z[k]) && json5Whitespace(&z[k])==0)
+ || (z[k]=='\\' && z[k+1]=='u' && jsonIs4Hex(&z[k+2]))
+ ){
+ k++;
+ }
+ jsonParseAddNode(pParse, JSON_STRING | (JNODE_RAW<<8), k-j, &z[j]);
+ pParse->hasNonstd = 1;
+ x = k;
+ }else{
+ if( x!=-1 ) pParse->iErr = j;
+ return -1;
+ }
}
if( pParse->oom ) return -1;
- pNode = &pParse->aNode[pParse->nNode-1];
- if( pNode->eType!=JSON_STRING ) return -1;
+ pNode = &pParse->aNode[nNode];
+ if( pNode->eType!=JSON_STRING ){
+ pParse->iErr = j;
+ return -1;
+ }
pNode->jnFlags |= JNODE_LABEL;
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- if( z[j]!=':' ) return -1;
- j++;
+ if( z[j]==':' ){
+ j++;
+ }else{
+ if( fast_isspace(z[j]) ){
+ do{ j++; }while( fast_isspace(z[j]) );
+ if( z[j]==':' ){
+ j++;
+ goto parse_object_value;
+ }
+ }
+ x = jsonParseValue(pParse, j);
+ if( x!=(-5) ){
+ if( x!=(-1) ) pParse->iErr = j;
+ return -1;
+ }
+ j = pParse->iErr+1;
+ }
+ parse_object_value:
x = jsonParseValue(pParse, j);
- pParse->iDepth--;
- if( x<0 ) return -1;
+ if( x<=0 ){
+ if( x!=(-1) ) pParse->iErr = j;
+ return -1;
+ }
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- c = z[j];
- if( c==',' ) continue;
- if( c!='}' ) return -1;
- break;
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]=='}' ){
+ break;
+ }else{
+ if( fast_isspace(z[j]) ){
+ do{ j++; }while( fast_isspace(z[j]) );
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]=='}' ){
+ break;
+ }
+ }
+ x = jsonParseValue(pParse, j);
+ if( x==(-4) ){
+ j = pParse->iErr;
+ continue;
+ }
+ if( x==(-2) ){
+ j = pParse->iErr;
+ break;
+ }
+ }
+ pParse->iErr = j;
+ return -1;
}
pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ pParse->iDepth--;
return j+1;
- }else if( c=='[' ){
+ }
+ case '[': {
/* Parse array */
iThis = jsonParseAddNode(pParse, JSON_ARRAY, 0, 0);
if( iThis<0 ) return -1;
+ if( ++pParse->iDepth > JSON_MAX_DEPTH ){
+ pParse->iErr = i;
+ return -1;
+ }
memset(&pParse->aNode[iThis].u, 0, sizeof(pParse->aNode[iThis].u));
for(j=i+1;;j++){
- while( fast_isspace(z[j]) ){ j++; }
- if( ++pParse->iDepth > JSON_MAX_DEPTH ) return -1;
x = jsonParseValue(pParse, j);
- pParse->iDepth--;
- if( x<0 ){
- if( x==(-3) && pParse->nNode==(u32)iThis+1 ) return j+1;
+ if( x<=0 ){
+ if( x==(-3) ){
+ j = pParse->iErr;
+ if( pParse->nNode!=(u32)iThis+1 ) pParse->hasNonstd = 1;
+ break;
+ }
+ if( x!=(-1) ) pParse->iErr = j;
return -1;
}
j = x;
- while( fast_isspace(z[j]) ){ j++; }
- c = z[j];
- if( c==',' ) continue;
- if( c!=']' ) return -1;
- break;
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]==']' ){
+ break;
+ }else{
+ if( fast_isspace(z[j]) ){
+ do{ j++; }while( fast_isspace(z[j]) );
+ if( z[j]==',' ){
+ continue;
+ }else if( z[j]==']' ){
+ break;
+ }
+ }
+ x = jsonParseValue(pParse, j);
+ if( x==(-4) ){
+ j = pParse->iErr;
+ continue;
+ }
+ if( x==(-3) ){
+ j = pParse->iErr;
+ break;
+ }
+ }
+ pParse->iErr = j;
+ return -1;
}
pParse->aNode[iThis].n = pParse->nNode - (u32)iThis - 1;
+ pParse->iDepth--;
return j+1;
- }else if( c=='"' ){
+ }
+ case '\'': {
+ u8 jnFlags;
+ char cDelim;
+ pParse->hasNonstd = 1;
+ jnFlags = JNODE_JSON5;
+ goto parse_string;
+ case '"':
/* Parse string */
- u8 jnFlags = 0;
+ jnFlags = 0;
+ parse_string:
+ cDelim = z[i];
j = i+1;
for(;;){
c = z[j];
if( (c & ~0x1f)==0 ){
/* Control characters are not allowed in strings */
+ pParse->iErr = j;
return -1;
}
if( c=='\\' ){
c = z[++j];
if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'
|| c=='n' || c=='r' || c=='t'
- || (c=='u' && jsonIs4Hex(z+j+1)) ){
- jnFlags = JNODE_ESCAPE;
+ || (c=='u' && jsonIs4Hex(&z[j+1])) ){
+ jnFlags |= JNODE_ESCAPE;
+ }else if( c=='\'' || c=='0' || c=='v' || c=='\n'
+ || (0xe2==(u8)c && 0x80==(u8)z[j+1]
+ && (0xa8==(u8)z[j+2] || 0xa9==(u8)z[j+2]))
+ || (c=='x' && jsonIs2Hex(&z[j+1])) ){
+ jnFlags |= (JNODE_ESCAPE|JNODE_JSON5);
+ pParse->hasNonstd = 1;
+ }else if( c=='\r' ){
+ if( z[j+1]=='\n' ) j++;
+ jnFlags |= (JNODE_ESCAPE|JNODE_JSON5);
+ pParse->hasNonstd = 1;
}else{
+ pParse->iErr = j;
return -1;
}
- }else if( c=='"' ){
+ }else if( c==cDelim ){
break;
}
j++;
}
- jsonParseAddNode(pParse, JSON_STRING, j+1-i, &z[i]);
- if( !pParse->oom ) pParse->aNode[pParse->nNode-1].jnFlags = jnFlags;
+ jsonParseAddNode(pParse, JSON_STRING | (jnFlags<<8), j+1-i, &z[i]);
return j+1;
- }else if( c=='n'
- && strncmp(z+i,"null",4)==0
- && !sqlite3Isalnum(z[i+4]) ){
- jsonParseAddNode(pParse, JSON_NULL, 0, 0);
- return i+4;
- }else if( c=='t'
- && strncmp(z+i,"true",4)==0
- && !sqlite3Isalnum(z[i+4]) ){
- jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
- return i+4;
- }else if( c=='f'
- && strncmp(z+i,"false",5)==0
- && !sqlite3Isalnum(z[i+5]) ){
- jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
- return i+5;
- }else if( c=='-' || (c>='0' && c<='9') ){
+ }
+ case 't': {
+ if( strncmp(z+i,"true",4)==0 && !sqlite3Isalnum(z[i+4]) ){
+ jsonParseAddNode(pParse, JSON_TRUE, 0, 0);
+ return i+4;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case 'f': {
+ if( strncmp(z+i,"false",5)==0 && !sqlite3Isalnum(z[i+5]) ){
+ jsonParseAddNode(pParse, JSON_FALSE, 0, 0);
+ return i+5;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case '+': {
+ u8 seenDP, seenE, jnFlags;
+ pParse->hasNonstd = 1;
+ jnFlags = JNODE_JSON5;
+ goto parse_number;
+ case '.':
+ if( sqlite3Isdigit(z[i+1]) ){
+ pParse->hasNonstd = 1;
+ jnFlags = JNODE_JSON5;
+ seenE = 0;
+ seenDP = JSON_REAL;
+ goto parse_number_2;
+ }
+ pParse->iErr = i;
+ return -1;
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
/* Parse number */
- u8 seenDP = 0;
- u8 seenE = 0;
+ jnFlags = 0;
+ parse_number:
+ seenDP = JSON_INT;
+ seenE = 0;
assert( '-' < '0' );
+ assert( '+' < '0' );
+ assert( '.' < '0' );
+ c = z[i];
+
if( c<='0' ){
- j = c=='-' ? i+1 : i;
- if( z[j]=='0' && z[j+1]>='0' && z[j+1]<='9' ) return -1;
+ if( c=='0' ){
+ if( (z[i+1]=='x' || z[i+1]=='X') && sqlite3Isxdigit(z[i+2]) ){
+ assert( seenDP==JSON_INT );
+ pParse->hasNonstd = 1;
+ jnFlags |= JNODE_JSON5;
+ for(j=i+3; sqlite3Isxdigit(z[j]); j++){}
+ goto parse_number_finish;
+ }else if( sqlite3Isdigit(z[i+1]) ){
+ pParse->iErr = i+1;
+ return -1;
+ }
+ }else{
+ if( !sqlite3Isdigit(z[i+1]) ){
+ /* JSON5 allows for "+Infinity" and "-Infinity" using exactly
+ ** that case. SQLite also allows these in any case and it allows
+ ** "+inf" and "-inf". */
+ if( (z[i+1]=='I' || z[i+1]=='i')
+ && sqlite3StrNICmp(&z[i+1], "inf",3)==0
+ ){
+ pParse->hasNonstd = 1;
+ if( z[i]=='-' ){
+ jsonParseAddNode(pParse, JSON_REAL, 8, "-9.0e999");
+ }else{
+ jsonParseAddNode(pParse, JSON_REAL, 7, "9.0e999");
+ }
+ return i + (sqlite3StrNICmp(&z[i+4],"inity",5)==0 ? 9 : 4);
+ }
+ if( z[i+1]=='.' ){
+ pParse->hasNonstd = 1;
+ jnFlags |= JNODE_JSON5;
+ goto parse_number_2;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ if( z[i+1]=='0' ){
+ if( sqlite3Isdigit(z[i+2]) ){
+ pParse->iErr = i+1;
+ return -1;
+ }else if( (z[i+2]=='x' || z[i+2]=='X') && sqlite3Isxdigit(z[i+3]) ){
+ pParse->hasNonstd = 1;
+ jnFlags |= JNODE_JSON5;
+ for(j=i+4; sqlite3Isxdigit(z[j]); j++){}
+ goto parse_number_finish;
+ }
+ }
+ }
}
- j = i+1;
- for(;; j++){
+ parse_number_2:
+ for(j=i+1;; j++){
c = z[j];
- if( c>='0' && c<='9' ) continue;
+ if( sqlite3Isdigit(c) ) continue;
if( c=='.' ){
- if( z[j-1]=='-' ) return -1;
- if( seenDP ) return -1;
- seenDP = 1;
+ if( seenDP==JSON_REAL ){
+ pParse->iErr = j;
+ return -1;
+ }
+ seenDP = JSON_REAL;
continue;
}
if( c=='e' || c=='E' ){
- if( z[j-1]<'0' ) return -1;
- if( seenE ) return -1;
- seenDP = seenE = 1;
+ if( z[j-1]<'0' ){
+ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
+ pParse->hasNonstd = 1;
+ jnFlags |= JNODE_JSON5;
+ }else{
+ pParse->iErr = j;
+ return -1;
+ }
+ }
+ if( seenE ){
+ pParse->iErr = j;
+ return -1;
+ }
+ seenDP = JSON_REAL;
+ seenE = 1;
c = z[j+1];
if( c=='+' || c=='-' ){
j++;
c = z[j+1];
}
- if( c<'0' || c>'9' ) return -1;
+ if( c<'0' || c>'9' ){
+ pParse->iErr = j;
+ return -1;
+ }
continue;
}
break;
}
- if( z[j-1]<'0' ) return -1;
- jsonParseAddNode(pParse, seenDP ? JSON_REAL : JSON_INT,
- j - i, &z[i]);
+ if( z[j-1]<'0' ){
+ if( ALWAYS(z[j-1]=='.') && ALWAYS(j-2>=i) && sqlite3Isdigit(z[j-2]) ){
+ pParse->hasNonstd = 1;
+ jnFlags |= JNODE_JSON5;
+ }else{
+ pParse->iErr = j;
+ return -1;
+ }
+ }
+ parse_number_finish:
+ jsonParseAddNode(pParse, seenDP | (jnFlags<<8), j - i, &z[i]);
return j;
- }else if( c=='}' ){
+ }
+ case '}': {
+ pParse->iErr = i;
return -2; /* End of {...} */
- }else if( c==']' ){
+ }
+ case ']': {
+ pParse->iErr = i;
return -3; /* End of [...] */
- }else if( c==0 ){
+ }
+ case ',': {
+ pParse->iErr = i;
+ return -4; /* List separator */
+ }
+ case ':': {
+ pParse->iErr = i;
+ return -5; /* Object label/value separator */
+ }
+ case 0: {
return 0; /* End of file */
- }else{
+ }
+ case 0x09:
+ case 0x0a:
+ case 0x0d:
+ case 0x20: {
+ do{
+ i++;
+ }while( fast_isspace(z[i]) );
+ goto json_parse_restart;
+ }
+ case 0x0b:
+ case 0x0c:
+ case '/':
+ case 0xc2:
+ case 0xe1:
+ case 0xe2:
+ case 0xe3:
+ case 0xef: {
+ j = json5Whitespace(&z[i]);
+ if( j>0 ){
+ i += j;
+ pParse->hasNonstd = 1;
+ goto json_parse_restart;
+ }
+ pParse->iErr = i;
+ return -1;
+ }
+ case 'n': {
+ if( strncmp(z+i,"null",4)==0 && !sqlite3Isalnum(z[i+4]) ){
+ jsonParseAddNode(pParse, JSON_NULL, 0, 0);
+ return i+4;
+ }
+ /* fall-through into the default case that checks for NaN */
+ }
+ default: {
+ u32 k;
+ int nn;
+ c = z[i];
+ for(k=0; k<sizeof(aNanInfName)/sizeof(aNanInfName[0]); k++){
+ if( c!=aNanInfName[k].c1 && c!=aNanInfName[k].c2 ) continue;
+ nn = aNanInfName[k].n;
+ if( sqlite3StrNICmp(&z[i], aNanInfName[k].zMatch, nn)!=0 ){
+ continue;
+ }
+ if( sqlite3Isalnum(z[i+nn]) ) continue;
+ jsonParseAddNode(pParse, aNanInfName[k].eType,
+ aNanInfName[k].nRepl, aNanInfName[k].zRepl);
+ pParse->hasNonstd = 1;
+ return i + nn;
+ }
+ pParse->iErr = i;
return -1; /* Syntax error */
}
+ } /* End switch(z[i]) */
}
/*
@@ -199649,7 +201243,14 @@ static int jsonParse(
if( i>0 ){
assert( pParse->iDepth==0 );
while( fast_isspace(zJson[i]) ) i++;
- if( zJson[i] ) i = -1;
+ if( zJson[i] ){
+ i += json5Whitespace(&zJson[i]);
+ if( zJson[i] ){
+ jsonParseReset(pParse);
+ return 1;
+ }
+ pParse->hasNonstd = 1;
+ }
}
if( i<=0 ){
if( pCtx!=0 ){
@@ -199720,6 +201321,15 @@ static int jsonParseFindParents(JsonParse *pParse){
** is no longer valid, parse the JSON again and return the new parse,
** and also register the new parse so that it will be available for
** future sqlite3_get_auxdata() calls.
+**
+** If an error occurs and pErrCtx!=0 then report the error on pErrCtx
+** and return NULL.
+**
+** If an error occurs and pErrCtx==0 then return the Parse object with
+** JsonParse.nErr non-zero. If the caller invokes this routine with
+** pErrCtx==0 and it gets back a JsonParse with nErr!=0, then the caller
+** is responsible for invoking jsonParseFree() on the returned value.
+** But the caller may invoke jsonParseFree() *only* if pParse->nErr!=0.
*/
static JsonParse *jsonParseCached(
sqlite3_context *pCtx,
@@ -199769,6 +201379,10 @@ static JsonParse *jsonParseCached(
p->zJson = (char*)&p[1];
memcpy((char*)p->zJson, zJson, nJson+1);
if( jsonParse(p, pErrCtx, p->zJson) ){
+ if( pErrCtx==0 ){
+ p->nErr = 1;
+ return p;
+ }
sqlite3_free(p);
return 0;
}
@@ -199783,7 +201397,7 @@ static JsonParse *jsonParseCached(
** Compare the OBJECT label at pNode against zKey,nKey. Return true on
** a match.
*/
-static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
+static int jsonLabelCompare(const JsonNode *pNode, const char *zKey, u32 nKey){
assert( pNode->eU==1 );
if( pNode->jnFlags & JNODE_RAW ){
if( pNode->n!=nKey ) return 0;
@@ -199793,6 +201407,15 @@ static int jsonLabelCompare(JsonNode *pNode, const char *zKey, u32 nKey){
return strncmp(pNode->u.zJContent+1, zKey, nKey)==0;
}
}
+static int jsonSameLabel(const JsonNode *p1, const JsonNode *p2){
+ if( p1->jnFlags & JNODE_RAW ){
+ return jsonLabelCompare(p2, p1->u.zJContent, p1->n);
+ }else if( p2->jnFlags & JNODE_RAW ){
+ return jsonLabelCompare(p1, p2->u.zJContent, p2->n);
+ }else{
+ return p1->n==p2->n && strncmp(p1->u.zJContent,p2->u.zJContent,p1->n)==0;
+ }
+}
/* forward declaration */
static JsonNode *jsonLookupAppend(JsonParse*,const char*,int*,const char**);
@@ -200263,7 +201886,7 @@ static void jsonExtractFunc(
zPath = (const char*)sqlite3_value_text(argv[1]);
if( zPath==0 ) return;
if( flags & JSON_ABPATH ){
- if( zPath[0]!='$' ){
+ if( zPath[0]!='$' || (zPath[1]!='.' && zPath[1]!='[' && zPath[1]!=0) ){
/* The -> and ->> operators accept abbreviated PATH arguments. This
** is mostly for compatibility with PostgreSQL, but also for
** convenience.
@@ -200354,12 +201977,10 @@ static JsonNode *jsonMergePatch(
assert( pPatch[i].eU==1 );
nKey = pPatch[i].n;
zKey = pPatch[i].u.zJContent;
- assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
for(j=1; j<pTarget->n; j += jsonNodeSize(&pTarget[j+1])+1 ){
assert( pTarget[j].eType==JSON_STRING );
assert( pTarget[j].jnFlags & JNODE_LABEL );
- assert( (pPatch[i].jnFlags & JNODE_RAW)==0 );
- if( pTarget[j].n==nKey && strncmp(pTarget[j].u.zJContent,zKey,nKey)==0 ){
+ if( jsonSameLabel(&pPatch[i], &pTarget[j]) ){
if( pTarget[j+1].jnFlags & (JNODE_REMOVE|JNODE_PATCH) ) break;
if( pPatch[i+1].eType==JSON_NULL ){
pTarget[j+1].jnFlags |= JNODE_REMOVE;
@@ -200646,8 +202267,8 @@ static void jsonTypeFunc(
/*
** json_valid(JSON)
**
-** Return 1 if JSON is a well-formed JSON string according to RFC-7159.
-** Return 0 otherwise.
+** Return 1 if JSON is a well-formed canonical JSON string according
+** to RFC-7159. Return 0 otherwise.
*/
static void jsonValidFunc(
sqlite3_context *ctx,
@@ -200656,8 +202277,69 @@ static void jsonValidFunc(
){
JsonParse *p; /* The parse */
UNUSED_PARAMETER(argc);
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
+ p = jsonParseCached(ctx, argv, 0);
+ if( p==0 || p->oom ){
+ sqlite3_result_error_nomem(ctx);
+ sqlite3_free(p);
+ }else{
+ sqlite3_result_int(ctx, p->nErr==0 && p->hasNonstd==0);
+ if( p->nErr ) jsonParseFree(p);
+ }
+}
+
+/*
+** json_error_position(JSON)
+**
+** If the argument is not an interpretable JSON string, then return the 1-based
+** character position at which the parser first recognized that the input
+** was in error. The left-most character is 1. If the string is valid
+** JSON, then return 0.
+**
+** Note that json_valid() is only true for strictly conforming canonical JSON.
+** But this routine returns zero if the input contains extension. Thus:
+**
+** (1) If the input X is strictly conforming canonical JSON:
+**
+** json_valid(X) returns true
+** json_error_position(X) returns 0
+**
+** (2) If the input X is JSON but it includes extension (such as JSON5) that
+** are not part of RFC-8259:
+**
+** json_valid(X) returns false
+** json_error_position(X) return 0
+**
+** (3) If the input X cannot be interpreted as JSON even taking extensions
+** into account:
+**
+** json_valid(X) return false
+** json_error_position(X) returns 1 or more
+*/
+static void jsonErrorFunc(
+ sqlite3_context *ctx,
+ int argc,
+ sqlite3_value **argv
+){
+ JsonParse *p; /* The parse */
+ UNUSED_PARAMETER(argc);
+ if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return;
p = jsonParseCached(ctx, argv, 0);
- sqlite3_result_int(ctx, p!=0);
+ if( p==0 || p->oom ){
+ sqlite3_result_error_nomem(ctx);
+ sqlite3_free(p);
+ }else if( p->nErr==0 ){
+ sqlite3_result_int(ctx, 0);
+ }else{
+ int n = 1;
+ u32 i;
+ const char *z = p->zJson;
+ for(i=0; i<p->iErr && ALWAYS(z[i]); i++){
+ if( (z[i]&0xc0)!=0x80 ) n++;
+ }
+ sqlite3_result_int(ctx, n);
+ jsonParseFree(p);
+ }
}
@@ -201001,14 +202683,16 @@ static void jsonAppendObjectPathElement(
assert( pNode->eU==1 );
z = pNode->u.zJContent;
nn = pNode->n;
- assert( nn>=2 );
- assert( z[0]=='"' );
- assert( z[nn-1]=='"' );
- if( nn>2 && sqlite3Isalpha(z[1]) ){
- for(jj=2; jj<nn-1 && sqlite3Isalnum(z[jj]); jj++){}
- if( jj==nn-1 ){
- z++;
- nn -= 2;
+ if( (pNode->jnFlags & JNODE_RAW)==0 ){
+ assert( nn>=2 );
+ assert( z[0]=='"' || z[0]=='\'' );
+ assert( z[nn-1]=='"' || z[0]=='\'' );
+ if( nn>2 && sqlite3Isalpha(z[1]) ){
+ for(jj=2; jj<nn-1 && sqlite3Isalnum(z[jj]); jj++){}
+ if( jj==nn-1 ){
+ z++;
+ nn -= 2;
+ }
}
}
jsonPrintf(nn+2, pStr, ".%.*s", nn, z);
@@ -201368,6 +203052,7 @@ SQLITE_PRIVATE void sqlite3RegisterJsonFunctions(void){
JFUNCTION(json_array, -1, 0, jsonArrayFunc),
JFUNCTION(json_array_length, 1, 0, jsonArrayLengthFunc),
JFUNCTION(json_array_length, 2, 0, jsonArrayLengthFunc),
+ JFUNCTION(json_error_position,1, 0, jsonErrorFunc),
JFUNCTION(json_extract, -1, 0, jsonExtractFunc),
JFUNCTION(->, 2, JSON_JSON, jsonExtractFunc),
JFUNCTION(->>, 2, JSON_SQL, jsonExtractFunc),
@@ -201892,16 +203577,17 @@ struct RtreeMatchArg {
** at run-time.
*/
#ifndef SQLITE_BYTEORDER
-#if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
- defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
- defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
- defined(__arm__)
-# define SQLITE_BYTEORDER 1234
-#elif defined(sparc) || defined(__ppc__)
-# define SQLITE_BYTEORDER 4321
-#else
-# define SQLITE_BYTEORDER 0 /* 0 means "unknown at compile-time" */
-#endif
+# if defined(i386) || defined(__i386__) || defined(_M_IX86) || \
+ defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \
+ defined(_M_AMD64) || defined(_M_ARM) || defined(__x86) || \
+ defined(__ARMEL__) || defined(__AARCH64EL__) || defined(_M_ARM64)
+# define SQLITE_BYTEORDER 1234
+# elif defined(sparc) || defined(__ppc__) || \
+ defined(__ARMEB__) || defined(__AARCH64EB__)
+# define SQLITE_BYTEORDER 4321
+# else
+# define SQLITE_BYTEORDER 0
+# endif
#endif
@@ -212446,6 +214132,11 @@ static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){
p->rc = pDb->pMethods->xWrite(pDb, p->aBuf, p->pgsz, iOff);
}
+/*
+** This value is copied from the definition of ZIPVFS_CTRL_FILE_POINTER
+** in zipvfs.h.
+*/
+#define RBU_ZIPVFS_CTRL_FILE_POINTER 230439
/*
** Take an EXCLUSIVE lock on the database file. Return SQLITE_OK if
@@ -212454,9 +214145,20 @@ static void rbuCheckpointFrame(sqlite3rbu *p, RbuFrame *pFrame){
static int rbuLockDatabase(sqlite3 *db){
int rc = SQLITE_OK;
sqlite3_file *fd = 0;
- sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
- if( fd->pMethods ){
+ sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd);
+ if( fd ){
+ sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
+ rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED);
+ if( rc==SQLITE_OK ){
+ rc = fd->pMethods->xUnlock(fd, SQLITE_LOCK_NONE);
+ }
+ sqlite3_file_control(db, "main", RBU_ZIPVFS_CTRL_FILE_POINTER, &fd);
+ }else{
+ sqlite3_file_control(db, "main", SQLITE_FCNTL_FILE_POINTER, &fd);
+ }
+
+ if( rc==SQLITE_OK && fd->pMethods ){
rc = fd->pMethods->xLock(fd, SQLITE_LOCK_SHARED);
if( rc==SQLITE_OK ){
rc = fd->pMethods->xLock(fd, SQLITE_LOCK_EXCLUSIVE);
@@ -215693,6 +217395,7 @@ static int dbpageConnect(
(void)pzErr;
sqlite3_vtab_config(db, SQLITE_VTAB_DIRECTONLY);
+ sqlite3_vtab_config(db, SQLITE_VTAB_USES_ALL_SCHEMAS);
rc = sqlite3_declare_vtab(db,
"CREATE TABLE x(pgno INTEGER PRIMARY KEY, data BLOB, schema HIDDEN)");
if( rc==SQLITE_OK ){
@@ -215776,7 +217479,6 @@ static int dbpageBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
){
pIdxInfo->orderByConsumed = 1;
}
- sqlite3VtabUsesAllSchemas(pIdxInfo);
return SQLITE_OK;
}
@@ -216077,6 +217779,8 @@ typedef struct SessionInput SessionInput;
# endif
#endif
+#define SESSIONS_ROWID "_rowid_"
+
static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE;
typedef struct SessionHook SessionHook;
@@ -216098,6 +217802,7 @@ struct sqlite3_session {
int bEnable; /* True if currently recording */
int bIndirect; /* True if all changes are indirect */
int bAutoAttach; /* True to auto-attach tables */
+ int bImplicitPK; /* True to handle tables with implicit PK */
int rc; /* Non-zero if an error has occurred */
void *pFilterCtx; /* First argument to pass to xTableFilter */
int (*xTableFilter)(void *pCtx, const char *zTab);
@@ -216174,6 +217879,7 @@ struct SessionTable {
char *zName; /* Local name of table */
int nCol; /* Number of columns in table zName */
int bStat1; /* True if this is sqlite_stat1 */
+ int bRowid; /* True if this table uses rowid for PK */
const char **azCol; /* Column names */
u8 *abPK; /* Array of primary key flags */
int nEntry; /* Total number of entries in hash table */
@@ -216566,6 +218272,7 @@ static unsigned int sessionHashAppendType(unsigned int h, int eType){
*/
static int sessionPreupdateHash(
sqlite3_session *pSession, /* Session object that owns pTab */
+ i64 iRowid,
SessionTable *pTab, /* Session table handle */
int bNew, /* True to hash the new.* PK */
int *piHash, /* OUT: Hash value */
@@ -216574,48 +218281,53 @@ static int sessionPreupdateHash(
unsigned int h = 0; /* Hash value to return */
int i; /* Used to iterate through columns */
- assert( *pbNullPK==0 );
- assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
- for(i=0; i<pTab->nCol; i++){
- if( pTab->abPK[i] ){
- int rc;
- int eType;
- sqlite3_value *pVal;
-
- if( bNew ){
- rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
- }else{
- rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
- }
- if( rc!=SQLITE_OK ) return rc;
+ if( pTab->bRowid ){
+ assert( pTab->nCol-1==pSession->hook.xCount(pSession->hook.pCtx) );
+ h = sessionHashAppendI64(h, iRowid);
+ }else{
+ assert( *pbNullPK==0 );
+ assert( pTab->nCol==pSession->hook.xCount(pSession->hook.pCtx) );
+ for(i=0; i<pTab->nCol; i++){
+ if( pTab->abPK[i] ){
+ int rc;
+ int eType;
+ sqlite3_value *pVal;
- eType = sqlite3_value_type(pVal);
- h = sessionHashAppendType(h, eType);
- if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
- i64 iVal;
- if( eType==SQLITE_INTEGER ){
- iVal = sqlite3_value_int64(pVal);
+ if( bNew ){
+ rc = pSession->hook.xNew(pSession->hook.pCtx, i, &pVal);
}else{
- double rVal = sqlite3_value_double(pVal);
- assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
- memcpy(&iVal, &rVal, 8);
+ rc = pSession->hook.xOld(pSession->hook.pCtx, i, &pVal);
}
- h = sessionHashAppendI64(h, iVal);
- }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
- const u8 *z;
- int n;
- if( eType==SQLITE_TEXT ){
- z = (const u8 *)sqlite3_value_text(pVal);
+ if( rc!=SQLITE_OK ) return rc;
+
+ eType = sqlite3_value_type(pVal);
+ h = sessionHashAppendType(h, eType);
+ if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
+ i64 iVal;
+ if( eType==SQLITE_INTEGER ){
+ iVal = sqlite3_value_int64(pVal);
+ }else{
+ double rVal = sqlite3_value_double(pVal);
+ assert( sizeof(iVal)==8 && sizeof(rVal)==8 );
+ memcpy(&iVal, &rVal, 8);
+ }
+ h = sessionHashAppendI64(h, iVal);
+ }else if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
+ const u8 *z;
+ int n;
+ if( eType==SQLITE_TEXT ){
+ z = (const u8 *)sqlite3_value_text(pVal);
+ }else{
+ z = (const u8 *)sqlite3_value_blob(pVal);
+ }
+ n = sqlite3_value_bytes(pVal);
+ if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
+ h = sessionHashAppendBlob(h, n, z);
}else{
- z = (const u8 *)sqlite3_value_blob(pVal);
+ assert( eType==SQLITE_NULL );
+ assert( pTab->bStat1==0 || i!=1 );
+ *pbNullPK = 1;
}
- n = sqlite3_value_bytes(pVal);
- if( !z && (eType!=SQLITE_BLOB || n>0) ) return SQLITE_NOMEM;
- h = sessionHashAppendBlob(h, n, z);
- }else{
- assert( eType==SQLITE_NULL );
- assert( pTab->bStat1==0 || i!=1 );
- *pbNullPK = 1;
}
}
}
@@ -216898,6 +218610,7 @@ static int sessionMergeUpdate(
*/
static int sessionPreupdateEqual(
sqlite3_session *pSession, /* Session object that owns SessionTable */
+ i64 iRowid, /* Rowid value if pTab->bRowid */
SessionTable *pTab, /* Table associated with change */
SessionChange *pChange, /* Change to compare to */
int op /* Current pre-update operation */
@@ -216905,6 +218618,11 @@ static int sessionPreupdateEqual(
int iCol; /* Used to iterate through columns */
u8 *a = pChange->aRecord; /* Cursor used to scan change record */
+ if( pTab->bRowid ){
+ if( a[0]!=SQLITE_INTEGER ) return 0;
+ return sessionGetI64(&a[1])==iRowid;
+ }
+
assert( op==SQLITE_INSERT || op==SQLITE_UPDATE || op==SQLITE_DELETE );
for(iCol=0; iCol<pTab->nCol; iCol++){
if( !pTab->abPK[iCol] ){
@@ -217049,7 +218767,8 @@ static int sessionTableInfo(
int *pnCol, /* OUT: number of columns */
const char **pzTab, /* OUT: Copy of zThis */
const char ***pazCol, /* OUT: Array of column names for table */
- u8 **pabPK /* OUT: Array of booleans - true for PK col */
+ u8 **pabPK, /* OUT: Array of booleans - true for PK col */
+ int *pbRowid /* OUT: True if only PK is a rowid */
){
char *zPragma;
sqlite3_stmt *pStmt;
@@ -217061,6 +218780,7 @@ static int sessionTableInfo(
u8 *pAlloc = 0;
char **azCol = 0;
u8 *abPK = 0;
+ int bRowid = 0; /* Set to true to use rowid as PK */
assert( pazCol && pabPK );
@@ -217105,10 +218825,15 @@ static int sessionTableInfo(
}
nByte = nThis + 1;
+ bRowid = (pbRowid!=0);
while( SQLITE_ROW==sqlite3_step(pStmt) ){
nByte += sqlite3_column_bytes(pStmt, 1);
nDbCol++;
+ if( sqlite3_column_int(pStmt, 5) ) bRowid = 0;
}
+ if( nDbCol==0 ) bRowid = 0;
+ nDbCol += bRowid;
+ nByte += strlen(SESSIONS_ROWID);
rc = sqlite3_reset(pStmt);
if( rc==SQLITE_OK ){
@@ -217130,6 +218855,14 @@ static int sessionTableInfo(
}
i = 0;
+ if( bRowid ){
+ size_t nName = strlen(SESSIONS_ROWID);
+ memcpy(pAlloc, SESSIONS_ROWID, nName+1);
+ azCol[i] = (char*)pAlloc;
+ pAlloc += nName+1;
+ abPK[i] = 1;
+ i++;
+ }
while( SQLITE_ROW==sqlite3_step(pStmt) ){
int nName = sqlite3_column_bytes(pStmt, 1);
const unsigned char *zName = sqlite3_column_text(pStmt, 1);
@@ -217141,7 +218874,6 @@ static int sessionTableInfo(
i++;
}
rc = sqlite3_reset(pStmt);
-
}
/* If successful, populate the output variables. Otherwise, zero them and
@@ -217158,6 +218890,7 @@ static int sessionTableInfo(
if( pzTab ) *pzTab = 0;
sessionFree(pSession, azCol);
}
+ if( pbRowid ) *pbRowid = bRowid;
sqlite3_finalize(pStmt);
return rc;
}
@@ -217179,7 +218912,8 @@ static int sessionInitTable(sqlite3_session *pSession, SessionTable *pTab){
u8 *abPK;
assert( pTab->azCol==0 || pTab->abPK==0 );
pSession->rc = sessionTableInfo(pSession, pSession->db, pSession->zDb,
- pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK
+ pTab->zName, &pTab->nCol, 0, &pTab->azCol, &abPK,
+ (pSession->bImplicitPK ? &pTab->bRowid : 0)
);
if( pSession->rc==SQLITE_OK ){
int i;
@@ -217251,6 +218985,7 @@ static int sessionUpdateMaxSize(
){
i64 nNew = 2;
if( pC->op==SQLITE_INSERT ){
+ if( pTab->bRowid ) nNew += 9;
if( op!=SQLITE_DELETE ){
int ii;
for(ii=0; ii<pTab->nCol; ii++){
@@ -217267,12 +219002,16 @@ static int sessionUpdateMaxSize(
}else{
int ii;
u8 *pCsr = pC->aRecord;
- for(ii=0; ii<pTab->nCol; ii++){
+ if( pTab->bRowid ){
+ nNew += 9 + 1;
+ pCsr += 9;
+ }
+ for(ii=pTab->bRowid; ii<pTab->nCol; ii++){
int bChanged = 1;
int nOld = 0;
int eType;
sqlite3_value *p = 0;
- pSession->hook.xNew(pSession->hook.pCtx, ii, &p);
+ pSession->hook.xNew(pSession->hook.pCtx, ii-pTab->bRowid, &p);
if( p==0 ){
return SQLITE_NOMEM;
}
@@ -217351,6 +219090,7 @@ static int sessionUpdateMaxSize(
*/
static void sessionPreupdateOneChange(
int op, /* One of SQLITE_UPDATE, INSERT, DELETE */
+ i64 iRowid,
sqlite3_session *pSession, /* Session object pTab is attached to */
SessionTable *pTab /* Table that change applies to */
){
@@ -217366,7 +219106,7 @@ static void sessionPreupdateOneChange(
/* Check the number of columns in this xPreUpdate call matches the
** number of columns in the table. */
- if( pTab->nCol!=pSession->hook.xCount(pSession->hook.pCtx) ){
+ if( (pTab->nCol-pTab->bRowid)!=pSession->hook.xCount(pSession->hook.pCtx) ){
pSession->rc = SQLITE_SCHEMA;
return;
}
@@ -217399,14 +219139,16 @@ static void sessionPreupdateOneChange(
/* Calculate the hash-key for this change. If the primary key of the row
** includes a NULL value, exit early. Such changes are ignored by the
** session module. */
- rc = sessionPreupdateHash(pSession, pTab, op==SQLITE_INSERT, &iHash, &bNull);
+ rc = sessionPreupdateHash(
+ pSession, iRowid, pTab, op==SQLITE_INSERT, &iHash, &bNull
+ );
if( rc!=SQLITE_OK ) goto error_out;
if( bNull==0 ){
/* Search the hash table for an existing record for this row. */
SessionChange *pC;
for(pC=pTab->apChange[iHash]; pC; pC=pC->pNext){
- if( sessionPreupdateEqual(pSession, pTab, pC, op) ) break;
+ if( sessionPreupdateEqual(pSession, iRowid, pTab, pC, op) ) break;
}
if( pC==0 ){
@@ -217421,7 +219163,7 @@ static void sessionPreupdateOneChange(
/* Figure out how large an allocation is required */
nByte = sizeof(SessionChange);
- for(i=0; i<pTab->nCol; i++){
+ for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
TESTONLY(int trc = ) pSession->hook.xOld(pSession->hook.pCtx, i, &p);
@@ -217436,6 +219178,9 @@ static void sessionPreupdateOneChange(
rc = sessionSerializeValue(0, p, &nByte);
if( rc!=SQLITE_OK ) goto error_out;
}
+ if( pTab->bRowid ){
+ nByte += 9; /* Size of rowid field - an integer */
+ }
/* Allocate the change object */
pC = (SessionChange *)sessionMalloc64(pSession, nByte);
@@ -217452,7 +219197,12 @@ static void sessionPreupdateOneChange(
** required values and encodings have already been cached in memory.
** It is not possible for an OOM to occur in this block. */
nByte = 0;
- for(i=0; i<pTab->nCol; i++){
+ if( pTab->bRowid ){
+ pC->aRecord[0] = SQLITE_INTEGER;
+ sessionPutI64(&pC->aRecord[1], iRowid);
+ nByte = 9;
+ }
+ for(i=0; i<(pTab->nCol-pTab->bRowid); i++){
sqlite3_value *p = 0;
if( op!=SQLITE_INSERT ){
pSession->hook.xOld(pSession->hook.pCtx, i, &p);
@@ -217567,9 +219317,10 @@ static void xPreUpdate(
pSession->rc = sessionFindTable(pSession, zName, &pTab);
if( pTab ){
assert( pSession->rc==SQLITE_OK );
- sessionPreupdateOneChange(op, pSession, pTab);
+ assert( op==SQLITE_UPDATE || iKey1==iKey2 );
+ sessionPreupdateOneChange(op, iKey1, pSession, pTab);
if( op==SQLITE_UPDATE ){
- sessionPreupdateOneChange(SQLITE_INSERT, pSession, pTab);
+ sessionPreupdateOneChange(SQLITE_INSERT, iKey2, pSession, pTab);
}
}
}
@@ -217608,6 +219359,7 @@ static void sessionPreupdateHooks(
typedef struct SessionDiffCtx SessionDiffCtx;
struct SessionDiffCtx {
sqlite3_stmt *pStmt;
+ int bRowid;
int nOldOff;
};
@@ -217616,17 +219368,17 @@ struct SessionDiffCtx {
*/
static int sessionDiffOld(void *pCtx, int iVal, sqlite3_value **ppVal){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff);
+ *ppVal = sqlite3_column_value(p->pStmt, iVal+p->nOldOff+p->bRowid);
return SQLITE_OK;
}
static int sessionDiffNew(void *pCtx, int iVal, sqlite3_value **ppVal){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- *ppVal = sqlite3_column_value(p->pStmt, iVal);
+ *ppVal = sqlite3_column_value(p->pStmt, iVal+p->bRowid);
return SQLITE_OK;
}
static int sessionDiffCount(void *pCtx){
SessionDiffCtx *p = (SessionDiffCtx*)pCtx;
- return p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt);
+ return (p->nOldOff ? p->nOldOff : sqlite3_column_count(p->pStmt)) - p->bRowid;
}
static int sessionDiffDepth(void *pCtx){
(void)pCtx;
@@ -217705,14 +219457,16 @@ static char *sessionExprCompareOther(
static char *sessionSelectFindNew(
const char *zDb1, /* Pick rows in this db only */
const char *zDb2, /* But not in this one */
+ int bRowid,
const char *zTbl, /* Table name */
const char *zExpr
){
+ const char *zSel = (bRowid ? SESSIONS_ROWID ", *" : "*");
char *zRet = sqlite3_mprintf(
- "SELECT * FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
+ "SELECT %s FROM \"%w\".\"%w\" WHERE NOT EXISTS ("
" SELECT 1 FROM \"%w\".\"%w\" WHERE %s"
")",
- zDb1, zTbl, zDb2, zTbl, zExpr
+ zSel, zDb1, zTbl, zDb2, zTbl, zExpr
);
return zRet;
}
@@ -217726,7 +219480,9 @@ static int sessionDiffFindNew(
char *zExpr
){
int rc = SQLITE_OK;
- char *zStmt = sessionSelectFindNew(zDb1, zDb2, pTab->zName,zExpr);
+ char *zStmt = sessionSelectFindNew(
+ zDb1, zDb2, pTab->bRowid, pTab->zName, zExpr
+ );
if( zStmt==0 ){
rc = SQLITE_NOMEM;
@@ -217737,8 +219493,10 @@ static int sessionDiffFindNew(
SessionDiffCtx *pDiffCtx = (SessionDiffCtx*)pSession->hook.pCtx;
pDiffCtx->pStmt = pStmt;
pDiffCtx->nOldOff = 0;
+ pDiffCtx->bRowid = pTab->bRowid;
while( SQLITE_ROW==sqlite3_step(pStmt) ){
- sessionPreupdateOneChange(op, pSession, pTab);
+ i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0);
+ sessionPreupdateOneChange(op, iRowid, pSession, pTab);
}
rc = sqlite3_finalize(pStmt);
}
@@ -217748,6 +219506,27 @@ static int sessionDiffFindNew(
return rc;
}
+/*
+** Return a comma-separated list of the fully-qualified (with both database
+** and table name) column names from table pTab. e.g.
+**
+** "main"."t1"."a", "main"."t1"."b", "main"."t1"."c"
+*/
+static char *sessionAllCols(
+ const char *zDb,
+ SessionTable *pTab
+){
+ int ii;
+ char *zRet = 0;
+ for(ii=0; ii<pTab->nCol; ii++){
+ zRet = sqlite3_mprintf("%z%s\"%w\".\"%w\".\"%w\"",
+ zRet, (zRet ? ", " : ""), zDb, pTab->zName, pTab->azCol[ii]
+ );
+ if( !zRet ) break;
+ }
+ return zRet;
+}
+
static int sessionDiffFindModified(
sqlite3_session *pSession,
SessionTable *pTab,
@@ -217762,11 +219541,13 @@ static int sessionDiffFindModified(
if( zExpr2==0 ){
rc = SQLITE_NOMEM;
}else{
+ char *z1 = sessionAllCols(pSession->zDb, pTab);
+ char *z2 = sessionAllCols(zFrom, pTab);
char *zStmt = sqlite3_mprintf(
- "SELECT * FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
- pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
+ "SELECT %s,%s FROM \"%w\".\"%w\", \"%w\".\"%w\" WHERE %s AND (%z)",
+ z1, z2, pSession->zDb, pTab->zName, zFrom, pTab->zName, zExpr, zExpr2
);
- if( zStmt==0 ){
+ if( zStmt==0 || z1==0 || z2==0 ){
rc = SQLITE_NOMEM;
}else{
sqlite3_stmt *pStmt;
@@ -217777,12 +219558,15 @@ static int sessionDiffFindModified(
pDiffCtx->pStmt = pStmt;
pDiffCtx->nOldOff = pTab->nCol;
while( SQLITE_ROW==sqlite3_step(pStmt) ){
- sessionPreupdateOneChange(SQLITE_UPDATE, pSession, pTab);
+ i64 iRowid = (pTab->bRowid ? sqlite3_column_int64(pStmt, 0) : 0);
+ sessionPreupdateOneChange(SQLITE_UPDATE, iRowid, pSession, pTab);
}
rc = sqlite3_finalize(pStmt);
}
- sqlite3_free(zStmt);
}
+ sqlite3_free(zStmt);
+ sqlite3_free(z1);
+ sqlite3_free(z2);
}
return rc;
@@ -217821,9 +219605,12 @@ SQLITE_API int sqlite3session_diff(
int bHasPk = 0;
int bMismatch = 0;
int nCol; /* Columns in zFrom.zTbl */
+ int bRowid = 0;
u8 *abPK;
const char **azCol = 0;
- rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK);
+ rc = sessionTableInfo(0, db, zFrom, zTbl, &nCol, 0, &azCol, &abPK,
+ pSession->bImplicitPK ? &bRowid : 0
+ );
if( rc==SQLITE_OK ){
if( pTo->nCol!=nCol ){
bMismatch = 1;
@@ -218165,9 +219952,10 @@ static void sessionAppendStr(
int *pRc
){
int nStr = sqlite3Strlen30(zStr);
- if( 0==sessionBufferGrow(p, nStr, pRc) ){
+ if( 0==sessionBufferGrow(p, nStr+1, pRc) ){
memcpy(&p->aBuf[p->nBuf], zStr, nStr);
p->nBuf += nStr;
+ p->aBuf[p->nBuf] = 0x00;
}
}
@@ -218189,6 +219977,27 @@ static void sessionAppendInteger(
sessionAppendStr(p, aBuf, pRc);
}
+static void sessionAppendPrintf(
+ SessionBuffer *p, /* Buffer to append to */
+ int *pRc,
+ const char *zFmt,
+ ...
+){
+ if( *pRc==SQLITE_OK ){
+ char *zApp = 0;
+ va_list ap;
+ va_start(ap, zFmt);
+ zApp = sqlite3_vmprintf(zFmt, ap);
+ if( zApp==0 ){
+ *pRc = SQLITE_NOMEM;
+ }else{
+ sessionAppendStr(p, zApp, pRc);
+ }
+ va_end(ap);
+ sqlite3_free(zApp);
+ }
+}
+
/*
** This function is a no-op if *pRc is other than SQLITE_OK when it is
** called. Otherwise, append the string zStr enclosed in quotes (") and
@@ -218203,7 +220012,7 @@ static void sessionAppendIdent(
const char *zStr, /* String to quote, escape and append */
int *pRc /* IN/OUT: Error code */
){
- int nStr = sqlite3Strlen30(zStr)*2 + 2 + 1;
+ int nStr = sqlite3Strlen30(zStr)*2 + 2 + 2;
if( 0==sessionBufferGrow(p, nStr, pRc) ){
char *zOut = (char *)&p->aBuf[p->nBuf];
const char *zIn = zStr;
@@ -218214,6 +220023,7 @@ static void sessionAppendIdent(
}
*zOut++ = '"';
p->nBuf = (int)((u8 *)zOut - p->aBuf);
+ p->aBuf[p->nBuf] = 0x00;
}
}
@@ -218349,7 +220159,7 @@ static int sessionAppendUpdate(
/* If at least one field has been modified, this is not a no-op. */
if( bChanged ) bNoop = 0;
- /* Add a field to the old.* record. This is omitted if this modules is
+ /* Add a field to the old.* record. This is omitted if this module is
** currently generating a patchset. */
if( bPatchset==0 ){
if( bChanged || abPK[i] ){
@@ -218438,12 +220248,20 @@ static int sessionAppendDelete(
** Formulate and prepare a SELECT statement to retrieve a row from table
** zTab in database zDb based on its primary key. i.e.
**
-** SELECT * FROM zDb.zTab WHERE pk1 = ? AND pk2 = ? AND ...
+** SELECT *, <noop-test> FROM zDb.zTab WHERE (pk1, pk2,...) IS (?1, ?2,...)
+**
+** where <noop-test> is:
+**
+** 1 AND (?A OR ?1 IS <column>) AND ...
+**
+** for each non-pk <column>.
*/
static int sessionSelectStmt(
sqlite3 *db, /* Database handle */
+ int bIgnoreNoop,
const char *zDb, /* Database name */
const char *zTab, /* Table name */
+ int bRowid,
int nCol, /* Number of columns in table */
const char **azCol, /* Names of table columns */
u8 *abPK, /* PRIMARY KEY array */
@@ -218451,16 +220269,57 @@ static int sessionSelectStmt(
){
int rc = SQLITE_OK;
char *zSql = 0;
+ const char *zSep = "";
+ const char *zCols = bRowid ? SESSIONS_ROWID ", *" : "*";
int nSql = -1;
+ int i;
+
+ SessionBuffer nooptest = {0, 0, 0};
+ SessionBuffer pkfield = {0, 0, 0};
+ SessionBuffer pkvar = {0, 0, 0};
+
+ sessionAppendStr(&nooptest, ", 1", &rc);
if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
+ sessionAppendStr(&nooptest, " AND (?6 OR ?3 IS stat)", &rc);
+ sessionAppendStr(&pkfield, "tbl, idx", &rc);
+ sessionAppendStr(&pkvar,
+ "?1, (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", &rc
+ );
+ zCols = "tbl, ?2, stat";
+ }else{
+ for(i=0; i<nCol; i++){
+ if( abPK[i] ){
+ sessionAppendStr(&pkfield, zSep, &rc);
+ sessionAppendStr(&pkvar, zSep, &rc);
+ zSep = ", ";
+ sessionAppendIdent(&pkfield, azCol[i], &rc);
+ sessionAppendPrintf(&pkvar, &rc, "?%d", i+1);
+ }else{
+ sessionAppendPrintf(&nooptest, &rc,
+ " AND (?%d OR ?%d IS %w.%w)", i+1+nCol, i+1, zTab, azCol[i]
+ );
+ }
+ }
+ }
+
+ if( rc==SQLITE_OK ){
+ zSql = sqlite3_mprintf(
+ "SELECT %s%s FROM %Q.%Q WHERE (%s) IS (%s)",
+ zCols, (bIgnoreNoop ? (char*)nooptest.aBuf : ""),
+ zDb, zTab, (char*)pkfield.aBuf, (char*)pkvar.aBuf
+ );
+ if( zSql==0 ) rc = SQLITE_NOMEM;
+ }
+
+#if 0
+ if( 0==sqlite3_stricmp("sqlite_stat1", zTab) ){
zSql = sqlite3_mprintf(
"SELECT tbl, ?2, stat FROM %Q.sqlite_stat1 WHERE tbl IS ?1 AND "
"idx IS (CASE WHEN ?2=X'' THEN NULL ELSE ?2 END)", zDb
);
if( zSql==0 ) rc = SQLITE_NOMEM;
}else{
- int i;
const char *zSep = "";
SessionBuffer buf = {0, 0, 0};
@@ -218481,11 +220340,15 @@ static int sessionSelectStmt(
zSql = (char*)buf.aBuf;
nSql = buf.nBuf;
}
+#endif
if( rc==SQLITE_OK ){
rc = sqlite3_prepare_v2(db, zSql, nSql, ppStmt, 0);
}
sqlite3_free(zSql);
+ sqlite3_free(nooptest.aBuf);
+ sqlite3_free(pkfield.aBuf);
+ sqlite3_free(pkvar.aBuf);
return rc;
}
@@ -218632,10 +220495,18 @@ static int sessionGenerateChangeset(
sqlite3_stmt *pSel = 0; /* SELECT statement to query table pTab */
int nRewind = buf.nBuf; /* Initial size of write buffer */
int nNoop; /* Size of buffer after writing tbl header */
+ int bRowid = 0;
/* Check the table schema is still Ok. */
- rc = sessionTableInfo(0, db, pSession->zDb, zName, &nCol, 0,&azCol,&abPK);
- if( !rc && (pTab->nCol!=nCol || memcmp(abPK, pTab->abPK, nCol)) ){
+ rc = sessionTableInfo(
+ 0, db, pSession->zDb, zName, &nCol, 0, &azCol, &abPK,
+ (pSession->bImplicitPK ? &bRowid : 0)
+ );
+ if( rc==SQLITE_OK && (
+ pTab->nCol!=nCol
+ || pTab->bRowid!=bRowid
+ || memcmp(abPK, pTab->abPK, nCol)
+ )){
rc = SQLITE_SCHEMA;
}
@@ -218645,7 +220516,8 @@ static int sessionGenerateChangeset(
/* Build and compile a statement to execute: */
if( rc==SQLITE_OK ){
rc = sessionSelectStmt(
- db, pSession->zDb, zName, nCol, azCol, abPK, &pSel);
+ db, 0, pSession->zDb, zName, bRowid, nCol, azCol, abPK, &pSel
+ );
}
nNoop = buf.nBuf;
@@ -218728,7 +220600,7 @@ SQLITE_API int sqlite3session_changeset(
int rc;
if( pnChangeset==0 || ppChangeset==0 ) return SQLITE_MISUSE;
- rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset,ppChangeset);
+ rc = sessionGenerateChangeset(pSession, 0, 0, 0, pnChangeset, ppChangeset);
assert( rc || pnChangeset==0
|| pSession->bEnableSize==0 || *pnChangeset<=pSession->nMaxChangesetSize
);
@@ -218846,6 +220718,19 @@ SQLITE_API int sqlite3session_object_config(sqlite3_session *pSession, int op, v
break;
}
+ case SQLITE_SESSION_OBJCONFIG_ROWID: {
+ int iArg = *(int*)pArg;
+ if( iArg>=0 ){
+ if( pSession->pTable ){
+ rc = SQLITE_MISUSE;
+ }else{
+ pSession->bImplicitPK = (iArg!=0);
+ }
+ }
+ *(int*)pArg = pSession->bImplicitPK;
+ break;
+ }
+
default:
rc = SQLITE_MISUSE;
}
@@ -219834,6 +221719,8 @@ struct SessionApplyCtx {
SessionBuffer rebase; /* Rebase information (if any) here */
u8 bRebaseStarted; /* If table header is already in rebase */
u8 bRebase; /* True to collect rebase information */
+ u8 bIgnoreNoop; /* True to ignore no-op conflicts */
+ int bRowid;
};
/* Number of prepared UPDATE statements to cache. */
@@ -220084,8 +221971,10 @@ static int sessionSelectRow(
const char *zTab, /* Table name */
SessionApplyCtx *p /* Session changeset-apply context */
){
- return sessionSelectStmt(
- db, "main", zTab, p->nCol, p->azCol, p->abPK, &p->pSelect);
+ /* TODO */
+ return sessionSelectStmt(db, p->bIgnoreNoop,
+ "main", zTab, p->bRowid, p->nCol, p->azCol, p->abPK, &p->pSelect
+ );
}
/*
@@ -220244,20 +222133,33 @@ static int sessionBindRow(
*/
static int sessionSeekToRow(
sqlite3_changeset_iter *pIter, /* Changeset iterator */
- u8 *abPK, /* Primary key flags array */
- sqlite3_stmt *pSelect /* SELECT statement from sessionSelectRow() */
+ SessionApplyCtx *p
){
+ sqlite3_stmt *pSelect = p->pSelect;
int rc; /* Return code */
int nCol; /* Number of columns in table */
int op; /* Changset operation (SQLITE_UPDATE etc.) */
const char *zDummy; /* Unused */
+ sqlite3_clear_bindings(pSelect);
sqlite3changeset_op(pIter, &zDummy, &nCol, &op, 0);
rc = sessionBindRow(pIter,
op==SQLITE_INSERT ? sqlite3changeset_new : sqlite3changeset_old,
- nCol, abPK, pSelect
+ nCol, p->abPK, pSelect
);
+ if( op!=SQLITE_DELETE && p->bIgnoreNoop ){
+ int ii;
+ for(ii=0; rc==SQLITE_OK && ii<nCol; ii++){
+ if( p->abPK[ii]==0 ){
+ sqlite3_value *pVal = 0;
+ sqlite3changeset_new(pIter, ii, &pVal);
+ sqlite3_bind_int(pSelect, ii+1+nCol, (pVal==0));
+ if( pVal ) rc = sessionBindValue(pSelect, ii+1, pVal);
+ }
+ }
+ }
+
if( rc==SQLITE_OK ){
rc = sqlite3_step(pSelect);
if( rc!=SQLITE_ROW ) rc = sqlite3_reset(pSelect);
@@ -220372,16 +222274,22 @@ static int sessionConflictHandler(
/* Bind the new.* PRIMARY KEY values to the SELECT statement. */
if( pbReplace ){
- rc = sessionSeekToRow(pIter, p->abPK, p->pSelect);
+ rc = sessionSeekToRow(pIter, p);
}else{
rc = SQLITE_OK;
}
if( rc==SQLITE_ROW ){
/* There exists another row with the new.* primary key. */
- pIter->pConflict = p->pSelect;
- res = xConflict(pCtx, eType, pIter);
- pIter->pConflict = 0;
+ if( p->bIgnoreNoop
+ && sqlite3_column_int(p->pSelect, sqlite3_column_count(p->pSelect)-1)
+ ){
+ res = SQLITE_CHANGESET_OMIT;
+ }else{
+ pIter->pConflict = p->pSelect;
+ res = xConflict(pCtx, eType, pIter);
+ pIter->pConflict = 0;
+ }
rc = sqlite3_reset(p->pSelect);
}else if( rc==SQLITE_OK ){
if( p->bDeferConstraints && eType==SQLITE_CHANGESET_CONFLICT ){
@@ -220489,7 +222397,7 @@ static int sessionApplyOneOp(
sqlite3_step(p->pDelete);
rc = sqlite3_reset(p->pDelete);
- if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 ){
+ if( rc==SQLITE_OK && sqlite3_changes(p->db)==0 && p->bIgnoreNoop==0 ){
rc = sessionConflictHandler(
SQLITE_CHANGESET_DATA, p, pIter, xConflict, pCtx, pbRetry
);
@@ -220546,7 +222454,7 @@ static int sessionApplyOneOp(
/* Check if there is a conflicting row. For sqlite_stat1, this needs
** to be done using a SELECT, as there is no PRIMARY KEY in the
** database schema to throw an exception if a duplicate is inserted. */
- rc = sessionSeekToRow(pIter, p->abPK, p->pSelect);
+ rc = sessionSeekToRow(pIter, p);
if( rc==SQLITE_ROW ){
rc = SQLITE_CONSTRAINT;
sqlite3_reset(p->pSelect);
@@ -220723,6 +222631,7 @@ static int sessionChangesetApply(
memset(&sApply, 0, sizeof(sApply));
sApply.bRebase = (ppRebase && pnRebase);
sApply.bInvertConstraints = !!(flags & SQLITE_CHANGESETAPPLY_INVERT);
+ sApply.bIgnoreNoop = !!(flags & SQLITE_CHANGESETAPPLY_IGNORENOOP);
sqlite3_mutex_enter(sqlite3_db_mutex(db));
if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){
rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0);
@@ -220760,6 +222669,7 @@ static int sessionChangesetApply(
sApply.bStat1 = 0;
sApply.bDeferConstraints = 1;
sApply.bRebaseStarted = 0;
+ sApply.bRowid = 0;
memset(&sApply.constraints, 0, sizeof(SessionBuffer));
/* If an xFilter() callback was specified, invoke it now. If the
@@ -220779,8 +222689,8 @@ static int sessionChangesetApply(
int i;
sqlite3changeset_pk(pIter, &abPK, 0);
- rc = sessionTableInfo(0,
- db, "main", zNew, &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK
+ rc = sessionTableInfo(0, db, "main", zNew,
+ &sApply.nCol, &zTab, &sApply.azCol, &sApply.abPK, &sApply.bRowid
);
if( rc!=SQLITE_OK ) break;
for(i=0; i<sApply.nCol; i++){
@@ -222662,6 +224572,7 @@ struct Fts5Config {
int ePattern; /* FTS_PATTERN_XXX constant */
/* Values loaded from the %_config table */
+ int iVersion; /* fts5 file format 'version' */
int iCookie; /* Incremented when %_config is modified */
int pgsz; /* Approximate page size used in %_data */
int nAutomerge; /* 'automerge' setting */
@@ -222670,6 +224581,7 @@ struct Fts5Config {
int nHashSize; /* Bytes of memory for in-memory hash */
char *zRank; /* Name of rank function */
char *zRankArgs; /* Arguments to rank function */
+ int bSecureDelete; /* 'secure-delete' */
/* If non-NULL, points to sqlite3_vtab.base.zErrmsg. Often NULL. */
char **pzErrmsg;
@@ -222679,8 +224591,11 @@ struct Fts5Config {
#endif
};
-/* Current expected value of %_config table 'version' field */
-#define FTS5_CURRENT_VERSION 4
+/* Current expected value of %_config table 'version' field. And
+** the expected version if the 'secure-delete' option has ever been
+** set on the table. */
+#define FTS5_CURRENT_VERSION 4
+#define FTS5_CURRENT_VERSION_SECUREDELETE 5
#define FTS5_CONTENT_NORMAL 0
#define FTS5_CONTENT_NONE 1
@@ -222846,6 +224761,7 @@ struct Fts5IndexIter {
** above. */
#define FTS5INDEX_QUERY_SKIPEMPTY 0x0010
#define FTS5INDEX_QUERY_NOOUTPUT 0x0020
+#define FTS5INDEX_QUERY_SKIPHASH 0x0040
/*
** Create/destroy an Fts5Index object.
@@ -223000,7 +224916,7 @@ static int sqlite3Fts5GetVarintLen(u32 iVal);
static u8 sqlite3Fts5GetVarint(const unsigned char*, u64*);
static int sqlite3Fts5PutVarint(unsigned char *p, u64 v);
-#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&b)
+#define fts5GetVarint32(a,b) sqlite3Fts5GetVarint32(a,(u32*)&(b))
#define fts5GetVarint sqlite3Fts5GetVarint
#define fts5FastGetVarint32(a, iOff, nVal) { \
@@ -224979,7 +226895,7 @@ static int fts5HighlightCb(
if( tflags & FTS5_TOKEN_COLOCATED ) return SQLITE_OK;
iPos = p->iPos++;
- if( p->iRangeEnd>0 ){
+ if( p->iRangeEnd>=0 ){
if( iPos<p->iRangeStart || iPos>p->iRangeEnd ) return SQLITE_OK;
if( p->iRangeStart && iPos==p->iRangeStart ) p->iOff = iStartOff;
}
@@ -224991,7 +226907,7 @@ static int fts5HighlightCb(
}
if( iPos==p->iter.iEnd ){
- if( p->iRangeEnd && p->iter.iStart<p->iRangeStart ){
+ if( p->iRangeEnd>=0 && p->iter.iStart<p->iRangeStart ){
fts5HighlightAppend(&rc, p, p->zOpen, -1);
}
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
@@ -225002,7 +226918,7 @@ static int fts5HighlightCb(
}
}
- if( p->iRangeEnd>0 && iPos==p->iRangeEnd ){
+ if( p->iRangeEnd>=0 && iPos==p->iRangeEnd ){
fts5HighlightAppend(&rc, p, &p->zIn[p->iOff], iEndOff - p->iOff);
p->iOff = iEndOff;
if( iPos>=p->iter.iStart && iPos<p->iter.iEnd ){
@@ -225037,6 +226953,7 @@ static void fts5HighlightFunction(
memset(&ctx, 0, sizeof(HighlightContext));
ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]);
ctx.zClose = (const char*)sqlite3_value_text(apVal[2]);
+ ctx.iRangeEnd = -1;
rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn);
if( ctx.zIn ){
@@ -225222,6 +227139,7 @@ static void fts5SnippetFunction(
iCol = sqlite3_value_int(apVal[0]);
ctx.zOpen = fts5ValueToText(apVal[1]);
ctx.zClose = fts5ValueToText(apVal[2]);
+ ctx.iRangeEnd = -1;
zEllips = fts5ValueToText(apVal[3]);
nToken = sqlite3_value_int(apVal[4]);
@@ -226490,6 +228408,7 @@ static int sqlite3Fts5ConfigParse(
rc = SQLITE_ERROR;
}
+ assert( (pRet->abUnindexed && pRet->azCol) || rc!=SQLITE_OK );
for(i=3; rc==SQLITE_OK && i<nArg; i++){
const char *zOrig = azArg[i];
const char *z;
@@ -226843,6 +228762,18 @@ static int sqlite3Fts5ConfigSetValue(
rc = SQLITE_OK;
*pbBadkey = 1;
}
+ }
+
+ else if( 0==sqlite3_stricmp(zKey, "secure-delete") ){
+ int bVal = -1;
+ if( SQLITE_INTEGER==sqlite3_value_numeric_type(pVal) ){
+ bVal = sqlite3_value_int(pVal);
+ }
+ if( bVal<0 ){
+ *pbBadkey = 1;
+ }else{
+ pConfig->bSecureDelete = (bVal ? 1 : 0);
+ }
}else{
*pbBadkey = 1;
}
@@ -226887,15 +228818,20 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
rc = sqlite3_finalize(p);
}
- if( rc==SQLITE_OK && iVersion!=FTS5_CURRENT_VERSION ){
+ if( rc==SQLITE_OK
+ && iVersion!=FTS5_CURRENT_VERSION
+ && iVersion!=FTS5_CURRENT_VERSION_SECUREDELETE
+ ){
rc = SQLITE_ERROR;
if( pConfig->pzErrmsg ){
assert( 0==*pConfig->pzErrmsg );
- *pConfig->pzErrmsg = sqlite3_mprintf(
- "invalid fts5 file format (found %d, expected %d) - run 'rebuild'",
- iVersion, FTS5_CURRENT_VERSION
+ *pConfig->pzErrmsg = sqlite3_mprintf("invalid fts5 file format "
+ "(found %d, expected %d or %d) - run 'rebuild'",
+ iVersion, FTS5_CURRENT_VERSION, FTS5_CURRENT_VERSION_SECUREDELETE
);
}
+ }else{
+ pConfig->iVersion = iVersion;
}
if( rc==SQLITE_OK ){
@@ -226923,6 +228859,10 @@ static int sqlite3Fts5ConfigLoad(Fts5Config *pConfig, int iCookie){
/* #include "fts5Int.h" */
/* #include "fts5parse.h" */
+#ifndef SQLITE_FTS5_MAX_EXPR_DEPTH
+# define SQLITE_FTS5_MAX_EXPR_DEPTH 256
+#endif
+
/*
** All token types in the generated fts5parse.h file are greater than 0.
*/
@@ -226963,11 +228903,17 @@ struct Fts5Expr {
** FTS5_NOT (nChild, apChild valid)
** FTS5_STRING (pNear valid)
** FTS5_TERM (pNear valid)
+**
+** iHeight:
+** Distance from this node to furthest leaf. This is always 0 for nodes
+** of type FTS5_STRING and FTS5_TERM. For all other nodes it is one
+** greater than the largest child value.
*/
struct Fts5ExprNode {
int eType; /* Node type */
int bEof; /* True at EOF */
int bNomatch; /* True if entry is not a match */
+ int iHeight; /* Distance to tree leaf nodes */
/* Next method for this node. */
int (*xNext)(Fts5Expr*, Fts5ExprNode*, int, i64);
@@ -227037,6 +228983,31 @@ struct Fts5Parse {
int bPhraseToAnd; /* Convert "a+b" to "a AND b" */
};
+/*
+** Check that the Fts5ExprNode.iHeight variables are set correctly in
+** the expression tree passed as the only argument.
+*/
+#ifndef NDEBUG
+static void assert_expr_depth_ok(int rc, Fts5ExprNode *p){
+ if( rc==SQLITE_OK ){
+ if( p->eType==FTS5_TERM || p->eType==FTS5_STRING || p->eType==0 ){
+ assert( p->iHeight==0 );
+ }else{
+ int ii;
+ int iMaxChild = 0;
+ for(ii=0; ii<p->nChild; ii++){
+ Fts5ExprNode *pChild = p->apChild[ii];
+ iMaxChild = MAX(iMaxChild, pChild->iHeight);
+ assert_expr_depth_ok(SQLITE_OK, pChild);
+ }
+ assert( p->iHeight==iMaxChild+1 );
+ }
+ }
+}
+#else
+# define assert_expr_depth_ok(rc, p)
+#endif
+
static void sqlite3Fts5ParseError(Fts5Parse *pParse, const char *zFmt, ...){
va_list ap;
va_start(ap, zFmt);
@@ -227151,6 +229122,8 @@ static int sqlite3Fts5ExprNew(
}while( sParse.rc==SQLITE_OK && t!=FTS5_EOF );
sqlite3Fts5ParserFree(pEngine, fts5ParseFree);
+ assert_expr_depth_ok(sParse.rc, sParse.pExpr);
+
/* If the LHS of the MATCH expression was a user column, apply the
** implicit column-filter. */
if( iCol<pConfig->nCol && sParse.pExpr && sParse.rc==SQLITE_OK ){
@@ -227313,7 +229286,7 @@ static int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
Fts5Parse sParse;
memset(&sParse, 0, sizeof(sParse));
- if( *pp1 ){
+ if( *pp1 && p2 ){
Fts5Expr *p1 = *pp1;
int nPhrase = p1->nPhrase + p2->nPhrase;
@@ -227338,7 +229311,7 @@ static int sqlite3Fts5ExprAnd(Fts5Expr **pp1, Fts5Expr *p2){
}
sqlite3_free(p2->apExprPhrase);
sqlite3_free(p2);
- }else{
+ }else if( p2 ){
*pp1 = p2;
}
@@ -229112,6 +231085,7 @@ static void fts5ExprAssignXNext(Fts5ExprNode *pNode){
}
static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
+ int ii = p->nChild;
if( p->eType!=FTS5_NOT && pSub->eType==p->eType ){
int nByte = sizeof(Fts5ExprNode*) * pSub->nChild;
memcpy(&p->apChild[p->nChild], pSub->apChild, nByte);
@@ -229120,6 +231094,9 @@ static void fts5ExprAddChildren(Fts5ExprNode *p, Fts5ExprNode *pSub){
}else{
p->apChild[p->nChild++] = pSub;
}
+ for( ; ii<p->nChild; ii++){
+ p->iHeight = MAX(p->iHeight, p->apChild[ii]->iHeight + 1);
+ }
}
/*
@@ -229150,6 +231127,7 @@ static Fts5ExprNode *fts5ParsePhraseToAnd(
if( pRet ){
pRet->eType = FTS5_AND;
pRet->nChild = nTerm;
+ pRet->iHeight = 1;
fts5ExprAssignXNext(pRet);
pParse->nPhrase--;
for(ii=0; ii<nTerm; ii++){
@@ -229255,6 +231233,14 @@ static Fts5ExprNode *sqlite3Fts5ParseNode(
}else{
fts5ExprAddChildren(pRet, pLeft);
fts5ExprAddChildren(pRet, pRight);
+ if( pRet->iHeight>SQLITE_FTS5_MAX_EXPR_DEPTH ){
+ sqlite3Fts5ParseError(pParse,
+ "fts5 expression tree is too large (maximum depth %d)",
+ SQLITE_FTS5_MAX_EXPR_DEPTH
+ );
+ sqlite3_free(pRet);
+ pRet = 0;
+ }
}
}
}
@@ -230855,6 +232841,8 @@ struct Fts5Index {
sqlite3_stmt *pIdxSelect;
int nRead; /* Total number of blocks read */
+ sqlite3_stmt *pDeleteFromIdx;
+
sqlite3_stmt *pDataVersion;
i64 iStructVersion; /* data_version when pStruct read */
Fts5Structure *pStruct; /* Current db structure (or NULL) */
@@ -230947,9 +232935,6 @@ struct Fts5CResult {
** iLeafOffset:
** Byte offset within the current leaf that is the first byte of the
** position list data (one byte passed the position-list size field).
-** rowid field of the current entry. Usually this is the size field of the
-** position list data. The exception is if the rowid for the current entry
-** is the last thing on the leaf page.
**
** pLeaf:
** Buffer containing current leaf page data. Set to NULL at EOF.
@@ -231508,6 +233493,7 @@ static int fts5StructureDecode(
rc = FTS5_CORRUPT;
break;
}
+ assert( pSeg!=0 );
i += fts5GetVarint32(&pData[i], pSeg->iSegid);
i += fts5GetVarint32(&pData[i], pSeg->pgnoFirst);
i += fts5GetVarint32(&pData[i], pSeg->pgnoLast);
@@ -231538,6 +233524,7 @@ static int fts5StructureDecode(
*/
static void fts5StructureAddLevel(int *pRc, Fts5Structure **ppStruct){
fts5StructureMakeWritable(pRc, ppStruct);
+ assert( (ppStruct!=0 && (*ppStruct)!=0) || (*pRc)!=SQLITE_OK );
if( *pRc==SQLITE_OK ){
Fts5Structure *pStruct = *ppStruct;
int nLevel = pStruct->nLevel;
@@ -231996,42 +233983,25 @@ static int fts5DlidxLvlPrev(Fts5DlidxLvl *pLvl){
pLvl->bEof = 1;
}else{
u8 *a = pLvl->pData->p;
- i64 iVal;
- int iLimit;
- int ii;
- int nZero = 0;
-
- /* Currently iOff points to the first byte of a varint. This block
- ** decrements iOff until it points to the first byte of the previous
- ** varint. Taking care not to read any memory locations that occur
- ** before the buffer in memory. */
- iLimit = (iOff>9 ? iOff-9 : 0);
- for(iOff--; iOff>iLimit; iOff--){
- if( (a[iOff-1] & 0x80)==0 ) break;
- }
-
- fts5GetVarint(&a[iOff], (u64*)&iVal);
- pLvl->iRowid -= iVal;
- pLvl->iLeafPgno--;
-
- /* Skip backwards past any 0x00 varints. */
- for(ii=iOff-1; ii>=pLvl->iFirstOff && a[ii]==0x00; ii--){
- nZero++;
- }
- if( ii>=pLvl->iFirstOff && (a[ii] & 0x80) ){
- /* The byte immediately before the last 0x00 byte has the 0x80 bit
- ** set. So the last 0x00 is only a varint 0 if there are 8 more 0x80
- ** bytes before a[ii]. */
- int bZero = 0; /* True if last 0x00 counts */
- if( (ii-8)>=pLvl->iFirstOff ){
- int j;
- for(j=1; j<=8 && (a[ii-j] & 0x80); j++);
- bZero = (j>8);
+
+ pLvl->iOff = 0;
+ fts5DlidxLvlNext(pLvl);
+ while( 1 ){
+ int nZero = 0;
+ int ii = pLvl->iOff;
+ u64 delta = 0;
+
+ while( a[ii]==0 ){
+ nZero++;
+ ii++;
}
- if( bZero==0 ) nZero--;
+ ii += sqlite3Fts5GetVarint(&a[ii], &delta);
+
+ if( ii>=iOff ) break;
+ pLvl->iLeafPgno += nZero+1;
+ pLvl->iRowid += delta;
+ pLvl->iOff = ii;
}
- pLvl->iLeafPgno -= nZero;
- pLvl->iOff = iOff - nZero;
}
return pLvl->bEof;
@@ -232227,7 +234197,7 @@ static void fts5SegIterLoadRowid(Fts5Index *p, Fts5SegIter *pIter){
i64 iOff = pIter->iLeafOffset;
ASSERT_SZLEAF_OK(pIter->pLeaf);
- if( iOff>=pIter->pLeaf->szLeaf ){
+ while( iOff>=pIter->pLeaf->szLeaf ){
fts5SegIterNextPage(p, pIter);
if( pIter->pLeaf==0 ){
if( p->rc==SQLITE_OK ) p->rc = FTS5_CORRUPT;
@@ -232326,10 +234296,12 @@ static void fts5SegIterInit(
fts5SegIterSetNext(p, pIter);
pIter->pSeg = pSeg;
pIter->iLeafPgno = pSeg->pgnoFirst-1;
- fts5SegIterNextPage(p, pIter);
+ do {
+ fts5SegIterNextPage(p, pIter);
+ }while( p->rc==SQLITE_OK && pIter->pLeaf && pIter->pLeaf->nn==4 );
}
- if( p->rc==SQLITE_OK ){
+ if( p->rc==SQLITE_OK && pIter->pLeaf ){
pIter->iLeafOffset = 4;
assert( pIter->pLeaf!=0 );
assert_nc( pIter->pLeaf->nn>4 );
@@ -232523,7 +234495,7 @@ static void fts5SegIterNext_None(
iOff = pIter->iLeafOffset;
/* Next entry is on the next page */
- if( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
+ while( pIter->pSeg && iOff>=pIter->pLeaf->szLeaf ){
fts5SegIterNextPage(p, pIter);
if( p->rc || pIter->pLeaf==0 ) return;
pIter->iRowid = 0;
@@ -232716,7 +234688,7 @@ static void fts5SegIterReverse(Fts5Index *p, Fts5SegIter *pIter){
Fts5Data *pLast = 0;
int pgnoLast = 0;
- if( pDlidx ){
+ if( pDlidx && p->pConfig->iVersion==FTS5_CURRENT_VERSION ){
int iSegid = pIter->pSeg->iSegid;
pgnoLast = fts5DlidxIterPgno(pDlidx);
pLast = fts5LeafRead(p, FTS5_SEGMENT_ROWID(iSegid, pgnoLast));
@@ -233277,7 +235249,8 @@ static int fts5MultiIterDoCompare(Fts5Iter *pIter, int iOut){
/*
** Move the seg-iter so that it points to the first rowid on page iLeafPgno.
-** It is an error if leaf iLeafPgno does not exist or contains no rowids.
+** It is an error if leaf iLeafPgno does not exist. Unless the db is
+** a 'secure-delete' db, if it contains no rowids then this is also an error.
*/
static void fts5SegIterGotoPage(
Fts5Index *p, /* FTS5 backend object */
@@ -233292,21 +235265,23 @@ static void fts5SegIterGotoPage(
fts5DataRelease(pIter->pNextLeaf);
pIter->pNextLeaf = 0;
pIter->iLeafPgno = iLeafPgno-1;
- fts5SegIterNextPage(p, pIter);
- assert( p->rc!=SQLITE_OK || pIter->iLeafPgno==iLeafPgno );
- if( p->rc==SQLITE_OK && ALWAYS(pIter->pLeaf!=0) ){
+ while( p->rc==SQLITE_OK ){
int iOff;
- u8 *a = pIter->pLeaf->p;
- int n = pIter->pLeaf->szLeaf;
-
+ fts5SegIterNextPage(p, pIter);
+ if( pIter->pLeaf==0 ) break;
iOff = fts5LeafFirstRowidOff(pIter->pLeaf);
- if( iOff<4 || iOff>=n ){
- p->rc = FTS5_CORRUPT;
- }else{
- iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
- pIter->iLeafOffset = iOff;
- fts5SegIterLoadNPos(p, pIter);
+ if( iOff>0 ){
+ u8 *a = pIter->pLeaf->p;
+ int n = pIter->pLeaf->szLeaf;
+ if( iOff<4 || iOff>=n ){
+ p->rc = FTS5_CORRUPT;
+ }else{
+ iOff += fts5GetVarint(&a[iOff], (u64*)&pIter->iRowid);
+ pIter->iLeafOffset = iOff;
+ fts5SegIterLoadNPos(p, pIter);
+ }
+ break;
}
}
}
@@ -234021,7 +235996,7 @@ static void fts5MultiIterNew(
if( iLevel<0 ){
assert( pStruct->nSegment==fts5StructureCountSegments(pStruct) );
nSeg = pStruct->nSegment;
- nSeg += (p->pHash ? 1 : 0);
+ nSeg += (p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH));
}else{
nSeg = MIN(pStruct->aLevel[iLevel].nSeg, nSegment);
}
@@ -234042,7 +236017,7 @@ static void fts5MultiIterNew(
if( p->rc==SQLITE_OK ){
if( iLevel<0 ){
Fts5StructureLevel *pEnd = &pStruct->aLevel[pStruct->nLevel];
- if( p->pHash ){
+ if( p->pHash && 0==(flags & FTS5INDEX_QUERY_SKIPHASH) ){
/* Add a segment iterator for the current contents of the hash table. */
Fts5SegIter *pIter = &pNew->aSeg[iIter++];
fts5SegIterHashInit(p, pTerm, nTerm, flags, pIter);
@@ -234797,7 +236772,7 @@ static void fts5TrimSegments(Fts5Index *p, Fts5Iter *pIter){
fts5BufferAppendBlob(&p->rc, &buf, sizeof(aHdr), aHdr);
fts5BufferAppendVarint(&p->rc, &buf, pSeg->term.n);
fts5BufferAppendBlob(&p->rc, &buf, pSeg->term.n, pSeg->term.p);
- fts5BufferAppendBlob(&p->rc, &buf, pData->szLeaf-iOff,&pData->p[iOff]);
+ fts5BufferAppendBlob(&p->rc, &buf,pData->szLeaf-iOff,&pData->p[iOff]);
if( p->rc==SQLITE_OK ){
/* Set the szLeaf field */
fts5PutU16(&buf.p[2], (u16)buf.n);
@@ -235075,16 +237050,16 @@ static void fts5IndexCrisismerge(
){
const int nCrisis = p->pConfig->nCrisisMerge;
Fts5Structure *pStruct = *ppStruct;
- int iLvl = 0;
-
- assert( p->rc!=SQLITE_OK || pStruct->nLevel>0 );
- while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
- fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
- assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
- fts5StructurePromote(p, iLvl+1, pStruct);
- iLvl++;
+ if( pStruct && pStruct->nLevel>0 ){
+ int iLvl = 0;
+ while( p->rc==SQLITE_OK && pStruct->aLevel[iLvl].nSeg>=nCrisis ){
+ fts5IndexMergeLevel(p, &pStruct, iLvl, 0);
+ assert( p->rc!=SQLITE_OK || pStruct->nLevel>(iLvl+1) );
+ fts5StructurePromote(p, iLvl+1, pStruct);
+ iLvl++;
+ }
+ *ppStruct = pStruct;
}
- *ppStruct = pStruct;
}
static int fts5IndexReturn(Fts5Index *p){
@@ -235119,6 +237094,413 @@ static int fts5PoslistPrefix(const u8 *aBuf, int nMax){
}
/*
+** Execute the SQL statement:
+**
+** DELETE FROM %_idx WHERE (segid, (pgno/2)) = ($iSegid, $iPgno);
+**
+** This is used when a secure-delete operation removes the last term
+** from a segment leaf page. In that case the %_idx entry is removed
+** too. This is done to ensure that if all instances of a token are
+** removed from an fts5 database in secure-delete mode, no trace of
+** the token itself remains in the database.
+*/
+static void fts5SecureDeleteIdxEntry(
+ Fts5Index *p, /* FTS5 backend object */
+ int iSegid, /* Id of segment to delete entry for */
+ int iPgno /* Page number within segment */
+){
+ if( iPgno!=1 ){
+ assert( p->pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE );
+ if( p->pDeleteFromIdx==0 ){
+ fts5IndexPrepareStmt(p, &p->pDeleteFromIdx, sqlite3_mprintf(
+ "DELETE FROM '%q'.'%q_idx' WHERE (segid, (pgno/2)) = (?1, ?2)",
+ p->pConfig->zDb, p->pConfig->zName
+ ));
+ }
+ if( p->rc==SQLITE_OK ){
+ sqlite3_bind_int(p->pDeleteFromIdx, 1, iSegid);
+ sqlite3_bind_int(p->pDeleteFromIdx, 2, iPgno);
+ sqlite3_step(p->pDeleteFromIdx);
+ p->rc = sqlite3_reset(p->pDeleteFromIdx);
+ }
+ }
+}
+
+/*
+** This is called when a secure-delete operation removes a position-list
+** that overflows onto segment page iPgno of segment pSeg. This function
+** rewrites node iPgno, and possibly one or more of its right-hand peers,
+** to remove this portion of the position list.
+**
+** Output variable (*pbLastInDoclist) is set to true if the position-list
+** removed is followed by a new term or the end-of-segment, or false if
+** it is followed by another rowid/position list.
+*/
+static void fts5SecureDeleteOverflow(
+ Fts5Index *p,
+ Fts5StructureSegment *pSeg,
+ int iPgno,
+ int *pbLastInDoclist
+){
+ const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
+ int pgno;
+ Fts5Data *pLeaf = 0;
+ assert( iPgno!=1 );
+
+ *pbLastInDoclist = 1;
+ for(pgno=iPgno; p->rc==SQLITE_OK && pgno<=pSeg->pgnoLast; pgno++){
+ i64 iRowid = FTS5_SEGMENT_ROWID(pSeg->iSegid, pgno);
+ int iNext = 0;
+ u8 *aPg = 0;
+
+ pLeaf = fts5DataRead(p, iRowid);
+ if( pLeaf==0 ) break;
+ aPg = pLeaf->p;
+
+ iNext = fts5GetU16(&aPg[0]);
+ if( iNext!=0 ){
+ *pbLastInDoclist = 0;
+ }
+ if( iNext==0 && pLeaf->szLeaf!=pLeaf->nn ){
+ fts5GetVarint32(&aPg[pLeaf->szLeaf], iNext);
+ }
+
+ if( iNext==0 ){
+ /* The page contains no terms or rowids. Replace it with an empty
+ ** page and move on to the right-hand peer. */
+ const u8 aEmpty[] = {0x00, 0x00, 0x00, 0x04};
+ assert_nc( bDetailNone==0 || pLeaf->nn==4 );
+ if( bDetailNone==0 ) fts5DataWrite(p, iRowid, aEmpty, sizeof(aEmpty));
+ fts5DataRelease(pLeaf);
+ pLeaf = 0;
+ }else if( bDetailNone ){
+ break;
+ }else if( iNext>=pLeaf->szLeaf || iNext<4 ){
+ p->rc = FTS5_CORRUPT;
+ break;
+ }else{
+ int nShift = iNext - 4;
+ int nPg;
+
+ int nIdx = 0;
+ u8 *aIdx = 0;
+
+ /* Unless the current page footer is 0 bytes in size (in which case
+ ** the new page footer will be as well), allocate and populate a
+ ** buffer containing the new page footer. Set stack variables aIdx
+ ** and nIdx accordingly. */
+ if( pLeaf->nn>pLeaf->szLeaf ){
+ int iFirst = 0;
+ int i1 = pLeaf->szLeaf;
+ int i2 = 0;
+
+ aIdx = sqlite3Fts5MallocZero(&p->rc, (pLeaf->nn-pLeaf->szLeaf)+2);
+ if( aIdx==0 ) break;
+ i1 += fts5GetVarint32(&aPg[i1], iFirst);
+ i2 = sqlite3Fts5PutVarint(aIdx, iFirst-nShift);
+ if( i1<pLeaf->nn ){
+ memcpy(&aIdx[i2], &aPg[i1], pLeaf->nn-i1);
+ i2 += (pLeaf->nn-i1);
+ }
+ nIdx = i2;
+ }
+
+ /* Modify the contents of buffer aPg[]. Set nPg to the new size
+ ** in bytes. The new page is always smaller than the old. */
+ nPg = pLeaf->szLeaf - nShift;
+ memmove(&aPg[4], &aPg[4+nShift], nPg-4);
+ fts5PutU16(&aPg[2], nPg);
+ if( fts5GetU16(&aPg[0]) ) fts5PutU16(&aPg[0], 4);
+ if( nIdx>0 ){
+ memcpy(&aPg[nPg], aIdx, nIdx);
+ nPg += nIdx;
+ }
+ sqlite3_free(aIdx);
+
+ /* Write the new page to disk and exit the loop */
+ assert( nPg>4 || fts5GetU16(aPg)==0 );
+ fts5DataWrite(p, iRowid, aPg, nPg);
+ break;
+ }
+ }
+ fts5DataRelease(pLeaf);
+}
+
+/*
+** Completely remove the entry that pSeg currently points to from
+** the database.
+*/
+static void fts5DoSecureDelete(
+ Fts5Index *p,
+ Fts5SegIter *pSeg
+){
+ const int bDetailNone = (p->pConfig->eDetail==FTS5_DETAIL_NONE);
+ int iSegid = pSeg->pSeg->iSegid;
+ u8 *aPg = pSeg->pLeaf->p;
+ int nPg = pSeg->pLeaf->nn;
+ int iPgIdx = pSeg->pLeaf->szLeaf;
+
+ u64 iDelta = 0;
+ u64 iNextDelta = 0;
+ int iNextOff = 0;
+ int iOff = 0;
+ int nIdx = 0;
+ u8 *aIdx = 0;
+ int bLastInDoclist = 0;
+ int iIdx = 0;
+ int iStart = 0;
+ int iKeyOff = 0;
+ int iPrevKeyOff = 0;
+ int iDelKeyOff = 0; /* Offset of deleted key, if any */
+
+ nIdx = nPg-iPgIdx;
+ aIdx = sqlite3Fts5MallocZero(&p->rc, nIdx+16);
+ if( p->rc ) return;
+ memcpy(aIdx, &aPg[iPgIdx], nIdx);
+
+ /* At this point segment iterator pSeg points to the entry
+ ** this function should remove from the b-tree segment.
+ **
+ ** In detail=full or detail=column mode, pSeg->iLeafOffset is the
+ ** offset of the first byte in the position-list for the entry to
+ ** remove. Immediately before this comes two varints that will also
+ ** need to be removed:
+ **
+ ** + the rowid or delta rowid value for the entry, and
+ ** + the size of the position list in bytes.
+ **
+ ** Or, in detail=none mode, there is a single varint prior to
+ ** pSeg->iLeafOffset - the rowid or delta rowid value.
+ **
+ ** This block sets the following variables:
+ **
+ ** iStart:
+ ** iDelta:
+ */
+ {
+ int iSOP;
+ if( pSeg->iLeafPgno==pSeg->iTermLeafPgno ){
+ iStart = pSeg->iTermLeafOffset;
+ }else{
+ iStart = fts5GetU16(&aPg[0]);
+ }
+
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ assert_nc( iSOP<=pSeg->iLeafOffset );
+
+ if( bDetailNone ){
+ while( iSOP<pSeg->iLeafOffset ){
+ if( aPg[iSOP]==0x00 ) iSOP++;
+ if( aPg[iSOP]==0x00 ) iSOP++;
+ iStart = iSOP;
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ }
+
+ iNextOff = iSOP;
+ if( iNextOff<pSeg->iEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
+ if( iNextOff<pSeg->iEndofDoclist && aPg[iNextOff]==0x00 ) iNextOff++;
+
+ }else{
+ int nPos = 0;
+ iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
+ while( iSOP<pSeg->iLeafOffset ){
+ iStart = iSOP + (nPos/2);
+ iSOP = iStart + fts5GetVarint(&aPg[iStart], &iDelta);
+ iSOP += fts5GetVarint32(&aPg[iSOP], nPos);
+ }
+ assert_nc( iSOP==pSeg->iLeafOffset );
+ iNextOff = pSeg->iLeafOffset + pSeg->nPos;
+ }
+ }
+
+ iOff = iStart;
+ if( iNextOff>=iPgIdx ){
+ int pgno = pSeg->iLeafPgno+1;
+ fts5SecureDeleteOverflow(p, pSeg->pSeg, pgno, &bLastInDoclist);
+ iNextOff = iPgIdx;
+ }else{
+ /* Set bLastInDoclist to true if the entry being removed is the last
+ ** in its doclist. */
+ for(iIdx=0, iKeyOff=0; iIdx<nIdx; /* no-op */){
+ u32 iVal = 0;
+ iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
+ iKeyOff += iVal;
+ if( iKeyOff==iNextOff ){
+ bLastInDoclist = 1;
+ }
+ }
+ }
+
+ if( fts5GetU16(&aPg[0])==iStart && (bLastInDoclist||iNextOff==iPgIdx) ){
+ fts5PutU16(&aPg[0], 0);
+ }
+
+ if( bLastInDoclist==0 ){
+ if( iNextOff!=iPgIdx ){
+ iNextOff += fts5GetVarint(&aPg[iNextOff], &iNextDelta);
+ iOff += sqlite3Fts5PutVarint(&aPg[iOff], iDelta + iNextDelta);
+ }
+ }else if(
+ iStart==pSeg->iTermLeafOffset && pSeg->iLeafPgno==pSeg->iTermLeafPgno
+ ){
+ /* The entry being removed was the only position list in its
+ ** doclist. Therefore the term needs to be removed as well. */
+ int iKey = 0;
+ for(iIdx=0, iKeyOff=0; iIdx<nIdx; iKey++){
+ u32 iVal = 0;
+ iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
+ if( (iKeyOff+iVal)>(u32)iStart ) break;
+ iKeyOff += iVal;
+ }
+
+ iDelKeyOff = iOff = iKeyOff;
+ if( iNextOff!=iPgIdx ){
+ int nPrefix = 0;
+ int nSuffix = 0;
+ int nPrefix2 = 0;
+ int nSuffix2 = 0;
+
+ iDelKeyOff = iNextOff;
+ iNextOff += fts5GetVarint32(&aPg[iNextOff], nPrefix2);
+ iNextOff += fts5GetVarint32(&aPg[iNextOff], nSuffix2);
+
+ if( iKey!=1 ){
+ iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nPrefix);
+ }
+ iKeyOff += fts5GetVarint32(&aPg[iKeyOff], nSuffix);
+
+ nPrefix = MIN(nPrefix, nPrefix2);
+ nSuffix = (nPrefix2 + nSuffix2) - nPrefix;
+
+ if( (iKeyOff+nSuffix)>iPgIdx || (iNextOff+nSuffix2)>iPgIdx ){
+ p->rc = FTS5_CORRUPT;
+ }else{
+ if( iKey!=1 ){
+ iOff += sqlite3Fts5PutVarint(&aPg[iOff], nPrefix);
+ }
+ iOff += sqlite3Fts5PutVarint(&aPg[iOff], nSuffix);
+ if( nPrefix2>nPrefix ){
+ memcpy(&aPg[iOff], &pSeg->term.p[nPrefix], nPrefix2-nPrefix);
+ iOff += (nPrefix2-nPrefix);
+ }
+ memmove(&aPg[iOff], &aPg[iNextOff], nSuffix2);
+ iOff += nSuffix2;
+ iNextOff += nSuffix2;
+ }
+ }
+ }else if( iStart==4 ){
+ int iPgno;
+
+ assert_nc( pSeg->iLeafPgno>pSeg->iTermLeafPgno );
+ /* The entry being removed may be the only position list in
+ ** its doclist. */
+ for(iPgno=pSeg->iLeafPgno-1; iPgno>pSeg->iTermLeafPgno; iPgno-- ){
+ Fts5Data *pPg = fts5DataRead(p, FTS5_SEGMENT_ROWID(iSegid, iPgno));
+ int bEmpty = (pPg && pPg->nn==4);
+ fts5DataRelease(pPg);
+ if( bEmpty==0 ) break;
+ }
+
+ if( iPgno==pSeg->iTermLeafPgno ){
+ i64 iId = FTS5_SEGMENT_ROWID(iSegid, pSeg->iTermLeafPgno);
+ Fts5Data *pTerm = fts5DataRead(p, iId);
+ if( pTerm && pTerm->szLeaf==pSeg->iTermLeafOffset ){
+ u8 *aTermIdx = &pTerm->p[pTerm->szLeaf];
+ int nTermIdx = pTerm->nn - pTerm->szLeaf;
+ int iTermIdx = 0;
+ int iTermOff = 0;
+
+ while( 1 ){
+ u32 iVal = 0;
+ int nByte = fts5GetVarint32(&aTermIdx[iTermIdx], iVal);
+ iTermOff += iVal;
+ if( (iTermIdx+nByte)>=nTermIdx ) break;
+ iTermIdx += nByte;
+ }
+ nTermIdx = iTermIdx;
+
+ memmove(&pTerm->p[iTermOff], &pTerm->p[pTerm->szLeaf], nTermIdx);
+ fts5PutU16(&pTerm->p[2], iTermOff);
+
+ fts5DataWrite(p, iId, pTerm->p, iTermOff+nTermIdx);
+ if( nTermIdx==0 ){
+ fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iTermLeafPgno);
+ }
+ }
+ fts5DataRelease(pTerm);
+ }
+ }
+
+ if( p->rc==SQLITE_OK ){
+ const int nMove = nPg - iNextOff;
+ int nShift = 0;
+
+ memmove(&aPg[iOff], &aPg[iNextOff], nMove);
+ iPgIdx -= (iNextOff - iOff);
+ nPg = iPgIdx;
+ fts5PutU16(&aPg[2], iPgIdx);
+
+ nShift = iNextOff - iOff;
+ for(iIdx=0, iKeyOff=0, iPrevKeyOff=0; iIdx<nIdx; /* no-op */){
+ u32 iVal = 0;
+ iIdx += fts5GetVarint32(&aIdx[iIdx], iVal);
+ iKeyOff += iVal;
+ if( iKeyOff!=iDelKeyOff ){
+ if( iKeyOff>iOff ){
+ iKeyOff -= nShift;
+ nShift = 0;
+ }
+ nPg += sqlite3Fts5PutVarint(&aPg[nPg], iKeyOff - iPrevKeyOff);
+ iPrevKeyOff = iKeyOff;
+ }
+ }
+
+ if( iPgIdx==nPg && nIdx>0 && pSeg->iLeafPgno!=1 ){
+ fts5SecureDeleteIdxEntry(p, iSegid, pSeg->iLeafPgno);
+ }
+
+ assert_nc( nPg>4 || fts5GetU16(aPg)==0 );
+ fts5DataWrite(p, FTS5_SEGMENT_ROWID(iSegid,pSeg->iLeafPgno), aPg,nPg);
+ }
+ sqlite3_free(aIdx);
+}
+
+/*
+** This is called as part of flushing a delete to disk in 'secure-delete'
+** mode. It edits the segments within the database described by argument
+** pStruct to remove the entries for term zTerm, rowid iRowid.
+*/
+static void fts5FlushSecureDelete(
+ Fts5Index *p,
+ Fts5Structure *pStruct,
+ const char *zTerm,
+ i64 iRowid
+){
+ const int f = FTS5INDEX_QUERY_SKIPHASH;
+ int nTerm = (int)strlen(zTerm);
+ Fts5Iter *pIter = 0; /* Used to find term instance */
+
+ fts5MultiIterNew(p, pStruct, f, 0, (const u8*)zTerm, nTerm, -1, 0, &pIter);
+ if( fts5MultiIterEof(p, pIter)==0 ){
+ i64 iThis = fts5MultiIterRowid(pIter);
+ if( iThis<iRowid ){
+ fts5MultiIterNextFrom(p, pIter, iRowid);
+ }
+
+ if( p->rc==SQLITE_OK
+ && fts5MultiIterEof(p, pIter)==0
+ && iRowid==fts5MultiIterRowid(pIter)
+ ){
+ Fts5SegIter *pSeg = &pIter->aSeg[pIter->aFirst[1].iFirst];
+ fts5DoSecureDelete(p, pSeg);
+ }
+ }
+
+ fts5MultiIterFree(pIter);
+}
+
+
+/*
** Flush the contents of in-memory hash table iHash to a new level-0
** segment on disk. Also update the corresponding structure record.
**
@@ -235140,6 +237522,7 @@ static void fts5FlushOneHash(Fts5Index *p){
if( iSegid ){
const int pgsz = p->pConfig->pgsz;
int eDetail = p->pConfig->eDetail;
+ int bSecureDelete = p->pConfig->bSecureDelete;
Fts5StructureSegment *pSeg; /* New segment within pStruct */
Fts5Buffer *pBuf; /* Buffer in which to assemble leaf page */
Fts5Buffer *pPgidx; /* Buffer in which to assemble pgidx */
@@ -235162,40 +237545,77 @@ static void fts5FlushOneHash(Fts5Index *p){
}
while( p->rc==SQLITE_OK && 0==sqlite3Fts5HashScanEof(pHash) ){
const char *zTerm; /* Buffer containing term */
+ int nTerm; /* Size of zTerm in bytes */
const u8 *pDoclist; /* Pointer to doclist for this term */
int nDoclist; /* Size of doclist in bytes */
- /* Write the term for this entry to disk. */
+ /* Get the term and doclist for this entry. */
sqlite3Fts5HashScanEntry(pHash, &zTerm, &pDoclist, &nDoclist);
- fts5WriteAppendTerm(p, &writer, (int)strlen(zTerm), (const u8*)zTerm);
- if( p->rc!=SQLITE_OK ) break;
+ nTerm = (int)strlen(zTerm);
+ if( bSecureDelete==0 ){
+ fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
+ if( p->rc!=SQLITE_OK ) break;
+ assert( writer.bFirstRowidInPage==0 );
+ }
- assert( writer.bFirstRowidInPage==0 );
- if( pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
+ if( !bSecureDelete && pgsz>=(pBuf->n + pPgidx->n + nDoclist + 1) ){
/* The entire doclist will fit on the current leaf. */
fts5BufferSafeAppendBlob(pBuf, pDoclist, nDoclist);
}else{
+ int bTermWritten = !bSecureDelete;
i64 iRowid = 0;
- u64 iDelta = 0;
+ i64 iPrev = 0;
int iOff = 0;
/* The entire doclist will not fit on this leaf. The following
** loop iterates through the poslists that make up the current
** doclist. */
while( p->rc==SQLITE_OK && iOff<nDoclist ){
+ u64 iDelta = 0;
iOff += fts5GetVarint(&pDoclist[iOff], &iDelta);
iRowid += iDelta;
+ /* If in secure delete mode, and if this entry in the poslist is
+ ** in fact a delete, then edit the existing segments directly
+ ** using fts5FlushSecureDelete(). */
+ if( bSecureDelete ){
+ if( eDetail==FTS5_DETAIL_NONE ){
+ if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
+ fts5FlushSecureDelete(p, pStruct, zTerm, iRowid);
+ iOff++;
+ if( iOff<nDoclist && pDoclist[iOff]==0x00 ){
+ iOff++;
+ nDoclist = 0;
+ }else{
+ continue;
+ }
+ }
+ }else if( (pDoclist[iOff] & 0x01) ){
+ fts5FlushSecureDelete(p, pStruct, zTerm, iRowid);
+ if( p->rc!=SQLITE_OK || pDoclist[iOff]==0x01 ){
+ iOff++;
+ continue;
+ }
+ }
+ }
+
+ if( p->rc==SQLITE_OK && bTermWritten==0 ){
+ fts5WriteAppendTerm(p, &writer, nTerm, (const u8*)zTerm);
+ bTermWritten = 1;
+ assert( p->rc!=SQLITE_OK || writer.bFirstRowidInPage==0 );
+ }
+
if( writer.bFirstRowidInPage ){
fts5PutU16(&pBuf->p[0], (u16)pBuf->n); /* first rowid on page */
pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid);
writer.bFirstRowidInPage = 0;
fts5WriteDlidxAppend(p, &writer, iRowid);
- if( p->rc!=SQLITE_OK ) break;
}else{
- pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iDelta);
+ pBuf->n += sqlite3Fts5PutVarint(&pBuf->p[pBuf->n], iRowid-iPrev);
}
+ if( p->rc!=SQLITE_OK ) break;
assert( pBuf->n<=pBuf->nSpace );
+ iPrev = iRowid;
if( eDetail==FTS5_DETAIL_NONE ){
if( iOff<nDoclist && pDoclist[iOff]==0 ){
@@ -235254,20 +237674,23 @@ static void fts5FlushOneHash(Fts5Index *p){
sqlite3Fts5HashClear(pHash);
fts5WriteFinish(p, &writer, &pgnoLast);
- /* Update the Fts5Structure. It is written back to the database by the
- ** fts5StructureRelease() call below. */
- if( pStruct->nLevel==0 ){
- fts5StructureAddLevel(&p->rc, &pStruct);
- }
- fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
- if( p->rc==SQLITE_OK ){
- pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
- pSeg->iSegid = iSegid;
- pSeg->pgnoFirst = 1;
- pSeg->pgnoLast = pgnoLast;
- pStruct->nSegment++;
+ assert( p->rc!=SQLITE_OK || bSecureDelete || pgnoLast>0 );
+ if( pgnoLast>0 ){
+ /* Update the Fts5Structure. It is written back to the database by the
+ ** fts5StructureRelease() call below. */
+ if( pStruct->nLevel==0 ){
+ fts5StructureAddLevel(&p->rc, &pStruct);
+ }
+ fts5StructureExtendLevel(&p->rc, pStruct, 0, 1, 0);
+ if( p->rc==SQLITE_OK ){
+ pSeg = &pStruct->aLevel[0].aSeg[ pStruct->aLevel[0].nSeg++ ];
+ pSeg->iSegid = iSegid;
+ pSeg->pgnoFirst = 1;
+ pSeg->pgnoLast = pgnoLast;
+ pStruct->nSegment++;
+ }
+ fts5StructurePromote(p, 0, pStruct);
}
- fts5StructurePromote(p, 0, pStruct);
}
fts5IndexAutomerge(p, &pStruct, pgnoLast);
@@ -236008,6 +238431,7 @@ static int sqlite3Fts5IndexClose(Fts5Index *p){
sqlite3_finalize(p->pIdxDeleter);
sqlite3_finalize(p->pIdxSelect);
sqlite3_finalize(p->pDataVersion);
+ sqlite3_finalize(p->pDeleteFromIdx);
sqlite3Fts5HashFree(p->pHash);
sqlite3_free(p->zDataTbl);
sqlite3_free(p);
@@ -236638,6 +239062,7 @@ static void fts5IndexIntegrityCheckSegment(
Fts5StructureSegment *pSeg /* Segment to check internal consistency */
){
Fts5Config *pConfig = p->pConfig;
+ int bSecureDelete = (pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE);
sqlite3_stmt *pStmt = 0;
int rc2;
int iIdxPrevLeaf = pSeg->pgnoFirst-1;
@@ -236673,7 +239098,19 @@ static void fts5IndexIntegrityCheckSegment(
** is also a rowid pointer within the leaf page header, it points to a
** location before the term. */
if( pLeaf->nn<=pLeaf->szLeaf ){
- p->rc = FTS5_CORRUPT;
+
+ if( nIdxTerm==0
+ && pConfig->iVersion==FTS5_CURRENT_VERSION_SECUREDELETE
+ && pLeaf->nn==pLeaf->szLeaf
+ && pLeaf->nn==4
+ ){
+ /* special case - the very first page in a segment keeps its %_idx
+ ** entry even if all the terms are removed from it by secure-delete
+ ** operations. */
+ }else{
+ p->rc = FTS5_CORRUPT;
+ }
+
}else{
int iOff; /* Offset of first term on leaf */
int iRowidOff; /* Offset of first rowid on leaf */
@@ -236737,9 +239174,12 @@ static void fts5IndexIntegrityCheckSegment(
ASSERT_SZLEAF_OK(pLeaf);
if( iRowidOff>=pLeaf->szLeaf ){
p->rc = FTS5_CORRUPT;
- }else{
+ }else if( bSecureDelete==0 || iRowidOff>0 ){
+ i64 iDlRowid = fts5DlidxIterRowid(pDlidx);
fts5GetVarint(&pLeaf->p[iRowidOff], (u64*)&iRowid);
- if( iRowid!=fts5DlidxIterRowid(pDlidx) ) p->rc = FTS5_CORRUPT;
+ if( iRowid<iDlRowid || (bSecureDelete==0 && iRowid!=iDlRowid) ){
+ p->rc = FTS5_CORRUPT;
+ }
}
fts5DataRelease(pLeaf);
}
@@ -239001,6 +241441,8 @@ static int fts5UpdateMethod(
Fts5Config *pConfig = pTab->p.pConfig;
int eType0; /* value_type() of apVal[0] */
int rc = SQLITE_OK; /* Return code */
+ int bUpdateOrDelete = 0;
+
/* A transaction must be open when this is called. */
assert( pTab->ts.eState==1 || pTab->ts.eState==2 );
@@ -239011,6 +241453,11 @@ static int fts5UpdateMethod(
|| sqlite3_value_type(apVal[0])==SQLITE_NULL
);
assert( pTab->p.pConfig->pzErrmsg==0 );
+ if( pConfig->pgsz==0 ){
+ rc = sqlite3Fts5IndexLoadConfig(pTab->p.pIndex);
+ if( rc!=SQLITE_OK ) return rc;
+ }
+
pTab->p.pConfig->pzErrmsg = &pTab->p.base.zErrMsg;
/* Put any active cursors into REQUIRE_SEEK state. */
@@ -239063,6 +241510,7 @@ static int fts5UpdateMethod(
else if( nArg==1 ){
i64 iDel = sqlite3_value_int64(apVal[0]); /* Rowid to delete */
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iDel, 0);
+ bUpdateOrDelete = 1;
}
/* INSERT or UPDATE */
@@ -239078,6 +241526,7 @@ static int fts5UpdateMethod(
if( eConflict==SQLITE_REPLACE && eType1==SQLITE_INTEGER ){
i64 iNew = sqlite3_value_int64(apVal[1]); /* Rowid to delete */
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iNew, 0);
+ bUpdateOrDelete = 1;
}
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
@@ -239106,10 +241555,24 @@ static int fts5UpdateMethod(
rc = sqlite3Fts5StorageDelete(pTab->pStorage, iOld, 0);
fts5StorageInsert(&rc, pTab, apVal, pRowid);
}
+ bUpdateOrDelete = 1;
}
}
}
+ if( rc==SQLITE_OK
+ && bUpdateOrDelete
+ && pConfig->bSecureDelete
+ && pConfig->iVersion==FTS5_CURRENT_VERSION
+ ){
+ rc = sqlite3Fts5StorageConfigValue(
+ pTab->pStorage, "version", 0, FTS5_CURRENT_VERSION_SECUREDELETE
+ );
+ if( rc==SQLITE_OK ){
+ pConfig->iVersion = FTS5_CURRENT_VERSION_SECUREDELETE;
+ }
+ }
+
pTab->p.pConfig->pzErrmsg = 0;
return rc;
}
@@ -239969,6 +242432,7 @@ static int fts5RollbackToMethod(sqlite3_vtab *pVtab, int iSavepoint){
UNUSED_PARAM(iSavepoint); /* Call below is a no-op for NDEBUG builds */
fts5CheckTransactionState(pTab, FTS5_ROLLBACKTO, iSavepoint);
fts5TripCursors(pTab);
+ pTab->p.pConfig->pgsz = 0;
return sqlite3Fts5StorageRollback(pTab->pStorage);
}
@@ -240171,7 +242635,7 @@ static void fts5SourceIdFunc(
){
assert( nArg==0 );
UNUSED_PARAM2(nArg, apUnused);
- sqlite3_result_text(pCtx, "fts5: 2023-02-21 18:09:37 05941c2a04037fc3ed2ffae11f5d2260706f89431f463518740f72ada350866d", -1, SQLITE_TRANSIENT);
+ sqlite3_result_text(pCtx, "fts5: 2023-05-16 12:36:15 831d0fb2836b71c9bc51067c49fee4b8f18047814f2ff22d817d25195cf350b0", -1, SQLITE_TRANSIENT);
}
/*
diff --git a/src/libs/3rdparty/sqlite/sqlite3.h b/src/libs/3rdparty/sqlite/sqlite3.h
index 4c6addac26c..48effe20216 100644
--- a/src/libs/3rdparty/sqlite/sqlite3.h
+++ b/src/libs/3rdparty/sqlite/sqlite3.h
@@ -146,9 +146,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
-#define SQLITE_VERSION "3.41.0"
-#define SQLITE_VERSION_NUMBER 3041000
-#define SQLITE_SOURCE_ID "2023-02-21 18:09:37 05941c2a04037fc3ed2ffae11f5d2260706f89431f463518740f72ada350866d"
+#define SQLITE_VERSION "3.42.0"
+#define SQLITE_VERSION_NUMBER 3042000
+#define SQLITE_SOURCE_ID "2023-05-16 12:36:15 831d0fb2836b71c9bc51067c49fee4b8f18047814f2ff22d817d25195cf350b0"
/*
** CAPI3REF: Run-Time Library Version Numbers
@@ -1655,20 +1655,23 @@ SQLITE_API int sqlite3_os_end(void);
** must ensure that no other SQLite interfaces are invoked by other
** threads while sqlite3_config() is running.</b>
**
-** The sqlite3_config() interface
-** may only be invoked prior to library initialization using
-** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
-** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
-** [sqlite3_shutdown()] then it will return SQLITE_MISUSE.
-** Note, however, that ^sqlite3_config() can be called as part of the
-** implementation of an application-defined [sqlite3_os_init()].
-**
** The first argument to sqlite3_config() is an integer
** [configuration option] that determines
** what property of SQLite is to be configured. Subsequent arguments
** vary depending on the [configuration option]
** in the first argument.
**
+** For most configuration options, the sqlite3_config() interface
+** may only be invoked prior to library initialization using
+** [sqlite3_initialize()] or after shutdown by [sqlite3_shutdown()].
+** The exceptional configuration options that may be invoked at any time
+** are called "anytime configuration options".
+** ^If sqlite3_config() is called after [sqlite3_initialize()] and before
+** [sqlite3_shutdown()] with a first argument that is not an anytime
+** configuration option, then the sqlite3_config() call will return SQLITE_MISUSE.
+** Note, however, that ^sqlite3_config() can be called as part of the
+** implementation of an application-defined [sqlite3_os_init()].
+**
** ^When a configuration option is set, sqlite3_config() returns [SQLITE_OK].
** ^If the option is unknown or SQLite is unable to set the option
** then this routine returns a non-zero [error code].
@@ -1776,6 +1779,23 @@ struct sqlite3_mem_methods {
** These constants are the available integer configuration options that
** can be passed as the first argument to the [sqlite3_config()] interface.
**
+** Most of the configuration options for sqlite3_config()
+** will only work if invoked prior to [sqlite3_initialize()] or after
+** [sqlite3_shutdown()]. The few exceptions to this rule are called
+** "anytime configuration options".
+** ^Calling [sqlite3_config()] with a first argument that is not an
+** anytime configuration option in between calls to [sqlite3_initialize()] and
+** [sqlite3_shutdown()] is a no-op that returns SQLITE_MISUSE.
+**
+** The set of anytime configuration options can change (by insertions
+** and/or deletions) from one release of SQLite to the next.
+** As of SQLite version 3.42.0, the complete set of anytime configuration
+** options is:
+** <ul>
+** <li> SQLITE_CONFIG_LOG
+** <li> SQLITE_CONFIG_PCACHE_HDRSZ
+** </ul>
+**
** New configuration options may be added in future releases of SQLite.
** Existing configuration options might be discontinued. Applications
** should check the return code from [sqlite3_config()] to make sure that
@@ -2122,28 +2142,28 @@ struct sqlite3_mem_methods {
** compile-time option is not set, then the default maximum is 1073741824.
** </dl>
*/
-#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
-#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
-#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
-#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
-#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
-#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
-#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
-#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
-#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
-#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
-/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
-#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
-#define SQLITE_CONFIG_PCACHE 14 /* no-op */
-#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
-#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
-#define SQLITE_CONFIG_URI 17 /* int */
-#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
-#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_SINGLETHREAD 1 /* nil */
+#define SQLITE_CONFIG_MULTITHREAD 2 /* nil */
+#define SQLITE_CONFIG_SERIALIZED 3 /* nil */
+#define SQLITE_CONFIG_MALLOC 4 /* sqlite3_mem_methods* */
+#define SQLITE_CONFIG_GETMALLOC 5 /* sqlite3_mem_methods* */
+#define SQLITE_CONFIG_SCRATCH 6 /* No longer used */
+#define SQLITE_CONFIG_PAGECACHE 7 /* void*, int sz, int N */
+#define SQLITE_CONFIG_HEAP 8 /* void*, int nByte, int min */
+#define SQLITE_CONFIG_MEMSTATUS 9 /* boolean */
+#define SQLITE_CONFIG_MUTEX 10 /* sqlite3_mutex_methods* */
+#define SQLITE_CONFIG_GETMUTEX 11 /* sqlite3_mutex_methods* */
+/* previously SQLITE_CONFIG_CHUNKALLOC 12 which is now unused. */
+#define SQLITE_CONFIG_LOOKASIDE 13 /* int int */
+#define SQLITE_CONFIG_PCACHE 14 /* no-op */
+#define SQLITE_CONFIG_GETPCACHE 15 /* no-op */
+#define SQLITE_CONFIG_LOG 16 /* xFunc, void* */
+#define SQLITE_CONFIG_URI 17 /* int */
+#define SQLITE_CONFIG_PCACHE2 18 /* sqlite3_pcache_methods2* */
+#define SQLITE_CONFIG_GETPCACHE2 19 /* sqlite3_pcache_methods2* */
#define SQLITE_CONFIG_COVERING_INDEX_SCAN 20 /* int */
-#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
-#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
+#define SQLITE_CONFIG_SQLLOG 21 /* xSqllog, void* */
+#define SQLITE_CONFIG_MMAP_SIZE 22 /* sqlite3_int64, sqlite3_int64 */
#define SQLITE_CONFIG_WIN32_HEAPSIZE 23 /* int nByte */
#define SQLITE_CONFIG_PCACHE_HDRSZ 24 /* int *psz */
#define SQLITE_CONFIG_PMASZ 25 /* unsigned int szPma */
@@ -2378,7 +2398,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DML]]
-** <dt>SQLITE_DBCONFIG_DQS_DML</td>
+** <dt>SQLITE_DBCONFIG_DQS_DML</dt>
** <dd>The SQLITE_DBCONFIG_DQS_DML option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DML statements
** only, that is DELETE, INSERT, SELECT, and UPDATE statements. The
@@ -2387,7 +2407,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_DQS_DDL]]
-** <dt>SQLITE_DBCONFIG_DQS_DDL</td>
+** <dt>SQLITE_DBCONFIG_DQS_DDL</dt>
** <dd>The SQLITE_DBCONFIG_DQS option activates or deactivates
** the legacy [double-quoted string literal] misfeature for DDL statements,
** such as CREATE TABLE and CREATE INDEX. The
@@ -2396,7 +2416,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_TRUSTED_SCHEMA]]
-** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</td>
+** <dt>SQLITE_DBCONFIG_TRUSTED_SCHEMA</dt>
** <dd>The SQLITE_DBCONFIG_TRUSTED_SCHEMA option tells SQLite to
** assume that database schemas are untainted by malicious content.
** When the SQLITE_DBCONFIG_TRUSTED_SCHEMA option is disabled, SQLite
@@ -2416,7 +2436,7 @@ struct sqlite3_mem_methods {
** </dd>
**
** [[SQLITE_DBCONFIG_LEGACY_FILE_FORMAT]]
-** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</td>
+** <dt>SQLITE_DBCONFIG_LEGACY_FILE_FORMAT</dt>
** <dd>The SQLITE_DBCONFIG_LEGACY_FILE_FORMAT option activates or deactivates
** the legacy file format flag. When activated, this flag causes all newly
** created database file to have a schema format version number (the 4-byte
@@ -2425,7 +2445,7 @@ struct sqlite3_mem_methods {
** any SQLite version back to 3.0.0 ([dateof:3.0.0]). Without this setting,
** newly created databases are generally not understandable by SQLite versions
** prior to 3.3.0 ([dateof:3.3.0]). As these words are written, there
-** is now scarcely any need to generated database files that are compatible
+** is now scarcely any need to generate database files that are compatible
** all the way back to version 3.0.0, and so this setting is of little
** practical use, but is provided so that SQLite can continue to claim the
** ability to generate new database files that are compatible with version
@@ -2436,6 +2456,38 @@ struct sqlite3_mem_methods {
** not considered a bug since SQLite versions 3.3.0 and earlier do not support
** either generated columns or decending indexes.
** </dd>
+**
+** [[SQLITE_DBCONFIG_STMT_SCANSTATUS]]
+** <dt>SQLITE_DBCONFIG_STMT_SCANSTATUS</dt>
+** <dd>The SQLITE_DBCONFIG_STMT_SCANSTATUS option is only useful in
+** SQLITE_ENABLE_STMT_SCANSTATUS builds. In this case, it sets or clears
+** a flag that enables collection of the sqlite3_stmt_scanstatus_v2()
+** statistics. For statistics to be collected, the flag must be set on
+** the database handle both when the SQL statement is prepared and when it
+** is stepped. The flag is set (collection of statistics is enabled)
+** by default. This option takes two arguments: an integer and a pointer to
+** an integer.. The first argument is 1, 0, or -1 to enable, disable, or
+** leave unchanged the statement scanstatus option. If the second argument
+** is not NULL, then the value of the statement scanstatus setting after
+** processing the first argument is written into the integer that the second
+** argument points to.
+** </dd>
+**
+** [[SQLITE_DBCONFIG_REVERSE_SCANORDER]]
+** <dt>SQLITE_DBCONFIG_REVERSE_SCANORDER</dt>
+** <dd>The SQLITE_DBCONFIG_REVERSE_SCANORDER option changes the default order
+** in which tables and indexes are scanned so that the scans start at the end
+** and work toward the beginning rather than starting at the beginning and
+** working toward the end. Setting SQLITE_DBCONFIG_REVERSE_SCANORDER is the
+** same as setting [PRAGMA reverse_unordered_selects]. This option takes
+** two arguments which are an integer and a pointer to an integer. The first
+** argument is 1, 0, or -1 to enable, disable, or leave unchanged the
+** reverse scan order flag, respectively. If the second argument is not NULL,
+** then 0 or 1 is written into the integer that the second argument points to
+** depending on if the reverse scan order flag is set after processing the
+** first argument.
+** </dd>
+**
** </dl>
*/
#define SQLITE_DBCONFIG_MAINDBNAME 1000 /* const char* */
@@ -2456,7 +2508,9 @@ struct sqlite3_mem_methods {
#define SQLITE_DBCONFIG_ENABLE_VIEW 1015 /* int int* */
#define SQLITE_DBCONFIG_LEGACY_FILE_FORMAT 1016 /* int int* */
#define SQLITE_DBCONFIG_TRUSTED_SCHEMA 1017 /* int int* */
-#define SQLITE_DBCONFIG_MAX 1017 /* Largest DBCONFIG */
+#define SQLITE_DBCONFIG_STMT_SCANSTATUS 1018 /* int int* */
+#define SQLITE_DBCONFIG_REVERSE_SCANORDER 1019 /* int int* */
+#define SQLITE_DBCONFIG_MAX 1019 /* Largest DBCONFIG */
/*
** CAPI3REF: Enable Or Disable Extended Result Codes
@@ -6201,6 +6255,13 @@ SQLITE_API void sqlite3_activate_cerod(
** of the default VFS is not implemented correctly, or not implemented at
** all, then the behavior of sqlite3_sleep() may deviate from the description
** in the previous paragraphs.
+**
+** If a negative argument is passed to sqlite3_sleep() the results vary by
+** VFS and operating system. Some system treat a negative argument as an
+** instruction to sleep forever. Others understand it to mean do not sleep
+** at all. ^In SQLite version 3.42.0 and later, a negative
+** argument passed into sqlite3_sleep() is changed to zero before it is relayed
+** down into the xSleep method of the VFS.
*/
SQLITE_API int sqlite3_sleep(int);
@@ -7828,9 +7889,9 @@ SQLITE_API int sqlite3_vfs_unregister(sqlite3_vfs*);
** is undefined if the mutex is not currently entered by the
** calling thread or is not currently allocated.
**
-** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(), or
-** sqlite3_mutex_leave() is a NULL pointer, then all three routines
-** behave as no-ops.
+** ^If the argument to sqlite3_mutex_enter(), sqlite3_mutex_try(),
+** sqlite3_mutex_leave(), or sqlite3_mutex_free() is a NULL pointer,
+** then any of the four routines behaves as a no-op.
**
** See also: [sqlite3_mutex_held()] and [sqlite3_mutex_notheld()].
*/
@@ -9564,18 +9625,28 @@ SQLITE_API int sqlite3_vtab_config(sqlite3*, int op, ...);
** [[SQLITE_VTAB_INNOCUOUS]]<dt>SQLITE_VTAB_INNOCUOUS</dt>
** <dd>Calls of the form
** [sqlite3_vtab_config](db,SQLITE_VTAB_INNOCUOUS) from within the
-** the [xConnect] or [xCreate] methods of a [virtual table] implmentation
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
** identify that virtual table as being safe to use from within triggers
** and views. Conceptually, the SQLITE_VTAB_INNOCUOUS tag means that the
** virtual table can do no serious harm even if it is controlled by a
** malicious hacker. Developers should avoid setting the SQLITE_VTAB_INNOCUOUS
** flag unless absolutely necessary.
** </dd>
+**
+** [[SQLITE_VTAB_USES_ALL_SCHEMAS]]<dt>SQLITE_VTAB_USES_ALL_SCHEMAS</dt>
+** <dd>Calls of the form
+** [sqlite3_vtab_config](db,SQLITE_VTAB_USES_ALL_SCHEMA) from within the
+** the [xConnect] or [xCreate] methods of a [virtual table] implementation
+** instruct the query planner to begin at least a read transaction on
+** all schemas ("main", "temp", and any ATTACH-ed databases) whenever the
+** virtual table is used.
+** </dd>
** </dl>
*/
#define SQLITE_VTAB_CONSTRAINT_SUPPORT 1
#define SQLITE_VTAB_INNOCUOUS 2
#define SQLITE_VTAB_DIRECTONLY 3
+#define SQLITE_VTAB_USES_ALL_SCHEMAS 4
/*
** CAPI3REF: Determine The Virtual Table Conflict Policy
@@ -10750,16 +10821,20 @@ SQLITE_API int sqlite3session_create(
SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
/*
-** CAPIREF: Conigure a Session Object
+** CAPI3REF: Configure a Session Object
** METHOD: sqlite3_session
**
** This method is used to configure a session object after it has been
-** created. At present the only valid value for the second parameter is
-** [SQLITE_SESSION_OBJCONFIG_SIZE].
+** created. At present the only valid values for the second parameter are
+** [SQLITE_SESSION_OBJCONFIG_SIZE] and [SQLITE_SESSION_OBJCONFIG_ROWID].
**
-** Arguments for sqlite3session_object_config()
+*/
+SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
+
+/*
+** CAPI3REF: Options for sqlite3session_object_config
**
-** The following values may passed as the the 4th parameter to
+** The following values may passed as the the 2nd parameter to
** sqlite3session_object_config().
**
** <dt>SQLITE_SESSION_OBJCONFIG_SIZE <dd>
@@ -10775,12 +10850,21 @@ SQLITE_API void sqlite3session_delete(sqlite3_session *pSession);
**
** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
** the first table has been attached to the session object.
+**
+** <dt>SQLITE_SESSION_OBJCONFIG_ROWID <dd>
+** This option is used to set, clear or query the flag that enables
+** collection of data for tables with no explicit PRIMARY KEY.
+**
+** Normally, tables with no explicit PRIMARY KEY are simply ignored
+** by the sessions module. However, if this flag is set, it behaves
+** as if such tables have a column "_rowid_ INTEGER PRIMARY KEY" inserted
+** as their leftmost columns.
+**
+** It is an error (SQLITE_MISUSE) to attempt to modify this setting after
+** the first table has been attached to the session object.
*/
-SQLITE_API int sqlite3session_object_config(sqlite3_session*, int op, void *pArg);
-
-/*
-*/
-#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_SIZE 1
+#define SQLITE_SESSION_OBJCONFIG_ROWID 2
/*
** CAPI3REF: Enable Or Disable A Session Object
@@ -11913,9 +11997,23 @@ SQLITE_API int sqlite3changeset_apply_v2(
** Invert the changeset before applying it. This is equivalent to inverting
** a changeset using sqlite3changeset_invert() before applying it. It is
** an error to specify this flag with a patchset.
+**
+** <dt>SQLITE_CHANGESETAPPLY_IGNORENOOP <dd>
+** Do not invoke the conflict handler callback for any changes that
+** would not actually modify the database even if they were applied.
+** Specifically, this means that the conflict handler is not invoked
+** for:
+** <ul>
+** <li>a delete change if the row being deleted cannot be found,
+** <li>an update change if the modified fields are already set to
+** their new values in the conflicting row, or
+** <li>an insert change if all fields of the conflicting row match
+** the row being inserted.
+** </ul>
*/
#define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001
#define SQLITE_CHANGESETAPPLY_INVERT 0x0002
+#define SQLITE_CHANGESETAPPLY_IGNORENOOP 0x0004
/*
** CAPI3REF: Constants Passed To The Conflict Handler
diff --git a/src/libs/CMakeLists.txt b/src/libs/CMakeLists.txt
index 2ee109d5cd0..de2d2b01ef3 100644
--- a/src/libs/CMakeLists.txt
+++ b/src/libs/CMakeLists.txt
@@ -12,12 +12,15 @@ add_subdirectory(nanotrace)
add_subdirectory(qmldebug)
add_subdirectory(qmleditorwidgets)
add_subdirectory(qmljs)
-add_subdirectory(qmlpuppetcommunication)
add_subdirectory(qtcreatorcdbext)
+add_subdirectory(utils)
add_subdirectory(solutions)
-add_subdirectory(sqlite)
add_subdirectory(tracing)
-add_subdirectory(utils)
+
+if (WITH_QMLDESIGNER)
+ add_subdirectory(sqlite)
+ add_subdirectory(qmlpuppetcommunication)
+endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/qlitehtml/src/CMakeLists.txt)
option(BUILD_LIBRARY_QLITEHTML "Build library qlitehtml." ${BUILD_LIBRARIES_BY_DEFAULT})
diff --git a/src/libs/advanceddockingsystem/CMakeLists.txt b/src/libs/advanceddockingsystem/CMakeLists.txt
index f22d3befe8c..19d89f41d6c 100644
--- a/src/libs/advanceddockingsystem/CMakeLists.txt
+++ b/src/libs/advanceddockingsystem/CMakeLists.txt
@@ -1,5 +1,5 @@
add_qtc_library(AdvancedDockingSystem
- DEPENDS Qt::Widgets Qt::Core Qt::Gui Utils
+ DEPENDS Qt::Widgets Qt::Core Qt::Gui Qt::Xml Utils
SOURCES
ads_globals.cpp ads_globals.h
advanceddockingsystemtr.h
@@ -19,7 +19,9 @@ add_qtc_library(AdvancedDockingSystem
floatingdockcontainer.cpp floatingdockcontainer.h
floatingdragpreview.cpp floatingdragpreview.h
iconprovider.cpp iconprovider.h
+ workspace.cpp workspace.h
workspacedialog.cpp workspacedialog.h
+ workspaceinputdialog.cpp workspaceinputdialog.h
workspacemodel.cpp workspacemodel.h
workspaceview.cpp workspaceview.h
)
diff --git a/src/libs/advanceddockingsystem/dockcontainerwidget.cpp b/src/libs/advanceddockingsystem/dockcontainerwidget.cpp
index 253937c4d17..51ced580963 100644
--- a/src/libs/advanceddockingsystem/dockcontainerwidget.cpp
+++ b/src/libs/advanceddockingsystem/dockcontainerwidget.cpp
@@ -641,8 +641,8 @@ namespace ADS
stream.writeAttribute("orientation",
QVariant::fromValue(splitter->orientation()).toString());
stream.writeAttribute("count", QString::number(splitter->count()));
- qCInfo(adsLog) << "NodeSplitter orient: " << splitter->orientation()
- << " WidgetCont: " << splitter->count();
+ qCInfo(adsLog) << "NodeSplitter orientation:" << splitter->orientation()
+ << "WidgetCount:" << splitter->count();
for (int i = 0; i < splitter->count(); ++i)
saveChildNodesState(stream, splitter->widget(i));
@@ -678,8 +678,8 @@ namespace ADS
if (!ok)
return false;
- qCInfo(adsLog) << "Restore NodeSplitter Orientation: " << orientation
- << " WidgetCount: " << widgetCount;
+ qCInfo(adsLog) << "Restore NodeSplitter Orientation:" << orientation
+ << "WidgetCount:" << widgetCount;
QSplitter *splitter = nullptr;
if (!testing)
splitter = createSplitter(orientation);
diff --git a/src/libs/advanceddockingsystem/dockmanager.cpp b/src/libs/advanceddockingsystem/dockmanager.cpp
index 46e7b5e5af0..1b2a1c322a1 100644
--- a/src/libs/advanceddockingsystem/dockmanager.cpp
+++ b/src/libs/advanceddockingsystem/dockmanager.cpp
@@ -4,6 +4,7 @@
#include "dockmanager.h"
#include "ads_globals.h"
+#include "advanceddockingsystemtr.h"
#include "ads_globals_p.h"
#include "dockareawidget.h"
#include "dockfocuscontroller.h"
@@ -18,7 +19,6 @@
#include <utils/algorithm.h>
#include <utils/fileutils.h>
#include <utils/qtcassert.h>
-#include <utils/utilstr.h>
#include <algorithm>
#include <iostream>
@@ -27,8 +27,11 @@
#include <QApplication>
#include <QDateTime>
#include <QDir>
+#include <QDomDocument>
#include <QFile>
#include <QFileInfo>
+#include <QJsonArray>
+#include <QJsonDocument>
#include <QList>
#include <QLoggingCategory>
#include <QMainWindow>
@@ -43,1005 +46,1245 @@ Q_LOGGING_CATEGORY(adsLog, "qtc.qmldesigner.advanceddockingsystem", QtWarningMsg
using namespace Utils;
-namespace ADS
+namespace ADS {
+/**
+ * Internal file version in case the structure changes internally
+ */
+enum eStateFileVersion {
+ InitialVersion = 0, //!< InitialVersion
+ Version1 = 1, //!< Version1
+ CurrentVersion = Version1 //!< CurrentVersion
+};
+
+static DockManager::ConfigFlags g_staticConfigFlags = DockManager::DefaultNonOpaqueConfig;
+
+/**
+ * Private data class of DockManager class (pimpl)
+ */
+class DockManagerPrivate
{
+public:
+ DockManager *q;
+ QList<QPointer<FloatingDockContainer>> m_floatingWidgets;
+ QList<DockContainerWidget *> m_containers;
+ DockOverlay *m_containerOverlay = nullptr;
+ DockOverlay *m_dockAreaOverlay = nullptr;
+ QMap<QString, DockWidget *> m_dockWidgetsMap;
+ bool m_restoringState = false;
+ QVector<FloatingDockContainer *> m_uninitializedFloatingWidgets;
+ DockFocusController *m_focusController = nullptr;
+
+ QString m_workspacePresetsPath;
+ QList<Workspace> m_workspaces;
+ Workspace m_workspace;
+
+ QSettings *m_settings = nullptr;
+ bool m_modeChangeState = false;
+ bool m_workspaceOrderDirty = false;
+
/**
- * Internal file version in case the structure changes internally
+ * Private data constructor
*/
- enum eStateFileVersion {
- InitialVersion = 0, //!< InitialVersion
- Version1 = 1, //!< Version1
- CurrentVersion = Version1 //!< CurrentVersion
- };
+ DockManagerPrivate(DockManager *parent);
- static DockManager::ConfigFlags g_staticConfigFlags = DockManager::DefaultNonOpaqueConfig;
+ /**
+ * Restores the state. If testing is set to true it will check if
+ * the given data stream is a valid docking system state file.
+ */
+ bool restoreStateFromXml(const QByteArray &state, int version, bool testing = false);
/**
- * Private data class of DockManager class (pimpl)
+ * Restore state
*/
- class DockManagerPrivate
- {
- public:
- DockManager *q;
- QList<QPointer<FloatingDockContainer>> m_floatingWidgets;
- QList<DockContainerWidget *> m_containers;
- DockOverlay *m_containerOverlay = nullptr;
- DockOverlay *m_dockAreaOverlay = nullptr;
- QMap<QString, DockWidget *> m_dockWidgetsMap;
- bool m_restoringState = false;
- QVector<FloatingDockContainer *> m_uninitializedFloatingWidgets;
- DockFocusController *m_focusController = nullptr;
-
- QString m_workspaceName;
- bool m_workspaceListDirty = true;
- QStringList m_workspaces;
- QSet<QString> m_workspacePresets;
- QHash<QString, QDateTime> m_workspaceDateTimes;
- QString m_workspaceToRestoreAtStartup;
- bool m_autorestoreLastWorkspace; // This option is set in the Workspace Manager!
- QSettings *m_settings = nullptr;
- QString m_workspacePresetsPath;
- bool m_modeChangeState = false;
-
- /**
- * Private data constructor
- */
- DockManagerPrivate(DockManager *parent);
-
- /**
- * Restores the state. If testing is set to true it will check if
- * the given data stream is a valid docking system state file.
- */
- bool restoreStateFromXml(const QByteArray &state,
- int version,
- bool testing = false);
-
- /**
- * Restore state
- */
- bool restoreState(const QByteArray &state, int version);
-
- void restoreDockWidgetsOpenState();
- void restoreDockAreasIndices();
- void emitTopLevelEvents();
-
- void hideFloatingWidgets()
- {
- // Hide updates of floating widgets from user
- for (const auto &floatingWidget : std::as_const(m_floatingWidgets)) {
- if (floatingWidget)
- floatingWidget->hide();
- }
- }
+ bool restoreState(const QByteArray &state, int version);
- void markDockWidgetsDirty()
- {
- for (const auto &dockWidget : std::as_const(m_dockWidgetsMap))
- dockWidget->setProperty("dirty", true);
- }
+ void restoreDockWidgetsOpenState();
+ void restoreDockAreasIndices();
+ void emitTopLevelEvents();
- /**
- * Restores the container with the given index
- */
- bool restoreContainer(int index, DockingStateReader &stream, bool testing);
+ void hideFloatingWidgets()
+ {
+ // Hide updates of floating widgets from user
+ for (const auto &floatingWidget : std::as_const(m_floatingWidgets)) {
+ if (floatingWidget)
+ floatingWidget->hide();
+ }
+ }
- void workspaceLoadingProgress();
- }; // class DockManagerPrivate
+ void markDockWidgetsDirty()
+ {
+ for (const auto &dockWidget : std::as_const(m_dockWidgetsMap))
+ dockWidget->setProperty("dirty", true);
+ }
- DockManagerPrivate::DockManagerPrivate(DockManager *parent)
- : q(parent)
- {}
+ /**
+ * Restores the container with the given index
+ */
+ bool restoreContainer(int index, DockingStateReader &stream, bool testing);
- bool DockManagerPrivate::restoreContainer(int index, DockingStateReader &stream, bool testing)
- {
- if (testing)
- index = 0;
+ void workspaceLoadingProgress();
+}; // class DockManagerPrivate
- bool result = false;
- if (index >= m_containers.count()) {
- FloatingDockContainer *floatingWidget = new FloatingDockContainer(q);
- result = floatingWidget->restoreState(stream, testing);
- } else {
- qCInfo(adsLog) << "d->m_containers[i]->restoreState ";
- auto container = m_containers[index];
- if (container->isFloating())
- result = container->floatingWidget()->restoreState(stream, testing);
- else
- result = container->restoreState(stream, testing);
- }
+DockManagerPrivate::DockManagerPrivate(DockManager *parent)
+ : q(parent)
+{}
- return result;
+bool DockManagerPrivate::restoreContainer(int index, DockingStateReader &stream, bool testing)
+{
+ if (testing)
+ index = 0;
+
+ bool result = false;
+ if (index >= m_containers.count()) {
+ FloatingDockContainer *floatingWidget = new FloatingDockContainer(q);
+ result = floatingWidget->restoreState(stream, testing);
+ } else {
+ auto container = m_containers[index];
+ if (container->isFloating())
+ result = container->floatingWidget()->restoreState(stream, testing);
+ else
+ result = container->restoreState(stream, testing);
}
- bool DockManagerPrivate::restoreStateFromXml(const QByteArray &state, int version, bool testing)
- {
- Q_UNUSED(version) // TODO version is not needed, why is it in here in the first place?
+ return result;
+}
- if (state.isEmpty())
- return false;
+bool DockManagerPrivate::restoreStateFromXml(const QByteArray &state, int version, bool testing)
+{
+ Q_UNUSED(version) // TODO version is not needed, why is it in here in the first place?
- DockingStateReader stateReader(state);
- if (!stateReader.readNextStartElement())
- return false;
+ if (state.isEmpty())
+ return false;
- if (stateReader.name() != QLatin1String("QtAdvancedDockingSystem"))
- return false;
+ DockingStateReader stateReader(state);
+ if (!stateReader.readNextStartElement())
+ return false;
- qCInfo(adsLog) << stateReader.attributes().value("version");
- bool ok;
- int v = stateReader.attributes().value("version").toInt(&ok);
- if (!ok || v > CurrentVersion)
- return false;
+ if (stateReader.name() != QLatin1String("QtAdvancedDockingSystem"))
+ return false;
- stateReader.setFileVersion(v);
+ qCInfo(adsLog) << "Version" << stateReader.attributes().value("version");
+ bool ok;
+ int v = stateReader.attributes().value("version").toInt(&ok);
+ if (!ok || v > CurrentVersion)
+ return false;
- qCInfo(adsLog) << stateReader.attributes().value("userVersion");
- // Older files do not support UserVersion but we still want to load them so
- // we first test if the attribute exists
- if (!stateReader.attributes().value("userVersion").isEmpty())
- {
- v = stateReader.attributes().value("userVersion").toInt(&ok);
- if (!ok || v != version)
- return false;
- }
+ stateReader.setFileVersion(v);
- bool result = true;
+ qCInfo(adsLog) << "User version" << stateReader.attributes().value("userVersion");
+ // Older files do not support userVersion, but we still want to load them so we first test
+ // if the attribute exists.
+ if (!stateReader.attributes().value("userVersion").isEmpty()) {
+ v = stateReader.attributes().value("userVersion").toInt(&ok);
+ if (!ok || v != version)
+ return false;
+ }
+
+ bool result = true;
#ifdef ADS_DEBUG_PRINT
- int dockContainers = stateReader.attributes().value("containers").toInt();
- qCInfo(adsLog) << dockContainers;
+ int dockContainers = stateReader.attributes().value("containers").toInt();
+ qCInfo(adsLog) << dockContainers;
#endif
- int dockContainerCount = 0;
- while (stateReader.readNextStartElement()) {
- if (stateReader.name() == QLatin1String("container")) {
- result = restoreContainer(dockContainerCount, stateReader, testing);
- if (!result)
- break;
-
- dockContainerCount++;
- }
+ int dockContainerCount = 0;
+ while (stateReader.readNextStartElement()) {
+ if (stateReader.name() == QLatin1String("container")) {
+ result = restoreContainer(dockContainerCount, stateReader, testing);
+ if (!result)
+ break;
+
+ dockContainerCount++;
}
+ }
- if (!testing) {
- // Delete remaining empty floating widgets
- int floatingWidgetIndex = dockContainerCount - 1;
- int deleteCount = m_floatingWidgets.count() - floatingWidgetIndex;
- for (int i = 0; i < deleteCount; ++i) {
- m_floatingWidgets[floatingWidgetIndex + i]->deleteLater();
- q->removeDockContainer(m_floatingWidgets[floatingWidgetIndex + i]->dockContainer());
- }
+ if (!testing) {
+ // Delete remaining empty floating widgets
+ int floatingWidgetIndex = dockContainerCount - 1;
+ int deleteCount = m_floatingWidgets.count() - floatingWidgetIndex;
+ for (int i = 0; i < deleteCount; ++i) {
+ m_floatingWidgets[floatingWidgetIndex + i]->deleteLater();
+ q->removeDockContainer(m_floatingWidgets[floatingWidgetIndex + i]->dockContainer());
}
+ }
+
+ return result;
+}
- return result;
+void DockManagerPrivate::restoreDockWidgetsOpenState()
+{
+ // All dock widgets, that have not been processed in the restore state function are
+ // invisible to the user now and have no assigned dock area. They do not belong to any dock
+ // container, until the user toggles the toggle view action the next time.
+ for (auto dockWidget : std::as_const(m_dockWidgetsMap)) {
+ if (dockWidget->property(internal::dirtyProperty).toBool()) {
+ dockWidget->flagAsUnassigned();
+ emit dockWidget->viewToggled(false);
+ } else {
+ dockWidget->toggleViewInternal(!dockWidget->property(internal::closedProperty).toBool());
+ }
}
+}
- void DockManagerPrivate::restoreDockWidgetsOpenState()
- {
- // All dock widgets, that have not been processed in the restore state
- // function are invisible to the user now and have no assigned dock area
- // They do not belong to any dock container, until the user toggles the
- // toggle view action the next time
- for (auto dockWidget : std::as_const(m_dockWidgetsMap)) {
- if (dockWidget->property(internal::dirtyProperty).toBool()) {
- dockWidget->flagAsUnassigned();
- emit dockWidget->viewToggled(false);
+void DockManagerPrivate::restoreDockAreasIndices()
+{
+ // Now all dock areas are properly restored and we setup the index of the dock areas,
+ // because the previous toggleView() action has changed the dock area index.
+ for (auto dockContainer : std::as_const(m_containers)) {
+ for (int i = 0; i < dockContainer->dockAreaCount(); ++i) {
+ DockAreaWidget *dockArea = dockContainer->dockArea(i);
+ const QString dockWidgetName = dockArea->property("currentDockWidget").toString();
+ DockWidget *dockWidget = nullptr;
+ if (!dockWidgetName.isEmpty())
+ dockWidget = q->findDockWidget(dockWidgetName);
+
+ if (!dockWidget || dockWidget->isClosed()) {
+ int index = dockArea->indexOfFirstOpenDockWidget();
+ if (index < 0)
+ continue;
+
+ dockArea->setCurrentIndex(index);
} else {
- dockWidget->toggleViewInternal(
- !dockWidget->property(internal::closedProperty).toBool());
+ dockArea->internalSetCurrentDockWidget(dockWidget);
}
}
}
+}
- void DockManagerPrivate::restoreDockAreasIndices()
- {
- // Now all dock areas are properly restored and we setup the index of
- // The dock areas because the previous toggleView() action has changed
- // the dock area index
- int count = 0;
- for (auto dockContainer : std::as_const(m_containers)) {
- count++;
+void DockManagerPrivate::emitTopLevelEvents()
+{
+ // Finally we need to send the topLevelChanged() signals for all dock widgets if top
+ // level changed.
+ for (auto dockContainer : std::as_const(m_containers)) {
+ DockWidget *topLevelDockWidget = dockContainer->topLevelDockWidget();
+ if (topLevelDockWidget) {
+ topLevelDockWidget->emitTopLevelChanged(true);
+ } else {
for (int i = 0; i < dockContainer->dockAreaCount(); ++i) {
- DockAreaWidget *dockArea = dockContainer->dockArea(i);
- QString dockWidgetName = dockArea->property("currentDockWidget").toString();
- DockWidget *dockWidget = nullptr;
- if (!dockWidgetName.isEmpty())
- dockWidget = q->findDockWidget(dockWidgetName);
-
- if (!dockWidget || dockWidget->isClosed()) {
- int index = dockArea->indexOfFirstOpenDockWidget();
- if (index < 0)
- continue;
-
- dockArea->setCurrentIndex(index);
- } else {
- dockArea->internalSetCurrentDockWidget(dockWidget);
- }
+ auto dockArea = dockContainer->dockArea(i);
+ for (auto dockWidget : dockArea->dockWidgets())
+ dockWidget->emitTopLevelChanged(false);
}
}
}
+}
- void DockManagerPrivate::emitTopLevelEvents()
- {
- // Finally we need to send the topLevelChanged() signals for all dock
- // widgets if top level changed
- for (auto dockContainer : std::as_const(m_containers)) {
- DockWidget *topLevelDockWidget = dockContainer->topLevelDockWidget();
- if (topLevelDockWidget) {
- topLevelDockWidget->emitTopLevelChanged(true);
- } else {
- for (int i = 0; i < dockContainer->dockAreaCount(); ++i) {
- auto dockArea = dockContainer->dockArea(i);
- for (auto dockWidget : dockArea->dockWidgets())
- dockWidget->emitTopLevelChanged(false);
- }
- }
- }
+bool DockManagerPrivate::restoreState(const QByteArray &state, int version)
+{
+ QByteArray currentState = state.startsWith("<?xml") ? state : qUncompress(state);
+ // Check the format of the given data stream
+ if (!restoreStateFromXml(currentState, version, true)) {
+ qWarning() << "CheckFormat: Error checking format!";
+ return false;
}
- bool DockManagerPrivate::restoreState(const QByteArray &state, int version)
- {
- QByteArray currentState = state.startsWith("<?xml") ? state : qUncompress(state);
- // Check the format of the given data stream
- if (!restoreStateFromXml(currentState, version, true)) {
- qCInfo(adsLog) << "checkFormat: Error checking format!!!";
- return false;
- }
+ // Hide updates of floating widgets from user
+ hideFloatingWidgets();
+ markDockWidgetsDirty();
- // Hide updates of floating widgets from use
- hideFloatingWidgets();
- markDockWidgetsDirty();
+ if (!restoreStateFromXml(currentState, version)) {
+ qWarning() << "RestoreState: Error restoring state!";
+ return false;
+ }
- if (!restoreStateFromXml(currentState, version)) {
- qCInfo(adsLog) << "restoreState: Error restoring state!!!";
- return false;
- }
+ restoreDockWidgetsOpenState();
+ restoreDockAreasIndices();
+ emitTopLevelEvents();
- restoreDockWidgetsOpenState();
- restoreDockAreasIndices();
- emitTopLevelEvents();
+ return true;
+}
- return true;
- }
+DockManager::DockManager(QWidget *parent)
+ : DockContainerWidget(this, parent)
+ , d(new DockManagerPrivate(this))
+{
+ connect(this, &DockManager::workspaceListChanged, this, [=] {
+ d->m_workspaceOrderDirty = true;
+ });
- DockManager::DockManager(QWidget *parent)
- : DockContainerWidget(this, parent)
- , d(new DockManagerPrivate(this))
- {
- connect(this, &DockManager::workspaceListChanged, this, [=] {
- d->m_workspaceListDirty = true;
- });
+ createRootSplitter();
+ QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parent);
+ if (mainWindow)
+ mainWindow->setCentralWidget(this);
- createRootSplitter();
- QMainWindow *mainWindow = qobject_cast<QMainWindow *>(parent);
- if (mainWindow) {
- mainWindow->setCentralWidget(this);
- }
+ d->m_dockAreaOverlay = new DockOverlay(this, DockOverlay::ModeDockAreaOverlay);
+ d->m_containerOverlay = new DockOverlay(this, DockOverlay::ModeContainerOverlay);
+ d->m_containers.append(this);
- d->m_dockAreaOverlay = new DockOverlay(this, DockOverlay::ModeDockAreaOverlay);
- d->m_containerOverlay = new DockOverlay(this, DockOverlay::ModeContainerOverlay);
- d->m_containers.append(this);
+ if (DockManager::configFlags().testFlag(DockManager::FocusHighlighting))
+ d->m_focusController = new DockFocusController(this);
+}
- if (DockManager::configFlags().testFlag(DockManager::FocusHighlighting))
- d->m_focusController = new DockFocusController(this);
+DockManager::~DockManager()
+{
+ emit aboutToUnloadWorkspace(d->m_workspace.fileName());
+ save();
+ saveStartupWorkspace();
+
+ // Using a temporary vector since the destructor of FloatingDockWidgetContainer
+ // alters d->m_floatingWidgets.
+ const auto copy = d->m_floatingWidgets;
+ for (const auto &floatingWidget : copy) {
+ if (floatingWidget)
+ delete floatingWidget.get();
}
+ delete d;
+}
- DockManager::~DockManager()
- {
- emit aboutToUnloadWorkspace(d->m_workspaceName);
- save();
- saveStartupWorkspace();
-
- // Using a temporal vector since the destructor of
- // FloatingDockWidgetContainer alters d->m_floatingWidgets.
- const auto copy = d->m_floatingWidgets;
- for (const auto &floatingWidget : copy) {
- if (floatingWidget)
- delete floatingWidget.get();
- }
- delete d;
- }
+DockManager::ConfigFlags DockManager::configFlags()
+{
+ return g_staticConfigFlags;
+}
- DockManager::ConfigFlags DockManager::configFlags() { return g_staticConfigFlags; }
+void DockManager::setConfigFlags(const ConfigFlags flags)
+{
+ g_staticConfigFlags = flags;
+}
- void DockManager::setConfigFlags(const ConfigFlags flags) { g_staticConfigFlags = flags; }
+void DockManager::setConfigFlag(eConfigFlag flag, bool on)
+{
+ internal::setFlag(g_staticConfigFlags, flag, on);
+}
- void DockManager::setConfigFlag(eConfigFlag flag, bool on)
- {
- internal::setFlag(g_staticConfigFlags, flag, on);
- }
+bool DockManager::testConfigFlag(eConfigFlag flag)
+{
+ return configFlags().testFlag(flag);
+}
- bool DockManager::testConfigFlag(eConfigFlag flag)
- {
- return configFlags().testFlag(flag);
- }
+IconProvider &DockManager::iconProvider()
+{
+ static IconProvider instance;
+ return instance;
+}
- IconProvider &DockManager::iconProvider()
- {
- static IconProvider instance;
- return instance;
- }
+int DockManager::startDragDistance()
+{
+ return static_cast<int>(QApplication::startDragDistance() * 1.5);
+}
- int DockManager::startDragDistance()
- {
- return static_cast<int>(QApplication::startDragDistance() * 1.5);
- }
+void DockManager::setSettings(QSettings *settings)
+{
+ d->m_settings = settings;
+}
- void DockManager::setSettings(QSettings *settings) { d->m_settings = settings; }
+void DockManager::setWorkspacePresetsPath(const QString &path)
+{
+ d->m_workspacePresetsPath = path;
+}
- void DockManager::setWorkspacePresetsPath(const QString &path) { d->m_workspacePresetsPath = path; }
+void DockManager::initialize()
+{
+ qCInfo(adsLog) << "Initialize DockManager";
- DockAreaWidget *DockManager::addDockWidget(DockWidgetArea area,
- DockWidget *dockWidget,
- DockAreaWidget *dockAreaWidget)
- {
- d->m_dockWidgetsMap.insert(dockWidget->objectName(), dockWidget);
- return DockContainerWidget::addDockWidget(area, dockWidget, dockAreaWidget);
- }
+ // Can't continue if settings are not set yet
+ QTC_ASSERT(d->m_settings, return);
- void DockManager::initialize()
- {
- syncWorkspacePresets();
+ syncWorkspacePresets();
+ prepareWorkspaces();
- QString workspace = ADS::Constants::DEFAULT_WORKSPACE;
+ QString workspace = ADS::Constants::DEFAULT_WORKSPACE;
- // Determine workspace to restore at startup
- if (autoRestorLastWorkspace()) {
- QString lastWS = lastWorkspace();
- if (!lastWS.isEmpty() && workspaces().contains(lastWS))
- workspace = lastWS;
- else
- qDebug() << "Couldn't restore last workspace!";
- }
+ // Determine workspace to restore at startup
+ if (autoRestoreWorkspace()) {
+ const QString lastWorkspace = startupWorkspace();
+ if (!lastWorkspace.isEmpty()) {
+ if (!workspaceExists(lastWorkspace)) {
+ // This is a fallback mechanism for pre 4.1 settings which stored the workspace name
+ // instead of the file name.
+ QString minusVariant = lastWorkspace;
+ minusVariant.replace(" ", "-");
+ minusVariant.append("." + workspaceFileExtension);
- openWorkspace(workspace);
- }
+ if (workspaceExists(minusVariant))
+ workspace = minusVariant;
- DockAreaWidget *DockManager::addDockWidgetTab(DockWidgetArea area, DockWidget *dockWidget)
- {
- DockAreaWidget *areaWidget = lastAddedDockAreaWidget(area);
- if (areaWidget)
- return addDockWidget(ADS::CenterDockWidgetArea, dockWidget, areaWidget);
- else if (!openedDockAreas().isEmpty())
- return addDockWidget(area, dockWidget, openedDockAreas().constLast());
- else
- return addDockWidget(area, dockWidget, nullptr);
- }
+ QString underscoreVariant = lastWorkspace;
+ underscoreVariant.replace(" ", "_");
+ underscoreVariant.append("." + workspaceFileExtension);
- DockAreaWidget *DockManager::addDockWidgetTabToArea(DockWidget *dockWidget,
- DockAreaWidget *dockAreaWidget)
- {
- return addDockWidget(ADS::CenterDockWidgetArea, dockWidget, dockAreaWidget);
+ if (workspaceExists(underscoreVariant))
+ workspace = underscoreVariant;
+ } else {
+ workspace = lastWorkspace;
+ }
+ } else
+ qWarning() << "Could not restore workspace:" << lastWorkspace;
}
- FloatingDockContainer *DockManager::addDockWidgetFloating(DockWidget *dockWidget)
- {
- d->m_dockWidgetsMap.insert(dockWidget->objectName(), dockWidget);
- DockAreaWidget *oldDockArea = dockWidget->dockAreaWidget();
- if (oldDockArea)
- oldDockArea->removeDockWidget(dockWidget);
-
- dockWidget->setDockManager(this);
- FloatingDockContainer *floatingWidget = new FloatingDockContainer(dockWidget);
- floatingWidget->resize(dockWidget->size());
- if (isVisible())
- floatingWidget->show();
- else
- d->m_uninitializedFloatingWidgets.append(floatingWidget);
+ openWorkspace(workspace);
+}
- return floatingWidget;
- }
+DockAreaWidget *DockManager::addDockWidget(DockWidgetArea area,
+ DockWidget *dockWidget,
+ DockAreaWidget *dockAreaWidget)
+{
+ d->m_dockWidgetsMap.insert(dockWidget->objectName(), dockWidget);
+ return DockContainerWidget::addDockWidget(area, dockWidget, dockAreaWidget);
+}
- void DockManager::registerFloatingWidget(FloatingDockContainer *floatingWidget)
- {
- d->m_floatingWidgets.append(floatingWidget);
- emit floatingWidgetCreated(floatingWidget);
- qCInfo(adsLog) << "d->FloatingWidgets.count() " << d->m_floatingWidgets.count();
- }
+DockAreaWidget *DockManager::addDockWidgetTab(DockWidgetArea area, DockWidget *dockWidget)
+{
+ DockAreaWidget *areaWidget = lastAddedDockAreaWidget(area);
+ if (areaWidget)
+ return addDockWidget(ADS::CenterDockWidgetArea, dockWidget, areaWidget);
+ else if (!openedDockAreas().isEmpty())
+ return addDockWidget(area, dockWidget, openedDockAreas().constLast());
+ else
+ return addDockWidget(area, dockWidget, nullptr);
+}
+
+DockAreaWidget *DockManager::addDockWidgetTabToArea(DockWidget *dockWidget,
+ DockAreaWidget *dockAreaWidget)
+{
+ return addDockWidget(ADS::CenterDockWidgetArea, dockWidget, dockAreaWidget);
+}
- void DockManager::removeFloatingWidget(FloatingDockContainer *floatingWidget)
- {
- d->m_floatingWidgets.removeAll(floatingWidget);
- }
+FloatingDockContainer *DockManager::addDockWidgetFloating(DockWidget *dockWidget)
+{
+ d->m_dockWidgetsMap.insert(dockWidget->objectName(), dockWidget);
+ DockAreaWidget *oldDockArea = dockWidget->dockAreaWidget();
+ if (oldDockArea)
+ oldDockArea->removeDockWidget(dockWidget);
+
+ dockWidget->setDockManager(this);
+ FloatingDockContainer *floatingWidget = new FloatingDockContainer(dockWidget);
+ floatingWidget->resize(dockWidget->size());
+ if (isVisible())
+ floatingWidget->show();
+ else
+ d->m_uninitializedFloatingWidgets.append(floatingWidget);
+
+ return floatingWidget;
+}
+
+DockWidget *DockManager::findDockWidget(const QString &objectName) const
+{
+ return d->m_dockWidgetsMap.value(objectName, nullptr);
+}
- void DockManager::registerDockContainer(DockContainerWidget *dockContainer)
- {
- d->m_containers.append(dockContainer);
- }
+void DockManager::removeDockWidget(DockWidget *dockWidget)
+{
+ emit dockWidgetAboutToBeRemoved(dockWidget);
+ d->m_dockWidgetsMap.remove(dockWidget->objectName());
+ DockContainerWidget::removeDockWidget(dockWidget);
+ emit dockWidgetRemoved(dockWidget);
+}
- void DockManager::removeDockContainer(DockContainerWidget *dockContainer)
- {
- if (this != dockContainer)
- d->m_containers.removeAll(dockContainer);
- }
+QMap<QString, DockWidget *> DockManager::dockWidgetsMap() const
+{
+ return d->m_dockWidgetsMap;
+}
- DockOverlay *DockManager::containerOverlay() const { return d->m_containerOverlay; }
+const QList<DockContainerWidget *> DockManager::dockContainers() const
+{
+ return d->m_containers;
+}
- DockOverlay *DockManager::dockAreaOverlay() const { return d->m_dockAreaOverlay; }
+const QList<QPointer<FloatingDockContainer>> DockManager::floatingWidgets() const
+{
+ return d->m_floatingWidgets;
+}
- const QList<DockContainerWidget *> DockManager::dockContainers() const
- {
- return d->m_containers;
- }
+unsigned int DockManager::zOrderIndex() const
+{
+ return 0;
+}
- const QList<QPointer<FloatingDockContainer>> DockManager::floatingWidgets() const
- {
- return d->m_floatingWidgets;
- }
+QByteArray DockManager::saveState(const QString &displayName, int version) const
+{
+ qCInfo(adsLog) << "Save state" << displayName;
+
+ QByteArray xmlData;
+ QXmlStreamWriter stream(&xmlData);
+ auto configFlags = DockManager::configFlags();
+ stream.setAutoFormatting(configFlags.testFlag(XmlAutoFormattingEnabled));
+ stream.setAutoFormattingIndent(workspaceXmlFormattingIndent);
+ stream.writeStartDocument();
+ stream.writeStartElement("QtAdvancedDockingSystem");
+ stream.writeAttribute("version", QString::number(CurrentVersion));
+ stream.writeAttribute("userVersion", QString::number(version));
+ stream.writeAttribute("containers", QString::number(d->m_containers.count()));
+ stream.writeAttribute(workspaceDisplayNameAttribute.toString(), displayName);
+ for (auto container : std::as_const(d->m_containers))
+ container->saveState(stream);
+
+ stream.writeEndElement();
+ stream.writeEndDocument();
+ return xmlData;
+}
+
+bool DockManager::restoreState(const QByteArray &state, int version)
+{
+ // Prevent multiple calls as long as state is not restore. This may happen, if
+ // QApplication::processEvents() is called somewhere.
+ if (d->m_restoringState)
+ return false;
- unsigned int DockManager::zOrderIndex() const { return 0; }
+ // We hide the complete dock manager here. Restoring the state means that DockWidgets are
+ // removed from the DockArea internal stack layout which in turn means, that each time a
+ // widget is removed the stack will show and raise the next available widget which in turn
+ // triggers show events for the dock widgets. To avoid this we hide the dock manager.
+ // Because there will be no processing of application events until this function is
+ // finished, the user will not see this hiding.
+ bool isHidden = this->isHidden();
+ if (!isHidden)
+ hide();
+
+ d->m_restoringState = true;
+ emit restoringState();
+ bool result = d->restoreState(state, version);
+ d->m_restoringState = false;
+ if (!isHidden)
+ show();
+
+ emit stateRestored();
+ return result;
+}
+
+bool DockManager::isRestoringState() const
+{
+ return d->m_restoringState;
+}
- QByteArray DockManager::saveState(int version) const
- {
- QByteArray xmlData;
- QXmlStreamWriter stream(&xmlData);
- auto configFlags = DockManager::configFlags();
- stream.setAutoFormatting(configFlags.testFlag(XmlAutoFormattingEnabled));
- stream.writeStartDocument();
- stream.writeStartElement("QtAdvancedDockingSystem");
- stream.writeAttribute("version", QString::number(CurrentVersion));
- stream.writeAttribute("userVersion", QString::number(version));
- stream.writeAttribute("containers", QString::number(d->m_containers.count()));
- for (auto container : std::as_const(d->m_containers))
- container->saveState(stream);
-
- stream.writeEndElement();
- stream.writeEndDocument();
- return xmlData;
- }
+void DockManager::setDockWidgetFocused(DockWidget *dockWidget)
+{
+ if (d->m_focusController)
+ d->m_focusController->setDockWidgetFocused(dockWidget);
+}
- bool DockManager::restoreState(const QByteArray &state, int version)
- {
- // Prevent multiple calls as long as state is not restore. This may
- // happen, if QApplication::processEvents() is called somewhere
- if (d->m_restoringState)
- return false;
+void DockManager::registerFloatingWidget(FloatingDockContainer *floatingWidget)
+{
+ d->m_floatingWidgets.append(floatingWidget);
+ emit floatingWidgetCreated(floatingWidget);
+ qCInfo(adsLog) << "d->FloatingWidgets.count() " << d->m_floatingWidgets.count();
+}
- // We hide the complete dock manager here. Restoring the state means
- // that DockWidgets are removed from the DockArea internal stack layout
- // which in turn means, that each time a widget is removed the stack
- // will show and raise the next available widget which in turn
- // triggers show events for the dock widgets. To avoid this we hide the
- // dock manager. Because there will be no processing of application
- // events until this function is finished, the user will not see this
- // hiding
- bool isHidden = this->isHidden();
- if (!isHidden)
- hide();
-
- d->m_restoringState = true;
- emit restoringState();
- bool result = d->restoreState(state, version);
- d->m_restoringState = false;
- if (!isHidden)
- show();
-
- emit stateRestored();
- return result;
- }
+void DockManager::removeFloatingWidget(FloatingDockContainer *floatingWidget)
+{
+ d->m_floatingWidgets.removeAll(floatingWidget);
+}
- void DockManager::showEvent(QShowEvent *event)
- {
- Super::showEvent(event);
- if (d->m_uninitializedFloatingWidgets.empty())
- return;
+void DockManager::registerDockContainer(DockContainerWidget *dockContainer)
+{
+ d->m_containers.append(dockContainer);
+}
- for (auto floatingWidget : std::as_const(d->m_uninitializedFloatingWidgets))
- floatingWidget->show();
+void DockManager::removeDockContainer(DockContainerWidget *dockContainer)
+{
+ if (this != dockContainer)
+ d->m_containers.removeAll(dockContainer);
+}
- d->m_uninitializedFloatingWidgets.clear();
- }
+DockOverlay *DockManager::containerOverlay() const
+{
+ return d->m_containerOverlay;
+}
- DockWidget *DockManager::findDockWidget(const QString &objectName) const
- {
- return d->m_dockWidgetsMap.value(objectName, nullptr);
- }
+DockOverlay *DockManager::dockAreaOverlay() const
+{
+ return d->m_dockAreaOverlay;
+}
- void DockManager::removeDockWidget(DockWidget *dockWidget)
- {
- emit dockWidgetAboutToBeRemoved(dockWidget);
- d->m_dockWidgetsMap.remove(dockWidget->objectName());
- DockContainerWidget::removeDockWidget(dockWidget);
- emit dockWidgetRemoved(dockWidget);
- }
+void DockManager::notifyWidgetOrAreaRelocation(QWidget *droppedWidget)
+{
+ if (d->m_focusController)
+ d->m_focusController->notifyWidgetOrAreaRelocation(droppedWidget);
+}
- QMap<QString, DockWidget *> DockManager::dockWidgetsMap() const { return d->m_dockWidgetsMap; }
+void DockManager::notifyFloatingWidgetDrop(FloatingDockContainer *floatingWidget)
+{
+ if (d->m_focusController)
+ d->m_focusController->notifyFloatingWidgetDrop(floatingWidget);
+}
- bool DockManager::isRestoringState() const { return d->m_restoringState; }
+void DockManager::notifyDockWidgetRelocation(DockWidget *, DockContainerWidget *) {}
- void DockManager::showWorkspaceMananger()
- {
- save(); // Save current workspace
+void DockManager::notifyDockAreaRelocation(DockAreaWidget *, DockContainerWidget *) {}
- WorkspaceDialog workspaceDialog(this, parentWidget());
- workspaceDialog.setAutoLoadWorkspace(autoRestorLastWorkspace());
- workspaceDialog.exec();
+void DockManager::showEvent(QShowEvent *event)
+{
+ Super::showEvent(event);
+ if (d->m_uninitializedFloatingWidgets.empty())
+ return;
- QTC_ASSERT(d->m_settings, return );
- d->m_settings->setValue(Constants::AUTO_RESTORE_WORKSPACE_SETTINGS_KEY,
- workspaceDialog.autoLoadWorkspace());
- }
+ for (auto floatingWidget : std::as_const(d->m_uninitializedFloatingWidgets))
+ floatingWidget->show();
- bool DockManager::isWorkspacePreset(const QString &workspace) const
- {
- return d->m_workspacePresets.contains(workspace);
- }
+ d->m_uninitializedFloatingWidgets.clear();
+}
- bool DockManager::save()
- {
- if (isModeChangeState())
- return false;
+Workspace *DockManager::activeWorkspace() const
+{
+ return &d->m_workspace;
+}
- emit aboutToSaveWorkspace();
+QString DockManager::startupWorkspace() const
+{
+ QTC_ASSERT(d->m_settings, return {});
+ return d->m_settings->value(Constants::STARTUP_WORKSPACE_SETTINGS_KEY).toString();
+}
- bool result = write(activeWorkspace(), saveState(), parentWidget());
- if (result)
- d->m_workspaceDateTimes.insert(activeWorkspace(), QDateTime::currentDateTime());
- else
- QMessageBox::warning(parentWidget(),
- Tr::tr("Cannot Save Workspace"),
- Tr::tr("Could not save workspace to file %1")
- .arg(workspaceNameToFilePath(d->m_workspaceName)
- .toUserOutput()));
+bool DockManager::autoRestoreWorkspace() const
+{
+ QTC_ASSERT(d->m_settings, return false);
+ return d->m_settings->value(Constants::AUTO_RESTORE_WORKSPACE_SETTINGS_KEY).toBool();
+}
- return result;
- }
+const QList<Workspace> &DockManager::workspaces() const
+{
+ return d->m_workspaces;
+}
- QString DockManager::activeWorkspace() const { return d->m_workspaceName; }
+int DockManager::workspaceIndex(const QString &fileName) const
+{
+ return Utils::indexOf(d->m_workspaces, [&fileName](const Workspace &workspace) {
+ return workspace == fileName;
+ });
+}
- QString DockManager::lastWorkspace() const
- {
- QTC_ASSERT(d->m_settings, return {});
- return d->m_settings->value(Constants::STARTUP_WORKSPACE_SETTINGS_KEY).toString();
- }
+bool DockManager::workspaceExists(const QString &fileName) const
+{
+ return workspaceIndex(fileName) >= 0;
+}
- bool DockManager::autoRestorLastWorkspace() const
- {
- QTC_ASSERT(d->m_settings, return false);
- return d->m_settings->value(Constants::AUTO_RESTORE_WORKSPACE_SETTINGS_KEY).toBool();
- }
+Workspace *DockManager::workspace(const QString &fileName) const
+{
+ auto result = std::find_if(std::begin(d->m_workspaces),
+ std::end(d->m_workspaces),
+ [&fileName](const Workspace &workspace) {
+ return workspace == fileName;
+ });
- constexpr QStringView m_dirName{u"workspaces"};
- constexpr QStringView m_fileExt{u".wrk"}; // TODO
+ if (result != std::end(d->m_workspaces))
+ return &*result;
- QStringView DockManager::workspaceFileExtension() const
- {
- return m_fileExt;
- }
+ return nullptr;
+}
- QStringList DockManager::workspaces()
- {
- if (d->m_workspaces.isEmpty() || d->m_workspaceListDirty) {
- auto tmp = Utils::toSet(d->m_workspaces);
-
- QTC_ASSERT(d->m_settings, return {});
- QDir workspaceDir(QFileInfo(d->m_settings->fileName()).path() + QLatin1Char('/')
- + m_dirName);
- QFileInfoList workspaceFiles
- = workspaceDir.entryInfoList(QStringList() << QLatin1Char('*') + m_fileExt,
- QDir::NoFilter,
- QDir::Time);
- for (const QFileInfo &fileInfo : workspaceFiles) {
- QString workspaceName = fileNameToWorkspaceName(fileInfo.completeBaseName());
- d->m_workspaceDateTimes.insert(workspaceName, fileInfo.lastModified());
- tmp.insert(workspaceName);
- }
+Workspace *DockManager::workspace(int index) const
+{
+ if (index < 0 || index >= d->m_workspaces.count())
+ return nullptr;
- d->m_workspaceListDirty = false;
- d->m_workspaces = Utils::toList(tmp);
- }
- return d->m_workspaces;
- }
+ return &d->m_workspaces[index];
+}
- QSet<QString> DockManager::workspacePresets() const
- {
- if (d->m_workspacePresets.isEmpty()) {
- QDir workspacePresetsDir(d->m_workspacePresetsPath);
- QFileInfoList workspacePresetsFiles
- = workspacePresetsDir.entryInfoList(QStringList() << QLatin1Char('*') + m_fileExt,
- QDir::NoFilter,
- QDir::Time);
- for (const QFileInfo &fileInfo : workspacePresetsFiles)
- d->m_workspacePresets.insert(fileNameToWorkspaceName(fileInfo.completeBaseName()));
- }
- return d->m_workspacePresets;
- }
+QDateTime DockManager::workspaceDateTime(const QString &fileName) const
+{
+ Workspace *w = workspace(fileName);
- QDateTime DockManager::workspaceDateTime(const QString &workspace) const
- {
- return d->m_workspaceDateTimes.value(workspace);
- }
+ if (w)
+ return w->lastModified();
- FilePath DockManager::workspaceNameToFilePath(const QString &workspaceName) const
- {
- QTC_ASSERT(d->m_settings, return {});
- return FilePath::fromString(QFileInfo(d->m_settings->fileName()).path() + QLatin1Char('/')
- + m_dirName + QLatin1Char('/')
- + workspaceNameToFileName(workspaceName));
- }
+ return QDateTime();
+}
- QString DockManager::fileNameToWorkspaceName(const QString &fileName) const
- {
- QString copy = QFileInfo(fileName).baseName();
- copy.replace("_", " ");
- return copy;
- }
+bool DockManager::moveWorkspace(int from, int to)
+{
+ qCInfo(adsLog) << "Move workspaces" << from << ">" << to;
- QString DockManager::workspaceNameToFileName(const QString &workspaceName) const
- {
- QString copy = workspaceName;
- copy.replace(" ", "_");
- copy.append(m_fileExt);
- return copy;
- }
+ int c = d->m_workspaces.count();
- /**
- * Creates \a workspace, but does not actually create the file.
- */
- bool DockManager::createWorkspace(const QString &workspace)
- {
- if (workspaces().contains(workspace))
- return false;
+ from = std::clamp(from, 0, c);
+ to = std::clamp(to, 0, c);
- bool result = write(workspace, saveState(), parentWidget());
- if (result) {
- d->m_workspaces.insert(1, workspace);
- d->m_workspaceDateTimes.insert(workspace, QDateTime::currentDateTime());
- emit workspaceListChanged();
- } else {
- QMessageBox::warning(parentWidget(),
- Tr::tr("Cannot Save Workspace"),
- Tr::tr("Could not save workspace to file %1")
- .arg(workspaceNameToFilePath(d->m_workspaceName)
- .toUserOutput()));
- }
+ if (from == to)
+ return false;
- return result;
- }
+ d->m_workspaces.move(from, to);
+ emit workspaceListChanged();
- bool DockManager::openWorkspace(const QString &workspace)
- {
- // Do nothing if we have that workspace already loaded, exception if it is
- // a preset workspace. In this case we still want to be able to load the
- // default workspace to undo potential user changes.
- if (workspace == d->m_workspaceName && !isWorkspacePreset(workspace))
- return true;
+ return true;
+}
- if (!workspaces().contains(workspace))
- return false;
+bool DockManager::moveWorkspaceUp(const QString &fileName)
+{
+ qCInfo(adsLog) << "Move workspace up" << fileName;
- // Check if the currently active workspace isn't empty and try to save it
- if (!d->m_workspaceName.isEmpty()) {
- // Allow everyone to set something in the workspace and before saving
- emit aboutToUnloadWorkspace(d->m_workspaceName);
- if (!save())
- return false;
- }
+ int i = workspaceIndex(fileName);
- // Try loading the file
- QByteArray data = loadWorkspace(workspace);
- if (data.isEmpty())
- return false;
+ // If workspace does not exist or is first item
+ if (i <= 0)
+ return false;
- emit openingWorkspace(workspace);
- // If data was loaded from file try to restore its state
- if (!data.isNull() && !restoreState(data))
- return false;
+ d->m_workspaces.swapItemsAt(i, i - 1);
+ emit workspaceListChanged();
- d->m_workspaceName = workspace;
- emit workspaceLoaded(workspace);
+ return true;
+}
- return true;
- }
+bool DockManager::moveWorkspaceDown(const QString &fileName)
+{
+ qCInfo(adsLog) << "Move workspace down" << fileName;
- bool DockManager::reloadActiveWorkspace()
- {
- if (!workspaces().contains(activeWorkspace()))
- return false;
+ int i = workspaceIndex(fileName);
+ int c = d->m_workspaces.count();
- // Try loading the file
- QByteArray data = loadWorkspace(activeWorkspace());
- if (data.isEmpty())
- return false;
+ // If workspace does not exist or is last item
+ if (i < 0 || i >= (c - 1))
+ return false;
- // If data was loaded from file try to restore its state
- if (!data.isNull() && !restoreState(data))
- return false;
+ d->m_workspaces.swapItemsAt(i, i + 1);
+ emit workspaceListChanged();
- emit workspaceReloaded(activeWorkspace());
+ return true;
+}
- return true;
- }
+FilePath DockManager::workspaceNameToFilePath(const QString &workspaceName) const
+{
+ QTC_ASSERT(d->m_settings, return {});
+ return userDirectory().pathAppended(workspaceNameToFileName(workspaceName));
+}
- /**
- * \brief Shows a dialog asking the user to confirm deleting the workspace \p workspace
- */
- bool DockManager::confirmWorkspaceDelete(const QStringList &workspace)
- {
- const QString title = workspace.size() == 1 ? Tr::tr("Delete Workspace")
- : Tr::tr("Delete Workspaces");
- const QString question = workspace.size() == 1
- ? Tr::tr("Delete workspace %1?").arg(workspace.first())
- : Tr::tr("Delete these workspaces?\n %1")
- .arg(workspace.join("\n "));
- return QMessageBox::question(parentWidget(),
- title,
- question,
- QMessageBox::Yes | QMessageBox::No)
- == QMessageBox::Yes;
+QString DockManager::workspaceNameToFileName(const QString &workspaceName) const
+{
+ QString copy = workspaceName;
+ copy.replace(" ", "-");
+ copy.append("." + workspaceFileExtension);
+ return copy;
+}
+
+void DockManager::uniqueWorkspaceFileName(QString &fileName) const
+{
+ auto filePath = FilePath::fromString(fileName);
+
+ if (workspaceExists(fileName)) {
+ int i = 1;
+ QString copy;
+ do {
+ copy = filePath.baseName() + QString::number(i) + "." + filePath.completeSuffix();
+ ++i;
+ } while (workspaceExists(copy));
+ fileName = copy;
}
+}
- /**
- * Deletes \a workspace name from workspace list and the file from disk.
- */
- bool DockManager::deleteWorkspace(const QString &workspace)
- {
- // Remove workspace from internal list
- if (!d->m_workspaces.contains(workspace))
- return false;
+void DockManager::showWorkspaceMananger()
+{
+ save(); // Save current workspace
- // Remove corresponding workspace file
- const FilePath file = workspaceNameToFilePath(workspace);
- if (file.exists()) {
- if (file.removeFile()) {
- d->m_workspaces.removeOne(workspace);
- emit workspacesRemoved();
- emit workspaceListChanged();
- return true;
- }
- }
+ WorkspaceDialog workspaceDialog(this, parentWidget());
+ workspaceDialog.setAutoLoadWorkspace(autoRestoreWorkspace());
+ workspaceDialog.exec();
- return false;
+ if (d->m_workspaceOrderDirty) {
+ writeOrder();
+ d->m_workspaceOrderDirty = false;
}
- void DockManager::deleteWorkspaces(const QStringList &workspaces)
- {
- for (const QString &workspace : workspaces)
- deleteWorkspace(workspace);
+ QTC_ASSERT(d->m_settings, return);
+ d->m_settings->setValue(Constants::AUTO_RESTORE_WORKSPACE_SETTINGS_KEY,
+ workspaceDialog.autoLoadWorkspace());
+}
+
+expected_str<QString> DockManager::createWorkspace(const QString &workspaceName)
+{
+ qCInfo(adsLog) << "Create workspace" << workspaceName;
+
+ QString fileName = workspaceNameToFileName(workspaceName);
+ uniqueWorkspaceFileName(fileName);
+ const FilePath filePath = userDirectory().pathAppended(fileName);
+
+ expected_str<void> result = write(filePath, saveState(workspaceName));
+ if (!result)
+ return make_unexpected(result.error());
+
+ Workspace workspace(filePath, false);
+
+ d->m_workspaces.append(workspace);
+ emit workspaceListChanged();
+ return workspace.fileName();
+}
+
+expected_str<void> DockManager::openWorkspace(const QString &fileName)
+{
+ qCInfo(adsLog) << "Open workspace" << fileName;
+
+ Workspace *wrk = workspace(fileName);
+ if (!wrk)
+ return make_unexpected(Tr::tr("Workspace \"%1\" does not exist.").arg(fileName));
+
+ // Do nothing if workspace is already loaded, exception if it is a preset workspace. In this
+ // case we still want to be able to load the default workspace to undo potential user changes.
+ if (*wrk == *activeWorkspace() && !wrk->isPreset())
+ return {}; // true
+
+ if (activeWorkspace()->isValid()) {
+ // Allow everyone to set something in the workspace and before saving
+ emit aboutToUnloadWorkspace(activeWorkspace()->fileName());
+ expected_str<void> saveResult = save();
+ if (!saveResult)
+ return saveResult;
}
- bool DockManager::cloneWorkspace(const QString &original, const QString &clone)
- {
- if (!d->m_workspaces.contains(original))
- return false;
+ // Try loading the file
+ const expected_str<QByteArray> data = loadWorkspace(*wrk);
+ if (!data)
+ return make_unexpected(data.error());
+
+ emit openingWorkspace(wrk->fileName());
+ // If data was loaded from file try to restore its state
+ if (!data->isNull() && !restoreState(*data))
+ return make_unexpected(Tr::tr("Cannot restore \"%1\".").arg(wrk->filePath().toUserOutput()));
+
+ d->m_workspace = *wrk;
+ emit workspaceLoaded(wrk->fileName());
+
+ return {};
+}
+
+expected_str<void> DockManager::reloadActiveWorkspace()
+{
+ qCInfo(adsLog) << "Reload active workspace";
- const FilePath originalPath = workspaceNameToFilePath(original);
- const FilePath clonePath = workspaceNameToFilePath(clone);
+ Workspace *wrk = activeWorkspace();
- // If the file does not exist, we can still clone
- if (!originalPath.exists() || originalPath.copyFile(clonePath)) {
- d->m_workspaces.insert(1, clone);
- d->m_workspaceDateTimes.insert(clone, clonePath.lastModified());
+ if (!workspaces().contains(*wrk))
+ return make_unexpected(
+ Tr::tr("Cannot reload \"%1\", it is not contained in the list of workspaces")
+ .arg(wrk->filePath().toUserOutput()));
+
+ const expected_str<QByteArray> data = loadWorkspace(*wrk);
+ if (!data)
+ return make_unexpected(data.error());
+
+ if (!data->isNull() && !restoreState(*data))
+ return make_unexpected(Tr::tr("Cannot restore \"%1\".").arg(wrk->filePath().toUserOutput()));
+
+ emit workspaceReloaded(wrk->fileName());
+
+ return {};
+}
+
+bool DockManager::deleteWorkspace(const QString &fileName)
+{
+ qCInfo(adsLog) << "Delete workspace" << fileName;
+
+ Workspace *w = workspace(fileName);
+ if (!w) {
+ qWarning() << "Workspace" << fileName << "does not exist";
+ return false;
+ }
+
+ // Remove corresponding workspace file
+ if (w->exists()) {
+ const FilePath filePath = w->filePath();
+ if (filePath.removeFile()) {
+ d->m_workspaces.removeOne(*w);
+ emit workspaceRemoved();
emit workspaceListChanged();
return true;
}
- return false;
}
- bool DockManager::renameWorkspace(const QString &original, const QString &newName)
- {
- if (!cloneWorkspace(original, newName))
- return false;
+ return false;
+}
- if (original == activeWorkspace())
- openWorkspace(newName);
+void DockManager::deleteWorkspaces(const QStringList &fileNames)
+{
+ for (const QString &fileName : fileNames)
+ deleteWorkspace(fileName);
+}
- return deleteWorkspace(original);
- }
+expected_str<QString> DockManager::cloneWorkspace(const QString &originalFileName,
+ const QString &cloneName)
+{
+ qCInfo(adsLog) << "Clone workspace" << originalFileName << cloneName;
- bool DockManager::resetWorkspacePreset(const QString &workspace)
- {
- if (!isWorkspacePreset(workspace))
- return false;
+ Workspace *w = workspace(originalFileName);
+ if (!w)
+ return make_unexpected(Tr::tr("Workspace \"%1\" does not exist.").arg(originalFileName));
- const FilePath fileName = workspaceNameToFilePath(workspace);
+ const FilePath originalPath = w->filePath();
- if (!fileName.removeFile())
- return false;
+ if (!originalPath.exists())
+ return make_unexpected(
+ Tr::tr("Workspace \"%1\" does not exist.").arg(originalPath.toUserOutput()));
+
+ const FilePath clonePath = workspaceNameToFilePath(cloneName);
+
+ const expected_str<void> copyResult = originalPath.copyFile(clonePath);
+ if (!copyResult)
+ return make_unexpected(Tr::tr("Could not clone '%1' due to: %2")
+ .arg(originalPath.toUserOutput(), copyResult.error()));
+
+ writeDisplayName(clonePath, cloneName);
+ d->m_workspaces.append(Workspace(clonePath));
+ emit workspaceListChanged();
+ return clonePath.fileName();
+}
+
+expected_str<QString> DockManager::renameWorkspace(const QString &originalFileName,
+ const QString &newName)
+{
+ qCInfo(adsLog) << "Rename workspace" << originalFileName << newName;
+
+ Workspace *w = workspace(originalFileName);
+ if (!w)
+ return make_unexpected(Tr::tr("Workspace \"%1\" does not exist.").arg(originalFileName));
+
+ w->setName(newName);
+
+ emit workspaceListChanged();
+ return originalFileName;
+}
+
+expected_str<void> DockManager::resetWorkspacePreset(const QString &fileName)
+{
+ qCInfo(adsLog) << "Reset workspace" << fileName;
+
+ Workspace *w = workspace(fileName);
+ if (!w)
+ return make_unexpected(Tr::tr("Workspace \"%1\" does not exist.").arg(fileName));
+
+ if (!w->isPreset())
+ return make_unexpected(Tr::tr("Workspace \"%1\" is not a preset.").arg(fileName));
+
+ const FilePath filePath = w->filePath();
+
+ if (!filePath.removeFile())
+ return make_unexpected(Tr::tr("Cannot remove \"%1\".").arg(filePath.toUserOutput()));
+
+ return presetDirectory().pathAppended(fileName).copyFile(filePath);
+}
+
+expected_str<void> DockManager::save()
+{
+ if (isModeChangeState())
+ return make_unexpected(Tr::tr("Cannot save workspace while in mode change state."));
+
+ emit aboutToSaveWorkspace();
+
+ Workspace *w = activeWorkspace();
+
+ return write(w->filePath(), saveState(w->name()));
+}
+
+void DockManager::setModeChangeState(bool value)
+{
+ d->m_modeChangeState = value;
+}
+
+bool DockManager::isModeChangeState() const
+{
+ return d->m_modeChangeState;
+}
+
+expected_str<QString> DockManager::importWorkspace(const QString &filePath)
+{
+ qCInfo(adsLog) << "Import workspace" << filePath;
+
+ const FilePath sourceFilePath = FilePath::fromUserInput(filePath);
+
+ if (!sourceFilePath.exists())
+ return make_unexpected(
+ Tr::tr("File \"%1\" does not exist.").arg(sourceFilePath.toUserOutput()));
+
+ // Extract workspace file name. Check if the workspace is already contained in the list of
+ // workspaces. If that is the case add a counter to the workspace file name.
+ QString fileName = sourceFilePath.fileName();
+ uniqueWorkspaceFileName(fileName);
- QDir presetsDir(d->m_workspacePresetsPath);
- bool result = QFile::copy(presetsDir.filePath(workspaceNameToFileName(workspace)),
- fileName.toFSPathString());
- if (result)
- d->m_workspaceDateTimes.insert(workspace, QDateTime::currentDateTime());
+ const FilePath targetFilePath = userDirectory().pathAppended(fileName);
- return result;
+ const expected_str<void> copyResult = sourceFilePath.copyFile(targetFilePath);
+ if (!copyResult)
+ return make_unexpected(
+ Tr::tr("Could not copy \"%1\" to \"%2\" due to: %3")
+ .arg(filePath, targetFilePath.toUserOutput(), copyResult.error()));
+
+ d->m_workspaces.append(Workspace(targetFilePath));
+ emit workspaceListChanged();
+
+ return targetFilePath.fileName();
+}
+
+expected_str<QString> DockManager::exportWorkspace(const QString &targetFilePath,
+ const QString &sourceFileName)
+{
+ qCInfo(adsLog) << "Export workspace" << targetFilePath << sourceFileName;
+
+ // If we came this far the user decided that in case the target already exists to overwrite it.
+ // We first need to remove the existing file, otherwise QFile::copy() will fail.
+ const FilePath targetFile = FilePath::fromUserInput(targetFilePath);
+
+ // Remove the file which supposed to be overwritten
+ if (targetFile.exists()) {
+ if (!targetFile.removeFile()) {
+ return make_unexpected(
+ Tr::tr("Could not remove \"%1\".").arg(targetFile.toUserOutput()));
+ }
}
- void DockManager::setModeChangeState(bool value)
- {
- d->m_modeChangeState = value;
+ // Check if the target directory exists
+ if (!targetFile.parentDir().exists())
+ return make_unexpected(
+ Tr::tr("Directory does not exist\"%1\".").arg(targetFile.parentDir().toUserOutput()));
+
+ // Check if the workspace exists
+ const FilePath workspaceFile = userDirectory().pathAppended(sourceFileName);
+ if (!workspaceFile.exists())
+ return make_unexpected(
+ Tr::tr("Workspace does not exist '%1'").arg(workspaceFile.toUserOutput()));
+
+ // Finally copy the workspace to the target
+ const expected_str<void> copyResult = workspaceFile.copyFile(targetFile);
+ if (!copyResult)
+ return make_unexpected(
+ Tr::tr("Could not copy \"%1\" to \"%2\" due to: %3")
+ .arg(sourceFileName, workspaceFile.toUserOutput(), copyResult.error()));
+
+ return workspaceFile.fileName();
+}
+
+QStringList DockManager::loadOrder(const FilePath &dir) const
+{
+ qCInfo(adsLog) << "Load workspace order" << dir.toUserOutput();
+
+ if (dir.isEmpty())
+ return {};
+
+ auto filePath = dir.pathAppended(workspaceOrderFileName.toString());
+ QByteArray data = loadFile(filePath);
+
+ if (data.isEmpty()) {
+ qWarning() << "Order data is empty" << filePath.toUserOutput();
+ return {};
}
- bool DockManager::isModeChangeState() const
- {
- return d->m_modeChangeState;
+ QJsonParseError parseError;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &parseError);
+ if (parseError.error != QJsonParseError::NoError) {
+ qWarning() << "Failed to parse JSON file" << filePath << ":" << parseError.errorString();
+ return {};
}
- void DockManager::importWorkspace(const QString &workspace)
- {
- // Extract workspace name
- QString workspaceName = fileNameToWorkspaceName(workspace);
-
- // Check if the workspace is already contained in the list of workspaces. If that is the case
- // add a counter to the workspace name.
- if (workspaces().contains(workspaceName)) {
- int i = 2;
- QString copy;
- do {
- copy = workspaceName + QLatin1String(" (") + QString::number(i) + QLatin1Char(')');
- ++i;
- } while (workspaces().contains(copy));
- workspaceName = copy;
- }
+ return jsonDoc.toVariant().toStringList();
+}
- QString fileName = workspaceNameToFileName(workspaceName);
- QFile file(workspace);
- if (!file.exists()) {
- qCInfo(adsLog) << QString("File doesn't exist '%1'").arg(workspace);
- return;
- }
+bool DockManager::writeOrder() const
+{
+ qCInfo(adsLog) << "Write workspace order";
- QDir workspaceDir(QFileInfo(d->m_settings->fileName()).path() + QLatin1Char('/') + m_dirName);
+ QJsonArray order;
+ for (const Workspace &workspace : d->m_workspaces)
+ order.append(QJsonValue(workspace.fileName()));
- if (!file.copy(workspaceDir.filePath(fileName))) {
- qCInfo(adsLog) << QString("Could not copy '%1' to '%2' error: %3").arg(
- workspace, workspaceDir.filePath(fileName), file.errorString());
- } else {
- d->m_workspaces.insert(1, workspaceName);
- d->m_workspaceDateTimes.insert(workspaceName,
- workspaceNameToFilePath(workspaceName).lastModified());
- d->m_workspaceListDirty = true;
- // After importing the workspace, update the workspace list
- workspaces();
- emit workspaceListChanged();
- }
+ const FilePath orderFilePath = userDirectory().pathAppended(workspaceOrderFileName.toString());
+
+ if (!orderFilePath.writeFileContents(QJsonDocument{order}.toJson())) {
+ qWarning() << "Faild to write order" << orderFilePath.toUserOutput();
+ return false;
}
- void DockManager::exportWorkspace(const QString &target, const QString &workspace)
- {
- // If we came this far the user decided that in case the target already exists to overwrite it.
- // We first need to remove the existing file, otherwise QFile::copy() will fail.
- const FilePath targetFile = FilePath::fromUserInput(target);
-
- // Remove the file which supposed to be overwritten
- if (targetFile.exists()) {
- if (!targetFile.removeFile()) {
- qCInfo(adsLog) << QString("Couldn't remove '%1'").arg(targetFile.toUserOutput());
- return;
- }
- }
+ return true;
+}
- // Check if the target directory exists
- if (!targetFile.parentDir().exists()) {
- qCInfo(adsLog) << QString("Directory doesn't exist '%1'")
- .arg(targetFile.parentDir().toUserOutput());
- return;
- }
+QList<Workspace> DockManager::loadWorkspaces(const FilePath &dir) const
+{
+ if (dir.isEmpty())
+ return {};
- // Check if the workspace exists
- FilePath workspaceFile = workspaceNameToFilePath(workspace);
- if (!workspaceFile.exists()) {
- qCInfo(adsLog) << QString("Workspace doesn't exist '%1'")
- .arg(workspaceFile.toUserOutput());
- return;
- }
+ QList<Workspace> workspaces;
- // Finally copy the workspace to the target
- const expected_str<void> copyResult = workspaceFile.copyFile(targetFile);
- if (!copyResult) {
- qCInfo(adsLog) << QString("Could not copy '%1' to '%2' error: %3")
- .arg(workspace, workspaceFile.toUserOutput(), copyResult.error());
- }
- }
+ dir.iterateDirectory(
+ [&workspaces](const FilePath &filePath, const FilePathInfo &) {
+ Workspace workspace(filePath);
+ //workspace.setName(displayName(filePath)); TODO
+ workspaces.append(workspace);
+ return IterationPolicy::Continue;
+ },
+ FileFilter(QStringList{"*." + workspaceFileExtension}, QDir::Files));
- bool DockManager::write(const QString &workspace, const QByteArray &data, QString *errorString) const
- {
- const FilePath fileName = workspaceNameToFilePath(workspace);
+ return workspaces;
+}
- QDir tmp;
- tmp.mkpath(fileName.toFileInfo().path());
- FileSaver fileSaver(fileName, QIODevice::Text);
- if (!fileSaver.hasError())
- fileSaver.write(data);
+FilePath DockManager::presetDirectory() const
+{
+ return FilePath::fromString(d->m_workspacePresetsPath);
+}
- bool ok = fileSaver.finalize();
+FilePath DockManager::userDirectory() const
+{
+ QTC_ASSERT(d->m_settings, return {});
+ return FilePath::fromString(QFileInfo(d->m_settings->fileName()).path())
+ .pathAppended(workspaceFolderName.toString());
+}
- if (!ok && errorString)
- *errorString = fileSaver.errorString();
+QByteArray DockManager::loadFile(const FilePath &filePath)
+{
+ qCInfo(adsLog) << "Load" << filePath;
- return ok;
+ if (!filePath.exists()) {
+ qWarning() << "File does not exist" << filePath.toUserOutput();
+ return {};
}
- bool DockManager::write(const QString &workspace, const QByteArray &data, QWidget *parent) const
- {
- QString errorString;
- const bool success = write(workspace, data, &errorString);
- if (!success)
- QMessageBox::critical(parent, ::Utils::Tr::tr("File Error"), errorString);
- return success;
+ const expected_str<QByteArray> data = filePath.fileContents();
+
+ if (!data) {
+ qWarning() << "Could not open" << filePath.toUserOutput() << data.error();
+ return {};
}
- QByteArray DockManager::loadWorkspace(const QString &workspace) const
- {
- const FilePath fileName = workspaceNameToFilePath(workspace);
- if (fileName.exists()) {
- const expected_str<QByteArray> data = fileName.fileContents();
+ return data.value();
+}
- if (!data) {
- QMessageBox::warning(parentWidget(),
- Tr::tr("Cannot Restore Workspace"),
- Tr::tr("Could not restore workspace %1")
- .arg(fileName.toUserOutput()));
+QString DockManager::readDisplayName(const FilePath &filePath)
+{
+ if (!filePath.exists())
+ return {};
- qCWarning(adsLog) << QString("Could not restore workspace %1: %2")
- .arg(fileName.toUserOutput())
- .arg(data.error());
+ auto data = loadFile(filePath);
- return {};
- }
- return data.value();
- }
+ if (data.isEmpty())
return {};
- }
- void DockManager::syncWorkspacePresets()
- {
- // Get a list of all workspace presets
- QSet<QString> presets = workspacePresets();
-
- // Get a list of all available workspaces
- QSet<QString> availableWorkspaces = Utils::toSet(workspaces());
- presets.subtract(availableWorkspaces);
-
- // Copy all missing workspace presets over to the local workspace folder
- QDir presetsDir(d->m_workspacePresetsPath);
- QDir workspaceDir(QFileInfo(d->m_settings->fileName()).path() + QLatin1Char('/') + m_dirName);
- // Try do create the 'workspaces' directory if it doesn't exist already
- workspaceDir.mkpath(workspaceDir.absolutePath());
- if (!workspaceDir.exists()) {
- qCInfo(adsLog) << QString("Could not make directory '%1')").arg(workspaceDir.absolutePath());
- return;
- }
+ auto tmp = data.startsWith("<?xml") ? data : qUncompress(data);
- for (const auto &preset : presets) {
- QString fileName = workspaceNameToFileName(preset);
- QString filePath = presetsDir.filePath(fileName);
- QFile file(filePath);
+ DockingStateReader reader(tmp);
+ if (!reader.readNextStartElement())
+ return {};
- if (file.exists()) {
- if (!file.copy(workspaceDir.filePath(fileName)))
- qCInfo(adsLog) << QString("Could not copy '%1' to '%2' error: %3").arg(
- filePath, workspaceDir.filePath(fileName), file.errorString());
+ if (reader.name() != QLatin1String("QtAdvancedDockingSystem"))
+ return {};
- d->m_workspaceListDirty = true;
- }
- }
+ return reader.attributes().value(workspaceDisplayNameAttribute.toString()).toString();
+}
- // After copying over missing workspace presets, update the workspace list
- workspaces();
+bool DockManager::writeDisplayName(const FilePath &filePath, const QString &displayName)
+{
+ const expected_str<QByteArray> content = filePath.fileContents();
+
+ QTC_ASSERT_EXPECTED(content, return false);
+
+ QDomDocument doc;
+ QString error_msg;
+ int error_line, error_col;
+ if (!doc.setContent(*content, &error_msg, &error_line, &error_col)) {
+ qWarning() << QString("XML error on line %1, col %2: %3")
+ .arg(error_line)
+ .arg(error_col)
+ .arg(error_msg);
+ return false;
}
- void DockManager::saveStartupWorkspace()
- {
- QTC_ASSERT(d->m_settings, return );
- d->m_settings->setValue(Constants::STARTUP_WORKSPACE_SETTINGS_KEY, activeWorkspace());
+ QDomElement docElem = doc.documentElement();
+ docElem.setAttribute(workspaceDisplayNameAttribute.toString(), displayName);
+
+ const expected_str<void> result = write(filePath, doc.toByteArray(workspaceXmlFormattingIndent));
+ if (!result) {
+ qWarning() << "Could not write display name" << displayName << "to" << filePath << ":"
+ << result.error();
+ return false;
}
- void DockManager::notifyWidgetOrAreaRelocation(QWidget *droppedWidget)
- {
- if (d->m_focusController)
- d->m_focusController->notifyWidgetOrAreaRelocation(droppedWidget);
+ return true;
+}
+
+expected_str<void> DockManager::write(const FilePath &filePath, const QByteArray &data)
+{
+ qCInfo(adsLog) << "Write" << filePath;
+
+ if (!filePath.parentDir().ensureWritableDir())
+ return make_unexpected(Tr::tr("Cannot write to \"%1\".").arg(filePath.toUserOutput()));
+
+ FileSaver fileSaver(filePath, QIODevice::Text);
+ if (!fileSaver.hasError())
+ fileSaver.write(data);
+
+ if (!fileSaver.finalize())
+ return make_unexpected(Tr::tr("Cannot write to \"%1\" due to: %2")
+ .arg(filePath.toUserOutput(), fileSaver.errorString()));
+
+ return {};
+}
+
+expected_str<QByteArray> DockManager::loadWorkspace(const Workspace &workspace) const
+{
+ qCInfo(adsLog) << "Load workspace" << workspace.fileName();
+
+ if (!workspace.exists())
+ return make_unexpected(
+ Tr::tr("Workspace \"%1\" does not exist.").arg(workspace.filePath().toUserOutput()));
+
+ return workspace.filePath().fileContents();
+}
+
+void DockManager::syncWorkspacePresets()
+{
+ qCInfo(adsLog) << "Sync workspaces";
+
+ auto fileFilter = FileFilter(QStringList{"*." + workspaceFileExtension, "*.json"}, QDir::Files);
+
+ // All files in the workspace preset directory with the file extension wrk or json
+ auto presetFiles = presetDirectory().dirEntries(fileFilter);
+ auto userFiles = userDirectory().dirEntries(fileFilter);
+
+ // Try do create the 'workspaces' directory if it doesn't exist already
+ if (!userDirectory().ensureWritableDir()) {
+ qWarning() << QString("Could not make directory '%1')").arg(userDirectory().toString());
+ return;
}
- void DockManager::notifyFloatingWidgetDrop(FloatingDockContainer *floatingWidget)
- {
- if (d->m_focusController)
- d->m_focusController->notifyFloatingWidgetDrop(floatingWidget);
+ for (const auto &filePath : presetFiles) {
+ const int index = Utils::indexOf(userFiles, [&filePath](const FilePath &other) {
+ return other.fileName() == filePath.fileName();
+ });
+
+ // File already contained in user directory
+ if (index >= 0) {
+ auto userFile = userFiles[index];
+
+ // If *.wrk file and displayName attribute is empty set the displayName. This
+ // should fix old workspace files which don't have the displayName attribute.
+ if (userFile.suffix() == workspaceFileExtension && readDisplayName(userFile).isEmpty())
+ writeDisplayName(userFile, readDisplayName(filePath));
+
+ continue;
+ }
+
+ const expected_str<void> copyResult = filePath.copyFile(
+ userDirectory().pathAppended(filePath.fileName()));
+ if (!copyResult)
+ qWarning() << QString("Could not copy '%1' to '%2' due to %3")
+ .arg(filePath.toString(),
+ userDirectory().toString(),
+ copyResult.error());
}
+}
- void DockManager::setDockWidgetFocused(DockWidget *dockWidget)
- {
- if (d->m_focusController)
- d->m_focusController->setDockWidgetFocused(dockWidget);
+void DockManager::prepareWorkspaces()
+{
+ qCInfo(adsLog) << "Prepare workspace";
+
+ auto presetWorkspaces = loadWorkspaces(presetDirectory());
+ auto userWorkspaces = loadWorkspaces(userDirectory());
+ auto userOrder = loadOrder(userDirectory());
+
+ std::vector<std::pair<int, Workspace>> tmp;
+
+ for (Workspace &userWorkspace : userWorkspaces) {
+ userWorkspace.setPreset(presetWorkspaces.contains(userWorkspace));
+ qsizetype index = userOrder.indexOf(userWorkspace.fileName());
+ if (index == -1)
+ index = userWorkspaces.count();
+ tmp.push_back(std::make_pair(index, userWorkspace));
}
+ Utils::sort(tmp, [](auto const &a, auto const &b) { return a.first < b.first; });
+
+ d->m_workspaces = Utils::transform<QList<Workspace>>(tmp,
+ [](const std::pair<int, Workspace> &p) {
+ return p.second;
+ });
+
+ emit workspaceListChanged();
+}
+
+void DockManager::saveStartupWorkspace()
+{
+ QTC_ASSERT(d->m_settings, return);
+ d->m_settings->setValue(Constants::STARTUP_WORKSPACE_SETTINGS_KEY,
+ activeWorkspace()->fileName());
+}
+
} // namespace ADS
diff --git a/src/libs/advanceddockingsystem/dockmanager.h b/src/libs/advanceddockingsystem/dockmanager.h
index 9ef2a6f3f10..62148d1e234 100644
--- a/src/libs/advanceddockingsystem/dockmanager.h
+++ b/src/libs/advanceddockingsystem/dockmanager.h
@@ -7,6 +7,7 @@
#include "dockcontainerwidget.h"
#include "dockwidget.h"
#include "floatingdockcontainer.h"
+#include "workspace.h"
#include <utils/persistentsettings.h>
@@ -28,7 +29,7 @@ QT_END_NAMESPACE
namespace ADS {
namespace Constants {
-const char DEFAULT_WORKSPACE[] = "Basic"; // This needs to align with a name of the shipped presets
+const char DEFAULT_WORKSPACE[] = "Basic.wrk"; // Needs to align with a shipped preset
const char STARTUP_WORKSPACE_SETTINGS_KEY[] = "QML/Designer/StartupWorkspace";
const char AUTO_RESTORE_WORKSPACE_SETTINGS_KEY[] = "QML/Designer/AutoRestoreLastWorkspace";
} // namespace Constants
@@ -46,14 +47,18 @@ class DockWidgetTabPrivate;
struct DockAreaWidgetPrivate;
class IconProvider;
+inline constexpr QStringView workspaceFolderName{u"workspaces"};
+inline constexpr QStringView workspaceFileExtension{u"wrk"};
+inline constexpr QStringView workspaceOrderFileName{u"order.json"};
+inline constexpr QStringView workspaceDisplayNameAttribute{u"displayName"};
+inline const int workspaceXmlFormattingIndent = 2;
+
/**
- * The central dock manager that maintains the complete docking system.
- * With the configuration flags you can globally control the functionality
- * of the docking system. The dock manager uses an internal stylesheet to
- * style its components like splitters, tabs and buttons. If you want to
- * disable this stylesheet because your application uses its own,
- * just call the function for settings the stylesheet with an empty
- * string.
+ * The central dock manager that maintains the complete docking system. With the configuration flags
+ * you can globally control the functionality of the docking system. The dock manager uses an
+ * internal stylesheet to style its components like splitters, tabs and buttons. If you want to
+ * disable this stylesheet because your application uses its own, just call the function for
+ * settings the stylesheet with an empty string.
* \code
* dockManager->setStyleSheet("");
* \endcode
@@ -76,71 +81,6 @@ private:
friend class FloatingDragPreviewPrivate;
friend class DockAreaTitleBar;
-protected:
- /**
- * Registers the given floating widget in the internal list of
- * floating widgets
- */
- void registerFloatingWidget(FloatingDockContainer *floatingWidget);
-
- /**
- * Remove the given floating widget from the list of registered floating
- * widgets
- */
- void removeFloatingWidget(FloatingDockContainer *floatingWidget);
-
- /**
- * Registers the given dock container widget
- */
- void registerDockContainer(DockContainerWidget *dockContainer);
-
- /**
- * Remove dock container from the internal list of registered dock
- * containers
- */
- void removeDockContainer(DockContainerWidget *dockContainer);
-
- /**
- * Overlay for containers
- */
- DockOverlay *containerOverlay() const;
-
- /**
- * Overlay for dock areas
- */
- DockOverlay *dockAreaOverlay() const;
-
- /**
- * A container needs to call this function if a widget has been dropped
- * into it
- */
- void notifyWidgetOrAreaRelocation(QWidget *droppedWidget);
-
- /**
- * This function is called, if a floating widget has been dropped into
- * an new position.
- * When this function is called, all dock widgets of the FloatingWidget
- * are already inserted into its new position
- */
- void notifyFloatingWidgetDrop(FloatingDockContainer *floatingWidget);
-
- /**
- * This function is called, if the given DockWidget has been relocated from
- * the old container ContainerOld to the new container DockWidget->dockContainer()
- */
- void notifyDockWidgetRelocation(DockWidget *dockWidget, DockContainerWidget *containerOld);
-
- /**
- * This function is called, if the given DockAreahas been relocated from
- * the old container ContainerOld to the new container DockArea->dockContainer()
- */
- void notifyDockAreaRelocation(DockAreaWidget *dockArea, DockContainerWidget *containerOld);
-
- /**
- * Show the floating widgets that has been created floating
- */
- void showEvent(QShowEvent *event) override;
-
public:
using Super = DockContainerWidget;
@@ -151,12 +91,10 @@ public:
enum eConfigFlag {
ActiveTabHasCloseButton
= 0x0001, //!< If this flag is set, the active tab in a tab area has a close button
- DockAreaHasCloseButton
- = 0x0002, //!< If the flag is set each dock area has a close button
+ DockAreaHasCloseButton = 0x0002, //!< If the flag is set each dock area has a close button
DockAreaCloseButtonClosesTab
= 0x0004, //!< If the flag is set, the dock area close button closes the active tab, if not set, it closes the complete dock area
- OpaqueSplitterResize
- = 0x0008, //!< See QSplitter::setOpaqueResize() documentation
+ OpaqueSplitterResize = 0x0008, //!< See QSplitter::setOpaqueResize() documentation
XmlAutoFormattingEnabled
= 0x0010, //!< If enabled, the XML writer automatically adds line-breaks and indentation to empty sections between elements (ignorable whitespace).
XmlCompressionEnabled
@@ -177,8 +115,7 @@ public:
= 0x1000, ///< If opaque undocking is disabled, then this flag configures if the drag preview is frameless or looks like a real window
AlwaysShowTabs
= 0x2000, ///< If this option is enabled, the tab of a dock widget is always displayed - even if it is the only visible dock widget in a floating widget.
- DockAreaHasUndockButton
- = 0x4000, //!< If the flag is set each dock area has an undock button
+ DockAreaHasUndockButton = 0x4000, //!< If the flag is set each dock area has an undock button
DockAreaHasTabsMenuButton
= 0x8000, //!< If the flag is set each dock area has a tabs menu button
DockAreaHideDisabledButtons
@@ -191,39 +128,39 @@ public:
= 0x80000, //!< If set, the Floating Widget icon reflects the icon of the current dock widget otherwise it displays application icon
HideSingleCentralWidgetTitleBar
= 0x100000, //!< If there is only one single visible dock widget in the main dock container (the dock manager) and if this flag is set, then the titlebar of this dock widget will be hidden
- //!< this only makes sense for non draggable and non floatable widgets and enables the creation of some kind of "central" widget
+ //!< this only makes sense for non draggable and non floatable widgets and enables the creation of some kind of "central" widget
FocusHighlighting
= 0x200000, //!< enables styling of focused dock widget tabs or floating widget titlebar
EqualSplitOnInsertion
= 0x400000, ///!< if enabled, the space is equally distributed to all widgets in a splitter
- DefaultDockAreaButtons = DockAreaHasCloseButton
- | DockAreaHasUndockButton
- | DockAreaHasTabsMenuButton,///< default configuration of dock area title bar buttons
+ DefaultDockAreaButtons
+ = DockAreaHasCloseButton | DockAreaHasUndockButton
+ | DockAreaHasTabsMenuButton, ///< default configuration of dock area title bar buttons
- DefaultBaseConfig = DefaultDockAreaButtons
- | ActiveTabHasCloseButton
- | XmlCompressionEnabled
- | FloatingContainerHasWidgetTitle,///< default base configuration settings
+ DefaultBaseConfig = DefaultDockAreaButtons | ActiveTabHasCloseButton
+ | XmlAutoFormattingEnabled
+ | FloatingContainerHasWidgetTitle, ///< default base configuration settings
- DefaultOpaqueConfig = DefaultBaseConfig
- | OpaqueSplitterResize
- | OpaqueUndocking, ///< the default configuration with opaque operations - this may cause issues if ActiveX or Qt 3D windows are involved
+ DefaultOpaqueConfig
+ = DefaultBaseConfig | OpaqueSplitterResize
+ | OpaqueUndocking, ///< the default configuration with opaque operations - this may cause issues if ActiveX or Qt 3D windows are involved
- DefaultNonOpaqueConfig = DefaultBaseConfig
- | DragPreviewShowsContentPixmap, ///< the default configuration for non opaque operations
+ DefaultNonOpaqueConfig
+ = DefaultBaseConfig
+ | DragPreviewShowsContentPixmap, ///< the default configuration for non opaque operations
- NonOpaqueWithWindowFrame = DefaultNonOpaqueConfig
- | DragPreviewHasWindowFrame ///< the default configuration for non opaque operations that show a real window with frame
+ NonOpaqueWithWindowFrame
+ = DefaultNonOpaqueConfig
+ | DragPreviewHasWindowFrame ///< the default configuration for non opaque operations that show a real window with frame
};
Q_DECLARE_FLAGS(ConfigFlags, eConfigFlag)
/**
* Default Constructor.
- * If the given parent is a QMainWindow, the dock manager sets itself as the
- * central widget.
- * Before you create any dock widgets, you should properly setup the
- * configuration flags via setConfigFlags().
+ * If the given parent is a QMainWindow, the dock manager sets itself as the central widget.
+ * Before you create any dock widgets, you should properly setup the configuration flags
+ * via setConfigFlags().
*/
DockManager(QWidget *parent = nullptr);
@@ -238,9 +175,8 @@ public:
static ConfigFlags configFlags();
/**
- * Sets the global configuration flags for the whole docking system.
- * Call this function before you create the dock manager and before
- * your create the first dock widget.
+ * Sets the global configuration flags for the whole docking system. Call this function before
+ * you create the dock manager and before your create the first dock widget.
*/
static void setConfigFlags(const ConfigFlags flags);
@@ -257,20 +193,19 @@ public:
/**
* Returns the global icon provider.
- * The icon provider enables the use of custom icons in case using
- * styleheets for icons is not an option.
+ * The icon provider enables the use of custom icons in case using styleheets for icons is not
+ * an option.
*/
static IconProvider &iconProvider();
/**
- * The distance the user needs to move the mouse with the left button
- * hold down before a dock widget start floating.
+ * The distance the user needs to move the mouse with the left button hold down before a dock
+ * widget start floating.
*/
static int startDragDistance();
/**
- * Helper function to set focus depending on the configuration of the
- * FocusStyling flag
+ * Helper function to set focus depending on the configuration of the FocusStyling flag
*/
template <class QWidgetPtr>
static void setWidgetFocus(QWidgetPtr widget)
@@ -295,11 +230,10 @@ public:
/**
* Adds dockwidget into the given area.
- * If DockAreaWidget is not null, then the area parameter indicates the area
- * into the DockAreaWidget. If DockAreaWidget is null, the Dockwidget will
- * be dropped into the container. If you would like to add a dock widget
- * tabified, then you need to add it to an existing dock area object
- * into the CenterDockWidgetArea. The following code shows this:
+ * If DockAreaWidget is not null, then the area parameter indicates the area into the
+ * DockAreaWidget. If DockAreaWidget is null, the Dockwidget will be dropped into the container.
+ * If you would like to add a dock widget tabified, then you need to add it to an existing
+ * dock area object into the CenterDockWidgetArea. The following code shows this:
* \code
* DockManager->addDockWidget(ads::CenterDockWidgetArea, NewDockWidget,
* ExisitingDockArea);
@@ -311,22 +245,18 @@ public:
DockAreaWidget *dockAreaWidget = nullptr);
/**
- * This function will add the given Dockwidget to the given dock area as
- * a new tab.
- * If no dock area widget exists for the given area identifier, a new
- * dock area widget is created.
+ * This function will add the given Dockwidget to the given dock area as a new tab. If no dock
+ * area widget exists for the given area identifier, a new dock area widget is created.
*/
DockAreaWidget *addDockWidgetTab(DockWidgetArea area, DockWidget *dockWidget);
/**
- * This function will add the given Dockwidget to the given DockAreaWidget
- * as a new tab.
+ * This function will add the given Dockwidget to the given DockAreaWidget as a new tab.
*/
DockAreaWidget *addDockWidgetTabToArea(DockWidget *dockWidget, DockAreaWidget *dockAreaWidget);
/**
- * Adds the given DockWidget floating and returns the created
- * CFloatingDockContainer instance.
+ * Adds the given DockWidget floating and returns the created FloatingDockContainer instance.
*/
FloatingDockContainer *addDockWidgetFloating(DockWidget *dockWidget);
@@ -343,8 +273,8 @@ public:
void removeDockWidget(DockWidget *dockWidget);
/**
- * This function returns a readable reference to the internal dock
- * widgets map so that it is possible to iterate over all dock widgets.
+ * This function returns a readable reference to the internal dock widgets map so that it is
+ * possible to iterate over all dock widgets.
*/
QMap<QString, DockWidget *> dockWidgetsMap() const;
@@ -366,39 +296,34 @@ public:
unsigned int zOrderIndex() const override;
/**
- * Saves the current state of the dockmanger and all its dock widgets
- * into the returned QByteArray.
- * The XmlMode enables / disables the auto formatting for the XmlStreamWriter.
+ * Saves the current state of the dockmanger and all its dock widgets into the returned
+ * QByteArray. The XmlMode enables / disables the auto formatting for the XmlStreamWriter.
* If auto formatting is enabled, the output is intended and line wrapped.
- * The XmlMode XmlAutoFormattingDisabled is better if you would like to have
- * a more compact XML output - i.e. for storage in ini files.
+ * The XmlMode XmlAutoFormattingDisabled is better if you would like to have a more compact
+ * XML output - i.e. for storage in ini files.
* The version number is stored as part of the data.
- * To restore the saved state, pass the return value and version number
- * to restoreState().
+ * To restore the saved state, pass the return value and version number to restoreState().
* \see restoreState()
*/
- QByteArray saveState(int version = 0) const;
+ QByteArray saveState(const QString &displayName, int version = 0) const;
/**
* Restores the state of this dockmanagers dockwidgets.
- * The version number is compared with that stored in state. If they do
- * not match, the dockmanager's state is left unchanged, and this function
- * returns false; otherwise, the state is restored, and this function
- * returns true.
+ * The version number is compared with that stored in state. If they do not match, the
+ * dockmanager's state is left unchanged, and this function returns false; otherwise, the state
+ * is restored, and this function returns true.
* \see saveState()
*/
bool restoreState(const QByteArray &state, int version = 0);
/**
- * This function returns true between the restoringState() and
- * stateRestored() signals.
+ * This function returns true between the restoringState() and stateRestored() signals.
*/
bool isRestoringState() const;
/**
* Request a focus change to the given dock widget.
- * This function only has an effect, if the flag CDockManager::FocusStyling
- * is enabled
+ * This function only has an effect, if the flag CDockManager::FocusStyling is enabled.
*/
void setDockWidgetFocused(DockWidget *dockWidget);
@@ -411,125 +336,234 @@ signals:
/**
* This signal is emitted if workspaces have been removed.
*/
- void workspacesRemoved();
+ void workspaceRemoved();
/**
- * This signal is emitted, if the restore function is called, just before
- * the dock manager starts restoring the state.
- * If this function is called, nothing has changed yet.
+ * This signal is emitted, if the restore function is called, just before the dock manager
+ * starts restoring the state. If this function is called, nothing has changed yet.
*/
void restoringState();
/**
* This signal is emitted if the state changed in restoreState.
- * The signal is emitted if the restoreState() function is called or
- * if the openWorkspace() function is called.
+ * The signal is emitted if the restoreState() function is called or if the openWorkspace()
+ * function is called.
*/
void stateRestored();
/**
- * This signal is emitted, if the dock manager starts opening a
- * workspace.
- * Opening a workspace may take more than a second if there are
- * many complex widgets. The application may use this signal
- * to show some progress indicator or to change the mouse cursor
- * into a busy cursor.
+ * This signal is emitted, if the dock manager starts opening a workspace.
+ * Opening a workspace may take more than a second if there are many complex widgets. The
+ * application may use this signal to show some progress indicator or to change the mouse
+ * cursor into a busy cursor.
*/
- void openingWorkspace(const QString &workspaceName);
+ void openingWorkspace(const QString &fileName);
/**
- * This signal is emitted if the dock manager finished opening a
- * workspace.
+ * This signal is emitted if the dock manager finished opening a workspace.
*/
- void workspaceOpened(const QString &workspaceName);
+ void workspaceOpened(const QString &fileName);
/**
- * This signal is emitted, if a new floating widget has been created.
- * An application can use this signal to e.g. subscribe to events of
- * the newly created window.
+ * This signal is emitted, if a new floating widget has been created. An application can use
+ * this signal to e.g. subscribe to events of the newly created window.
*/
- void floatingWidgetCreated(FloatingDockContainer *floatingWidget);
+ void floatingWidgetCreated(ADS::FloatingDockContainer *floatingWidget);
/**
- * This signal is emitted, if a new DockArea has been created.
- * An application can use this signal to set custom icons or custom
- * tooltips for the DockArea buttons.
+ * This signal is emitted, if a new DockArea has been created. An application can use this
+ * signal to set custom icons or custom tooltips for the DockArea buttons.
*/
- void dockAreaCreated(DockAreaWidget *dockArea);
+ void dockAreaCreated(ADS::DockAreaWidget *dockArea);
/**
* This signal is emitted just before removal of the given DockWidget.
*/
- void dockWidgetAboutToBeRemoved(DockWidget *dockWidget);
+ void dockWidgetAboutToBeRemoved(ADS::DockWidget *dockWidget);
/**
- * This signal is emitted if a dock widget has been removed with the remove
- * removeDockWidget() function.
- * If this signal is emitted, the dock widget has been removed from the
- * docking system but it is not deleted yet.
+ * This signal is emitted if a dock widget has been removed with the remove removeDockWidget()
+ * function. If this signal is emitted, the dock widget has been removed from the docking
+ * system but it is not deleted yet.
*/
- void dockWidgetRemoved(DockWidget *dockWidget);
+ void dockWidgetRemoved(ADS::DockWidget *dockWidget);
/**
- * This signal is emitted if the focused dock widget changed.
- * Both old and now can be nullptr.
+ * This signal is emitted if the focused dock widget changed. Both old and now can be nullptr.
* The focused dock widget is the one that is highlighted in the GUI
*/
- void focusedDockWidgetChanged(DockWidget *old, DockWidget *now);
+ void focusedDockWidgetChanged(ADS::DockWidget *old, ADS::DockWidget *now);
+
+protected:
+ /**
+ * Registers the given floating widget in the internal list of floating widgets
+ */
+ void registerFloatingWidget(FloatingDockContainer *floatingWidget);
+
+ /**
+ * Remove the given floating widget from the list of registered floating widgets
+ */
+ void removeFloatingWidget(FloatingDockContainer *floatingWidget);
+
+ /**
+ * Registers the given dock container widget
+ */
+ void registerDockContainer(DockContainerWidget *dockContainer);
+
+ /**
+ * Remove dock container from the internal list of registered dock containers
+ */
+ void removeDockContainer(DockContainerWidget *dockContainer);
+
+ /**
+ * Overlay for containers
+ */
+ DockOverlay *containerOverlay() const;
+
+ /**
+ * Overlay for dock areas
+ */
+ DockOverlay *dockAreaOverlay() const;
+
+ /**
+ * A container needs to call this function if a widget has been dropped into it
+ */
+ void notifyWidgetOrAreaRelocation(QWidget *droppedWidget);
+
+ /**
+ * This function is called, if a floating widget has been dropped into an new position. When
+ * this function is called, all dock widgets of the FloatingWidget are already inserted into
+ * its new position
+ */
+ void notifyFloatingWidgetDrop(FloatingDockContainer *floatingWidget);
+
+ /**
+ * This function is called, if the given DockWidget has been relocated from the old container
+ * ContainerOld to the new container DockWidget->dockContainer()
+ */
+ void notifyDockWidgetRelocation(DockWidget *dockWidget, DockContainerWidget *containerOld);
+
+ /**
+ * This function is called, if the given DockArea has been relocated from the old container
+ * ContainerOld to the new container DockArea->dockContainer()
+ */
+ void notifyDockAreaRelocation(DockAreaWidget *dockArea, DockContainerWidget *containerOld);
+
+ /**
+ * Show the floating widgets that has been created floating
+ */
+ void showEvent(QShowEvent *event) override;
public:
- void showWorkspaceMananger();
+ // Workspace state
+ Workspace *activeWorkspace() const;
+ QString startupWorkspace() const;
+ bool autoRestoreWorkspace() const;
+ const QList<Workspace> &workspaces() const;
+
+ // Workspace convenience functions
+ int workspaceIndex(const QString &fileName) const;
+ bool workspaceExists(const QString &fileName) const;
+ Workspace *workspace(const QString &fileName) const;
+ Workspace *workspace(int index) const;
+ QDateTime workspaceDateTime(const QString &fileName) const;
+
+ bool moveWorkspace(int from, int to);
+ bool moveWorkspaceUp(const QString &fileName);
+ bool moveWorkspaceDown(const QString &fileName);
- // higher level workspace management
- QString activeWorkspace() const;
- QString lastWorkspace() const;
- bool autoRestorLastWorkspace() const;
- QStringView workspaceFileExtension() const;
- QStringList workspaces();
- QSet<QString> workspacePresets() const;
- QDateTime workspaceDateTime(const QString &workspace) const;
Utils::FilePath workspaceNameToFilePath(const QString &workspaceName) const;
- QString fileNameToWorkspaceName(const QString &fileName) const;
+
QString workspaceNameToFileName(const QString &workspaceName) const;
- bool createWorkspace(const QString &workspace);
+ void uniqueWorkspaceFileName(QString &fileName) const;
- bool openWorkspace(const QString &workspace);
- bool reloadActiveWorkspace();
+ // Workspace management functionality
+ void showWorkspaceMananger();
- bool confirmWorkspaceDelete(const QStringList &workspaces);
- bool deleteWorkspace(const QString &workspace);
- void deleteWorkspaces(const QStringList &workspaces);
+ /**
+ * \brief Create a workspace.
+ *
+ * The display name does not need to be unique, but the file name must be. So this function will
+ * generate a file name from the display name so it will not collide with an existing workspace.
+ *
+ * \param workspace display name of the workspace that will be created
+ * \return file name of the created workspace or unexpected
+ */
+ Utils::expected_str<QString> createWorkspace(const QString &workspace);
- bool cloneWorkspace(const QString &original, const QString &clone);
- bool renameWorkspace(const QString &original, const QString &newName);
+ Utils::expected_str<void> openWorkspace(const QString &fileName);
+ Utils::expected_str<void> reloadActiveWorkspace();
- bool resetWorkspacePreset(const QString &workspace);
+ /**
+ * \brief Deletes a workspace from workspace list and the file from disk.
+ */
+ bool deleteWorkspace(const QString &fileName);
+ void deleteWorkspaces(const QStringList &fileNames);
+
+ /**
+ * \brief Clone a workspace.
+ *
+ * \param originalFileName file name of the workspace that will be cloned
+ * \param cloneName display name of cloned workspace
+ * \return file name of the cloned workspace or unexpected
+ */
+ Utils::expected_str<QString> cloneWorkspace(const QString &originalFileName,
+ const QString &cloneName);
+
+ /**
+ * \brief Rename a workspace.
+ *
+ * \param originalFileName file name of the workspace that will be renamed
+ * \param newName new display name
+ * \return file name of the renamed workspace or unexpected if rename failed
+ */
+ Utils::expected_str<QString> renameWorkspace(const QString &originalFileName,
+ const QString &newName);
- bool save();
+ Utils::expected_str<void> resetWorkspacePreset(const QString &fileName);
- bool isWorkspacePreset(const QString &workspace) const;
+ /**
+ * \brief Save the currently active workspace.
+ */
+ Utils::expected_str<void> save();
void setModeChangeState(bool value);
bool isModeChangeState() const;
- void importWorkspace(const QString &workspace);
- void exportWorkspace(const QString &target, const QString &workspace);
+ Utils::expected_str<QString> importWorkspace(const QString &filePath);
+ Utils::expected_str<QString> exportWorkspace(const QString &targetFilePath,
+ const QString &sourceFileName);
+
+ // Workspace convenience functions
+ QStringList loadOrder(const Utils::FilePath &dir) const;
+ bool writeOrder() const;
+ QList<Workspace> loadWorkspaces(const Utils::FilePath &dir) const;
+
+ Utils::FilePath presetDirectory() const;
+ Utils::FilePath userDirectory() const;
+
+ static QByteArray loadFile(const Utils::FilePath &filePath);
+ static QString readDisplayName(const Utils::FilePath &filePath);
+ static bool writeDisplayName(const Utils::FilePath &filePath, const QString &displayName);
signals:
- void aboutToUnloadWorkspace(QString workspaceName);
- void aboutToLoadWorkspace(QString workspaceName);
- void workspaceLoaded(QString workspaceName);
- void workspaceReloaded(QString workspaceName);
+ void aboutToUnloadWorkspace(QString fileName);
+ void aboutToLoadWorkspace(QString fileName);
+ void workspaceLoaded(QString fileName);
+ void workspaceReloaded(QString fileName);
void aboutToSaveWorkspace();
private:
- bool write(const QString &workspace, const QByteArray &data, QString *errorString) const;
- bool write(const QString &workspace, const QByteArray &data, QWidget *parent) const;
+ static Utils::expected_str<void> write(const Utils::FilePath &filePath, const QByteArray &data);
- QByteArray loadWorkspace(const QString &workspace) const;
+ Utils::expected_str<QByteArray> loadWorkspace(const Workspace &workspace) const;
+ /**
+ * \brief Copy all missing workspace presets over to the local workspace folder.
+ */
void syncWorkspacePresets();
+ void prepareWorkspaces();
void saveStartupWorkspace();
}; // class DockManager
diff --git a/src/libs/advanceddockingsystem/dockwidget.cpp b/src/libs/advanceddockingsystem/dockwidget.cpp
index 64269ebfdb3..ea680149661 100644
--- a/src/libs/advanceddockingsystem/dockwidget.cpp
+++ b/src/libs/advanceddockingsystem/dockwidget.cpp
@@ -534,7 +534,17 @@ namespace ADS
QSize DockWidget::minimumSizeHint() const
{
- if (d->m_minimumSizeHintMode == DockWidget::MinimumSizeHintFromDockWidget || !d->m_widget)
+ if (!d->m_widget)
+ return QSize(60, 40);
+
+ DockContainerWidget *container = this->dockContainer();
+ if (!container || container->isFloating()) {
+ const QSize sh = d->m_widget->minimumSizeHint();
+ const QSize s = d->m_widget->minimumSize();
+ return {std::max(s.width(), sh.width()), std::max(s.height(), sh.height())};
+ }
+
+ if (d->m_minimumSizeHintMode == DockWidget::MinimumSizeHintFromDockWidget)
return QSize(60, 40);
else
return d->m_widget->minimumSizeHint();
diff --git a/src/libs/advanceddockingsystem/workspace.cpp b/src/libs/advanceddockingsystem/workspace.cpp
new file mode 100644
index 00000000000..d3b0785d90b
--- /dev/null
+++ b/src/libs/advanceddockingsystem/workspace.cpp
@@ -0,0 +1,95 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
+
+#include "workspace.h"
+
+#include "dockmanager.h"
+
+namespace ADS {
+
+Workspace::Workspace() {}
+
+Workspace::Workspace(const Utils::FilePath &filePath, bool isPreset)
+ : m_filePath(filePath)
+ , m_preset(isPreset)
+{
+ if (m_filePath.isEmpty())
+ return;
+
+ QString name = DockManager::readDisplayName(m_filePath);
+
+ if (name.isEmpty()) {
+ name = baseName();
+ // Remove "-" and "_" remove
+ name.replace("-", " ");
+ name.replace("_", " ");
+
+ setName(name);
+ } else {
+ m_name = name;
+ }
+}
+
+void Workspace::setName(const QString &name)
+{
+ if (DockManager::writeDisplayName(filePath(), name))
+ m_name = name;
+}
+
+const QString &Workspace::name() const
+{
+ return m_name;
+}
+
+const Utils::FilePath &Workspace::filePath() const
+{
+ return m_filePath;
+}
+
+QString Workspace::fileName() const
+{
+ return m_filePath.fileName();
+}
+
+QString Workspace::baseName() const
+{
+ return m_filePath.baseName();
+}
+
+QDateTime Workspace::lastModified() const
+{
+ return m_filePath.lastModified();
+}
+
+bool Workspace::exists() const
+{
+ return m_filePath.exists();
+}
+
+bool Workspace::isValid() const
+{
+ if (m_filePath.isEmpty())
+ return false;
+
+ return exists();
+}
+
+void Workspace::setPreset(bool value)
+{
+ m_preset = value;
+}
+
+bool Workspace::isPreset() const
+{
+ return m_preset;
+}
+
+Workspace::operator QString() const
+{
+ return QString("Workspace %1 Preset[%2] %3")
+ .arg(name())
+ .arg(isPreset())
+ .arg(filePath().toUserOutput());
+}
+
+} // namespace ADS
diff --git a/src/libs/advanceddockingsystem/workspace.h b/src/libs/advanceddockingsystem/workspace.h
new file mode 100644
index 00000000000..c23db55d6b6
--- /dev/null
+++ b/src/libs/advanceddockingsystem/workspace.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
+
+#pragma once
+
+#include "ads_globals.h"
+
+#include <utils/fileutils.h>
+
+namespace ADS {
+
+class ADS_EXPORT Workspace
+{
+public:
+ Workspace();
+ Workspace(const Utils::FilePath &filePath, bool isPreset = false);
+
+ void setName(const QString &name);
+ const QString &name() const;
+
+ const Utils::FilePath &filePath() const;
+
+ QString fileName() const;
+ QString baseName() const;
+ QDateTime lastModified() const;
+ bool exists() const;
+
+ bool isValid() const;
+
+ void setPreset(bool value);
+ bool isPreset() const;
+
+ friend bool operator==(const Workspace &a, const Workspace &b)
+ {
+ return a.fileName() == b.fileName();
+ }
+
+ friend bool operator==(const QString &fileName, const Workspace &workspace)
+ {
+ return fileName == workspace.fileName();
+ }
+ friend bool operator==(const Workspace &workspace, const QString &fileName)
+ {
+ return workspace.fileName() == fileName;
+ }
+
+ explicit operator QString() const;
+
+private:
+ QString m_name;
+ Utils::FilePath m_filePath;
+ bool m_preset = false;
+};
+
+} // namespace ADS
diff --git a/src/libs/advanceddockingsystem/workspacedialog.cpp b/src/libs/advanceddockingsystem/workspacedialog.cpp
index e99ec6946ac..06e74f310a1 100644
--- a/src/libs/advanceddockingsystem/workspacedialog.cpp
+++ b/src/libs/advanceddockingsystem/workspacedialog.cpp
@@ -13,103 +13,11 @@
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QLabel>
-#include <QLineEdit>
#include <QPushButton>
-#include <QRegularExpression>
-#include <QValidator>
+#include <QLineEdit>
namespace ADS {
-class WorkspaceValidator : public QValidator
-{
-public:
- WorkspaceValidator(QObject *parent, const QStringList &workspaces);
- void fixup(QString &input) const override;
- QValidator::State validate(QString &input, int &pos) const override;
-
-private:
- QStringList m_workspaces;
-};
-
-WorkspaceValidator::WorkspaceValidator(QObject *parent, const QStringList &workspaces)
- : QValidator(parent)
- , m_workspaces(workspaces)
-{}
-
-QValidator::State WorkspaceValidator::validate(QString &input, int &pos) const
-{
- Q_UNUSED(pos)
-
- static const QRegularExpression rx("^[a-zA-Z0-9 ()\\-]*$");
-
- if (!rx.match(input).hasMatch())
- return QValidator::Invalid;
-
- if (m_workspaces.contains(input))
- return QValidator::Intermediate;
- else
- return QValidator::Acceptable;
-}
-
-void WorkspaceValidator::fixup(QString &input) const
-{
- int i = 2;
- QString copy;
- do {
- copy = input + QLatin1String(" (") + QString::number(i) + QLatin1Char(')');
- ++i;
- } while (m_workspaces.contains(copy));
- input = copy;
-}
-
-WorkspaceNameInputDialog::WorkspaceNameInputDialog(DockManager *manager, QWidget *parent)
- : QDialog(parent)
- , m_manager(manager)
-{
- auto label = new QLabel(Tr::tr("Enter the name of the workspace:"), this);
- m_newWorkspaceLineEdit = new QLineEdit(this);
- m_newWorkspaceLineEdit->setValidator(new WorkspaceValidator(this, m_manager->workspaces()));
- auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
- Qt::Horizontal,
- this);
- m_okButton = buttons->button(QDialogButtonBox::Ok);
- m_switchToButton = new QPushButton;
- buttons->addButton(m_switchToButton, QDialogButtonBox::AcceptRole);
- connect(m_switchToButton, &QPushButton::clicked, this, [this] { m_usedSwitchTo = true; });
- connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
- connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
-
- using namespace Layouting;
-
- Column {
- label,
- m_newWorkspaceLineEdit,
- buttons
- }.attachTo(this);
-}
-
-void WorkspaceNameInputDialog::setActionText(const QString &actionText,
- const QString &openActionText)
-{
- m_okButton->setText(actionText);
- m_switchToButton->setText(openActionText);
-}
-
-void WorkspaceNameInputDialog::setValue(const QString &value)
-{
- m_newWorkspaceLineEdit->setText(value);
-}
-
-QString WorkspaceNameInputDialog::value() const
-{
- return m_newWorkspaceLineEdit->text();
-}
-
-bool WorkspaceNameInputDialog::isSwitchToRequested() const
-{
- return m_usedSwitchTo;
-}
-
WorkspaceDialog::WorkspaceDialog(DockManager *manager, QWidget *parent)
: QDialog(parent)
, m_manager(manager)
@@ -122,9 +30,12 @@ WorkspaceDialog::WorkspaceDialog(DockManager *manager, QWidget *parent)
, m_btSwitch(new QPushButton(Tr::tr("&Switch To")))
, m_btImport(new QPushButton(Tr::tr("Import")))
, m_btExport(new QPushButton(Tr::tr("Export")))
+ , m_btUp(new QPushButton(Tr::tr("Move Up")))
+ , m_btDown(new QPushButton(Tr::tr("Move Down")))
, m_autoLoadCheckBox(new QCheckBox(Tr::tr("Restore last workspace on startup")))
{
setWindowTitle(Tr::tr("Workspace Manager"));
+ resize(550, 380);
m_workspaceView->setActivationMode(Utils::DoubleClickActivation);
@@ -139,34 +50,27 @@ WorkspaceDialog::WorkspaceDialog(DockManager *manager, QWidget *parent)
using namespace Layouting;
- Column {
- Row {
- Column {
- m_workspaceView,
- m_autoLoadCheckBox
- },
- Column {
- m_btCreateNew,
- m_btRename,
- m_btClone,
- m_btDelete,
- m_btReset,
- m_btSwitch,
- st,
- m_btImport,
- m_btExport
- }
- },
- hr,
- Row {
- whatsAWorkspaceLabel,
- buttonBox
- }
- }.attachTo(this);
-
-
- connect(m_btCreateNew, &QAbstractButton::clicked,
- m_workspaceView, &WorkspaceView::createNewWorkspace);
+ Column{Row{Column{m_workspaceView, m_autoLoadCheckBox},
+ Column{m_btCreateNew,
+ m_btRename,
+ m_btClone,
+ m_btDelete,
+ m_btReset,
+ m_btSwitch,
+ st,
+ m_btUp,
+ m_btDown,
+ st,
+ m_btImport,
+ m_btExport}},
+ hr,
+ Row{whatsAWorkspaceLabel, buttonBox}}
+ .attachTo(this);
+
+ connect(m_btCreateNew,
+ &QAbstractButton::clicked,
+ m_workspaceView,
+ &WorkspaceView::createNewWorkspace);
connect(m_btClone, &QAbstractButton::clicked,
m_workspaceView, &WorkspaceView::cloneCurrentWorkspace);
connect(m_btDelete, &QAbstractButton::clicked,
@@ -183,10 +87,15 @@ WorkspaceDialog::WorkspaceDialog(DockManager *manager, QWidget *parent)
this, &WorkspaceDialog::updateActions);
connect(m_btImport, &QAbstractButton::clicked,
m_workspaceView, &WorkspaceView::importWorkspace);
- connect(m_btExport, &QAbstractButton::clicked,
- m_workspaceView, &WorkspaceView::exportCurrentWorkspace);
+ connect(m_btExport,
+ &QAbstractButton::clicked,
+ m_workspaceView,
+ &WorkspaceView::exportCurrentWorkspace);
+
+ connect(m_btUp, &QAbstractButton::clicked, m_workspaceView, &WorkspaceView::moveWorkspaceUp);
+ connect(m_btDown, &QAbstractButton::clicked, m_workspaceView, &WorkspaceView::moveWorkspaceDown);
- updateActions(m_workspaceView->selectedWorkspaces());
+ updateActions(m_workspaceView->selectedWorkspaces());
}
void WorkspaceDialog::setAutoLoadWorkspace(bool check)
@@ -204,29 +113,50 @@ DockManager *WorkspaceDialog::dockManager() const
return m_manager;
}
-void WorkspaceDialog::updateActions(const QStringList &workspaces)
+void WorkspaceDialog::updateActions(const QStringList &fileNames)
{
- if (workspaces.isEmpty()) {
+ if (fileNames.isEmpty()) {
m_btDelete->setEnabled(false);
m_btRename->setEnabled(false);
m_btClone->setEnabled(false);
m_btReset->setEnabled(false);
m_btSwitch->setEnabled(false);
+ m_btUp->setEnabled(false);
+ m_btDown->setEnabled(false);
m_btExport->setEnabled(false);
return;
}
- const bool presetIsSelected = Utils::anyOf(workspaces, [this](const QString &workspace) {
- return m_manager->isWorkspacePreset(workspace);
+ const bool presetIsSelected = Utils::anyOf(fileNames, [this](const QString &fileName) {
+ Workspace *workspace = m_manager->workspace(fileName);
+ if (!workspace)
+ return false;
+
+ return workspace->isPreset();
+ });
+ const bool activeIsSelected = Utils::anyOf(fileNames, [this](const QString &fileName) {
+ Workspace *workspace = m_manager->workspace(fileName);
+ if (!workspace)
+ return false;
+
+ return *workspace == *m_manager->activeWorkspace();
});
- const bool activeIsSelected = Utils::anyOf(workspaces, [this](const QString &workspace) {
- return workspace == m_manager->activeWorkspace();
+ const bool canMoveUp = Utils::anyOf(fileNames, [this](const QString &fileName) {
+ return m_manager->workspaceIndex(fileName) > 0;
});
+ const int count = m_manager->workspaces().count();
+ const bool canMoveDown = Utils::anyOf(fileNames, [this, &count](const QString &fileName) {
+ const int i = m_manager->workspaceIndex(fileName);
+ return i < (count - 1);
+ });
+
m_btDelete->setEnabled(!activeIsSelected && !presetIsSelected);
- m_btRename->setEnabled(workspaces.size() == 1 && !presetIsSelected);
- m_btClone->setEnabled(workspaces.size() == 1);
+ m_btRename->setEnabled(fileNames.size() == 1 && !presetIsSelected);
+ m_btClone->setEnabled(fileNames.size() == 1);
m_btReset->setEnabled(presetIsSelected);
- m_btSwitch->setEnabled(workspaces.size() == 1);
- m_btExport->setEnabled(workspaces.size() == 1);
+ m_btSwitch->setEnabled(fileNames.size() == 1 && !activeIsSelected);
+ m_btUp->setEnabled(fileNames.size() == 1 && canMoveUp);
+ m_btDown->setEnabled(fileNames.size() == 1 && canMoveDown);
+ m_btExport->setEnabled(fileNames.size() == 1);
}
} // namespace ADS
diff --git a/src/libs/advanceddockingsystem/workspacedialog.h b/src/libs/advanceddockingsystem/workspacedialog.h
index 10ad1af624c..7918c8e8250 100644
--- a/src/libs/advanceddockingsystem/workspacedialog.h
+++ b/src/libs/advanceddockingsystem/workspacedialog.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
#pragma once
@@ -7,7 +7,6 @@
QT_BEGIN_NAMESPACE
class QCheckBox;
-class QLineEdit;
class QPushButton;
QT_END_NAMESPACE
@@ -29,7 +28,7 @@ public:
DockManager *dockManager() const;
private:
- void updateActions(const QStringList &workspaces);
+ void updateActions(const QStringList &fileNames);
DockManager *m_manager = nullptr;
@@ -42,28 +41,9 @@ private:
QPushButton *m_btSwitch = nullptr;
QPushButton *m_btImport = nullptr;
QPushButton *m_btExport = nullptr;
+ QPushButton *m_btUp = nullptr;
+ QPushButton *m_btDown = nullptr;
QCheckBox *m_autoLoadCheckBox = nullptr;
};
-class WorkspaceNameInputDialog : public QDialog
-{
- Q_OBJECT
-
-public:
- explicit WorkspaceNameInputDialog(DockManager *manager, QWidget *parent);
-
- void setActionText(const QString &actionText, const QString &openActionText);
- void setValue(const QString &value);
- QString value() const;
- bool isSwitchToRequested() const;
-
-private:
- QLineEdit *m_newWorkspaceLineEdit = nullptr;
- QPushButton *m_switchToButton = nullptr;
- QPushButton *m_okButton = nullptr;
- bool m_usedSwitchTo = false;
-
- DockManager *m_manager;
-};
-
} // namespace ADS
diff --git a/src/libs/advanceddockingsystem/workspaceinputdialog.cpp b/src/libs/advanceddockingsystem/workspaceinputdialog.cpp
new file mode 100644
index 00000000000..15f36398c2a
--- /dev/null
+++ b/src/libs/advanceddockingsystem/workspaceinputdialog.cpp
@@ -0,0 +1,103 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
+
+#include "workspaceinputdialog.h"
+
+#include "advanceddockingsystemtr.h"
+#include "dockmanager.h"
+
+#include <utils/algorithm.h>
+#include <utils/layoutbuilder.h>
+
+#include <QDialogButtonBox>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPushButton>
+#include <QRegularExpression>
+#include <QValidator>
+
+namespace ADS {
+
+class WorkspaceValidator : public QValidator
+{
+public:
+ WorkspaceValidator(QObject *parent = nullptr);
+ QValidator::State validate(QString &input, int &pos) const override;
+};
+
+WorkspaceValidator::WorkspaceValidator(QObject *parent)
+ : QValidator(parent)
+{}
+
+QValidator::State WorkspaceValidator::validate(QString &input, int &pos) const
+{
+ Q_UNUSED(pos)
+
+ static const QRegularExpression rx("^[a-zA-Z0-9 ()]*$");
+
+ if (!rx.match(input).hasMatch())
+ return QValidator::Invalid;
+
+ if (input.isEmpty())
+ return QValidator::Intermediate;
+
+ return QValidator::Acceptable;
+}
+
+WorkspaceNameInputDialog::WorkspaceNameInputDialog(DockManager *manager, QWidget *parent)
+ : QDialog(parent)
+ , m_manager(manager)
+{
+ auto label = new QLabel(Tr::tr("Enter the name of the workspace:"), this);
+ m_newWorkspaceLineEdit = new QLineEdit(this);
+ m_newWorkspaceLineEdit->setValidator(new WorkspaceValidator(this));
+ auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel,
+ Qt::Horizontal,
+ this);
+ m_okButton = buttons->button(QDialogButtonBox::Ok);
+ m_switchToButton = new QPushButton;
+ buttons->addButton(m_switchToButton, QDialogButtonBox::AcceptRole);
+ connect(m_switchToButton, &QPushButton::clicked, this, [this] { m_usedSwitchTo = true; });
+ connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
+ connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
+
+ m_okButton->setEnabled(false);
+ m_switchToButton->setEnabled(false);
+
+ connect(m_newWorkspaceLineEdit, &QLineEdit::textChanged, this, [this](const QString &) {
+ m_okButton->setEnabled(m_newWorkspaceLineEdit->hasAcceptableInput());
+ m_switchToButton->setEnabled(m_newWorkspaceLineEdit->hasAcceptableInput());
+ });
+
+ using namespace Layouting;
+
+ Column {
+ label,
+ m_newWorkspaceLineEdit,
+ buttons
+ }.attachTo(this);
+}
+
+void WorkspaceNameInputDialog::setActionText(const QString &actionText,
+ const QString &openActionText)
+{
+ m_okButton->setText(actionText);
+ m_switchToButton->setText(openActionText);
+}
+
+void WorkspaceNameInputDialog::setValue(const QString &value)
+{
+ m_newWorkspaceLineEdit->setText(value);
+}
+
+QString WorkspaceNameInputDialog::value() const
+{
+ return m_newWorkspaceLineEdit->text();
+}
+
+bool WorkspaceNameInputDialog::isSwitchToRequested() const
+{
+ return m_usedSwitchTo;
+}
+
+} // namespace ADS
diff --git a/src/libs/advanceddockingsystem/workspaceinputdialog.h b/src/libs/advanceddockingsystem/workspaceinputdialog.h
new file mode 100644
index 00000000000..0568e466b4a
--- /dev/null
+++ b/src/libs/advanceddockingsystem/workspaceinputdialog.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-2.1-or-later OR GPL-3.0-or-later
+
+#pragma once
+
+#include <QDialog>
+
+QT_BEGIN_NAMESPACE
+class QLineEdit;
+class QPushButton;
+QT_END_NAMESPACE
+
+namespace ADS {
+
+class DockManager;
+
+class WorkspaceNameInputDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit WorkspaceNameInputDialog(DockManager *manager, QWidget *parent);
+
+ void setActionText(const QString &actionText, const QString &openActionText);
+ void setValue(const QString &value);
+ QString value() const;
+ bool isSwitchToRequested() const;
+
+private:
+ QLineEdit *m_newWorkspaceLineEdit = nullptr;
+ QPushButton *m_switchToButton = nullptr;
+ QPushButton *m_okButton = nullptr;
+ bool m_usedSwitchTo = false;
+
+ DockManager *m_manager;
+};
+
+} // namespace ADS
diff --git a/src/libs/advanceddockingsystem/workspacemodel.cpp b/src/libs/advanceddockingsystem/workspacemodel.cpp
index 2f73e747607..99d3bd1473e 100644
--- a/src/libs/advanceddockingsystem/workspacemodel.cpp
+++ b/src/libs/advanceddockingsystem/workspacemodel.cpp
@@ -18,21 +18,21 @@ namespace ADS {
WorkspaceModel::WorkspaceModel(DockManager *manager, QObject *parent)
: QAbstractTableModel(parent)
, m_manager(manager)
- , m_currentSortColumn(0)
{
- m_sortedWorkspaces = m_manager->workspaces();
- sort(m_currentSortColumn, m_currentSortOrder);
connect(m_manager, &DockManager::workspaceLoaded, this, &WorkspaceModel::resetWorkspaces);
}
-int WorkspaceModel::indexOfWorkspace(const QString &workspace)
+int WorkspaceModel::indexOfWorkspace(const QString &fileName)
{
- return m_sortedWorkspaces.indexOf(workspace);
+ return m_manager->workspaceIndex(fileName);
}
QString WorkspaceModel::workspaceAt(int row) const
{
- return m_sortedWorkspaces.value(row, QString());
+ if (row >= rowCount() || row < 0)
+ return {};
+
+ return m_manager->workspaces()[row].fileName();
}
QVariant WorkspaceModel::headerData(int section, Qt::Orientation orientation, int role) const
@@ -46,6 +46,9 @@ QVariant WorkspaceModel::headerData(int section, Qt::Orientation orientation, in
result = Tr::tr("Workspace");
break;
case 1:
+ result = Tr::tr("File Name");
+ break;
+ case 2:
result = Tr::tr("Last Modified");
break;
} // switch (section)
@@ -59,7 +62,6 @@ int WorkspaceModel::columnCount(const QModelIndex &) const
{
static int sectionCount = 0;
if (sectionCount == 0) {
- // headers sections defining possible columns
while (!headerData(sectionCount, Qt::Horizontal, Qt::DisplayRole).isNull())
sectionCount++;
}
@@ -69,183 +71,79 @@ int WorkspaceModel::columnCount(const QModelIndex &) const
int WorkspaceModel::rowCount(const QModelIndex &) const
{
- return m_sortedWorkspaces.count();
-}
-
-QStringList pathsToBaseNames(const QStringList &paths)
-{
- return Utils::transform(paths,
- [](const QString &path) { return QFileInfo(path).completeBaseName(); });
+ return m_manager->workspaces().count();
}
QVariant WorkspaceModel::data(const QModelIndex &index, int role) const
{
- QVariant result;
- if (index.isValid()) {
- QString workspaceName = m_sortedWorkspaces.at(index.row());
-
- switch (role) {
- case Qt::DisplayRole:
- switch (index.column()) {
- case 0:
- result = workspaceName;
- break;
- case 1:
- result = m_manager->workspaceDateTime(workspaceName);
- break;
- } // switch (section)
+ if (!index.isValid() || index.row() >= rowCount())
+ return QVariant();
+
+ Workspace *workspace = m_manager->workspace(index.row());
+ if (!workspace)
+ return QVariant();
+
+ switch (role) {
+ case Qt::DisplayRole:
+ switch (index.column()) {
+ case 0:
+ return workspace->name();
+ case 1:
+ return workspace->fileName();
+ case 2:
+ return workspace->lastModified();
+ default:
+ qWarning("data: invalid display value column %d", index.column());
break;
- case Qt::FontRole: {
- QFont font;
- if (m_manager->isWorkspacePreset(workspaceName))
- font.setItalic(true);
- else
- font.setItalic(false);
- if (m_manager->activeWorkspace() == workspaceName)
- font.setBold(true);
- else
- font.setBold(false);
- result = font;
- } break;
- case PresetWorkspaceRole:
- result = m_manager->isWorkspacePreset(workspaceName);
- break;
- case LastWorkspaceRole:
- result = m_manager->lastWorkspace() == workspaceName;
- break;
- case ActiveWorkspaceRole:
- result = m_manager->activeWorkspace() == workspaceName;
- break;
- } // switch (role)
+ }
+ break;
+ case Qt::FontRole: {
+ QFont font;
+ font.setItalic(workspace->isPreset());
+ font.setBold(*m_manager->activeWorkspace() == *workspace);
+ return font;
}
-
- return result;
+ case WorkspacePreset:
+ return workspace->isPreset();
+ case WorkspaceStartup:
+ return m_manager->startupWorkspace() == workspace->fileName();
+ case WorkspaceActive:
+ return *m_manager->activeWorkspace() == *workspace;
+ }
+ return QVariant();
}
QHash<int, QByteArray> WorkspaceModel::roleNames() const
{
static QHash<int, QByteArray> extraRoles{{Qt::DisplayRole, "workspaceName"},
- {PresetWorkspaceRole, "presetWorkspace"},
- {LastWorkspaceRole, "activeWorkspace"},
- {ActiveWorkspaceRole, "lastWorkspace"}};
+ {WorkspacePreset, "presetWorkspace"},
+ {WorkspaceStartup, "lastWorkspace"},
+ {WorkspaceActive, "activeWorkspace"}};
auto defaultRoles = QAbstractTableModel::roleNames();
defaultRoles.insert(extraRoles);
return defaultRoles;
}
-void WorkspaceModel::sort(int column, Qt::SortOrder order)
-{
- m_currentSortColumn = column;
- m_currentSortOrder = order;
-
- beginResetModel();
- const auto cmp = [this, column, order](const QString &s1, const QString &s2) {
- bool isLess;
- if (column == 0)
- isLess = s1 < s2;
- else
- isLess = m_manager->workspaceDateTime(s1) < m_manager->workspaceDateTime(s2);
- if (order == Qt::DescendingOrder)
- isLess = !isLess;
- return isLess;
- };
- Utils::sort(m_sortedWorkspaces, cmp);
- endResetModel();
-}
-
-void WorkspaceModel::resetWorkspaces()
-{
- m_sortedWorkspaces = m_manager->workspaces();
- sort(m_currentSortColumn, m_currentSortOrder);
-}
-
-void WorkspaceModel::newWorkspace(QWidget *parent)
-{
- WorkspaceNameInputDialog workspaceInputDialog(m_manager, parent);
- workspaceInputDialog.setWindowTitle(Tr::tr("New Workspace Name"));
- workspaceInputDialog.setActionText(Tr::tr("&Create"), Tr::tr("Create and &Open"));
-
- runWorkspaceNameInputDialog(&workspaceInputDialog, [this](const QString &newName) {
- m_manager->createWorkspace(newName);
- });
-}
-
-void WorkspaceModel::cloneWorkspace(QWidget *parent, const QString &workspace)
-{
- WorkspaceNameInputDialog workspaceInputDialog(m_manager, parent);
- workspaceInputDialog.setWindowTitle(Tr::tr("New Workspace Name"));
- workspaceInputDialog.setActionText(Tr::tr("&Clone"), Tr::tr("Clone and &Open"));
- workspaceInputDialog.setValue(workspace + " (2)");
-
- runWorkspaceNameInputDialog(&workspaceInputDialog, [this, workspace](const QString &newName) {
- m_manager->cloneWorkspace(workspace, newName);
- });
-}
-
-void WorkspaceModel::deleteWorkspaces(const QStringList &workspaces)
-{
- if (!m_manager->confirmWorkspaceDelete(workspaces))
- return;
-
- m_manager->deleteWorkspaces(workspaces);
- m_sortedWorkspaces = m_manager->workspaces();
- sort(m_currentSortColumn, m_currentSortOrder);
-}
-
-void WorkspaceModel::renameWorkspace(QWidget *parent, const QString &workspace)
+Qt::DropActions WorkspaceModel::supportedDropActions() const
{
- WorkspaceNameInputDialog workspaceInputDialog(m_manager, parent);
- workspaceInputDialog.setWindowTitle(Tr::tr("Rename Workspace"));
- workspaceInputDialog.setActionText(Tr::tr("&Rename"), Tr::tr("Rename and &Open"));
- workspaceInputDialog.setValue(workspace);
-
- runWorkspaceNameInputDialog(&workspaceInputDialog, [this, workspace](const QString &newName) {
- m_manager->renameWorkspace(workspace, newName);
- });
+ return Qt::MoveAction;
}
-void WorkspaceModel::resetWorkspace(const QString &workspace)
+Qt::ItemFlags WorkspaceModel::flags(const QModelIndex &index) const
{
- if (m_manager->resetWorkspacePreset(workspace) && workspace == m_manager->activeWorkspace())
- m_manager->reloadActiveWorkspace();
-}
+ Qt::ItemFlags defaultFlags = QAbstractTableModel::flags(index);
-void WorkspaceModel::switchToWorkspace(const QString &workspace)
-{
- m_manager->openWorkspace(workspace);
- emit workspaceSwitched();
-}
+ if (index.isValid())
+ return Qt::ItemIsDragEnabled | defaultFlags;
-void WorkspaceModel::importWorkspace(const QString &workspace)
-{
- m_manager->importWorkspace(workspace);
- m_sortedWorkspaces = m_manager->workspaces();
- sort(m_currentSortColumn, m_currentSortOrder);
-}
-
-void WorkspaceModel::exportWorkspace(const QString &target, const QString &workspace)
-{
- m_manager->exportWorkspace(target, workspace);
+ return Qt::ItemIsDropEnabled | defaultFlags;
}
-void WorkspaceModel::runWorkspaceNameInputDialog(WorkspaceNameInputDialog *workspaceInputDialog,
- std::function<void(const QString &)> createWorkspace)
+void WorkspaceModel::resetWorkspaces()
{
- if (workspaceInputDialog->exec() == QDialog::Accepted) {
- QString newWorkspace = workspaceInputDialog->value();
- if (newWorkspace.isEmpty() || m_manager->workspaces().contains(newWorkspace))
- return;
-
- createWorkspace(newWorkspace);
- m_sortedWorkspaces = m_manager->workspaces();
- sort(m_currentSortColumn, m_currentSortOrder);
-
- if (workspaceInputDialog->isSwitchToRequested())
- switchToWorkspace(newWorkspace);
-
- emit workspaceCreated(newWorkspace);
- }
+ beginResetModel();
+ endResetModel();
}
} // namespace ADS
diff --git a/src/libs/advanceddockingsystem/workspacemodel.h b/src/libs/advanceddockingsystem/workspacemodel.h
index 38386ad348b..fe868f71f5b 100644
--- a/src/libs/advanceddockingsystem/workspacemodel.h
+++ b/src/libs/advanceddockingsystem/workspacemodel.h
@@ -17,45 +17,27 @@ class WorkspaceModel final : public QAbstractTableModel
Q_OBJECT
public:
- enum { PresetWorkspaceRole = Qt::UserRole + 1, LastWorkspaceRole, ActiveWorkspaceRole };
+ enum { WorkspaceFileName = Qt::UserRole, WorkspacePreset, WorkspaceStartup, WorkspaceActive };
explicit WorkspaceModel(DockManager *manager, QObject *parent = nullptr);
- int indexOfWorkspace(const QString &workspace);
+ int indexOfWorkspace(const QString &fileName);
QString workspaceAt(int row) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
- QVariant data(const QModelIndex &index, int role) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
- void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override;
-signals:
- void workspaceSwitched();
- void workspaceCreated(const QString &workspaceName);
+ Qt::DropActions supportedDropActions() const override;
+ Qt::ItemFlags flags(const QModelIndex &index) const override;
-public:
void resetWorkspaces();
- void newWorkspace(QWidget *parent);
- void cloneWorkspace(QWidget *parent, const QString &workspace);
- void deleteWorkspaces(const QStringList &workspaces);
- void renameWorkspace(QWidget *parent, const QString &workspace);
- void resetWorkspace(const QString &workspace);
- void switchToWorkspace(const QString &workspace);
-
- void importWorkspace(const QString &workspace);
- void exportWorkspace(const QString &target, const QString &workspace);
private:
- void runWorkspaceNameInputDialog(WorkspaceNameInputDialog *workspaceInputDialog,
- std::function<void(const QString &)> createWorkspace);
-
- QStringList m_sortedWorkspaces;
DockManager *m_manager;
- int m_currentSortColumn;
- Qt::SortOrder m_currentSortOrder = Qt::AscendingOrder;
};
} // namespace ADS
diff --git a/src/libs/advanceddockingsystem/workspaceview.cpp b/src/libs/advanceddockingsystem/workspaceview.cpp
index 430bb097efc..bab54e5e927 100644
--- a/src/libs/advanceddockingsystem/workspaceview.cpp
+++ b/src/libs/advanceddockingsystem/workspaceview.cpp
@@ -3,14 +3,16 @@
#include "workspaceview.h"
-#include "dockmanager.h"
#include "advanceddockingsystemtr.h"
+#include "dockmanager.h"
#include <utils/algorithm.h>
#include <QFileDialog>
#include <QHeaderView>
#include <QItemSelection>
+#include <QMessageBox>
+#include <QMimeData>
#include <QStringList>
#include <QStyledItemDelegate>
@@ -49,13 +51,15 @@ WorkspaceView::WorkspaceView(DockManager *manager, QWidget *parent)
setSelectionMode(QAbstractItemView::SingleSelection);
setWordWrap(false);
setRootIsDecorated(false);
- setSortingEnabled(true);
+ setSortingEnabled(false);
+ setDragEnabled(true);
+ setAcceptDrops(true);
+ setDropIndicatorShown(true);
+ setDragDropMode(QAbstractItemView::InternalMove);
setModel(&m_workspaceModel);
- sortByColumn(0, Qt::AscendingOrder);
- // Ensure that the full workspace name is visible.
- header()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
+ header()->setDefaultSectionSize(150);
QItemSelection firstRow(m_workspaceModel.index(0, 0),
m_workspaceModel.index(0, m_workspaceModel.columnCount() - 1));
@@ -68,79 +72,167 @@ WorkspaceView::WorkspaceView(DockManager *manager, QWidget *parent)
emit workspacesSelected(selectedWorkspaces());
});
- connect(&m_workspaceModel, &WorkspaceModel::workspaceSwitched,
- this, &WorkspaceView::workspaceSwitched);
- connect(&m_workspaceModel, &WorkspaceModel::modelReset,
- this, &WorkspaceView::selectActiveWorkspace);
- connect(&m_workspaceModel, &WorkspaceModel::workspaceCreated,
- this, &WorkspaceView::selectWorkspace);
+ connect(&m_workspaceModel,
+ &WorkspaceModel::modelReset,
+ this,
+ &WorkspaceView::selectActiveWorkspace);
}
void WorkspaceView::createNewWorkspace()
{
- m_workspaceModel.newWorkspace(this);
+ WorkspaceNameInputDialog workspaceInputDialog(m_manager, this);
+ workspaceInputDialog.setWindowTitle(Tr::tr("New Workspace Name"));
+ workspaceInputDialog.setActionText(Tr::tr("&Create"), Tr::tr("Create and &Open"));
+
+ runWorkspaceNameInputDialog(&workspaceInputDialog, [this](const QString &newName) {
+ Utils::expected_str<QString> result = m_manager->createWorkspace(newName);
+
+ if (!result)
+ QMessageBox::warning(this, Tr::tr("Cannot Create Workspace"), result.error());
+
+ return result;
+ });
}
-void WorkspaceView::deleteSelectedWorkspaces()
+void WorkspaceView::cloneCurrentWorkspace()
{
- deleteWorkspaces(selectedWorkspaces());
+ const QString fileName = currentWorkspace();
+
+ QString displayName = "Unknown";
+ Workspace *workspace = m_manager->workspace(fileName);
+ if (workspace)
+ displayName = workspace->name();
+
+ WorkspaceNameInputDialog workspaceInputDialog(m_manager, this);
+ workspaceInputDialog.setWindowTitle(Tr::tr("New Workspace Name"));
+ workspaceInputDialog.setActionText(Tr::tr("&Clone"), Tr::tr("Clone and &Open"));
+ workspaceInputDialog.setValue(Tr::tr("%1 Copy").arg(displayName));
+
+ runWorkspaceNameInputDialog(&workspaceInputDialog, [this, fileName](const QString &newName) {
+ Utils::expected_str<QString> result = m_manager->cloneWorkspace(fileName, newName);
+
+ if (!result)
+ QMessageBox::warning(this, Tr::tr("Cannot Clone Workspace"), result.error());
+
+ return result;
+ });
}
-void WorkspaceView::deleteWorkspaces(const QStringList &workspaces)
+void WorkspaceView::renameCurrentWorkspace()
{
- m_workspaceModel.deleteWorkspaces(workspaces);
+ const QString fileName = currentWorkspace();
+
+ QString displayName = "Unknown";
+ Workspace *workspace = m_manager->workspace(fileName);
+ if (workspace)
+ displayName = workspace->name();
+
+ WorkspaceNameInputDialog workspaceInputDialog(m_manager, this);
+ workspaceInputDialog.setWindowTitle(Tr::tr("Rename Workspace"));
+ workspaceInputDialog.setActionText(Tr::tr("&Rename"), Tr::tr("Rename and &Open"));
+ workspaceInputDialog.setValue(displayName);
+
+ runWorkspaceNameInputDialog(&workspaceInputDialog, [this, fileName](const QString &newName) {
+ Utils::expected_str<QString> result = m_manager->renameWorkspace(fileName, newName);
+
+ if (!result)
+ QMessageBox::warning(this, Tr::tr("Cannot Rename Workspace"), result.error());
+
+ return result;
+ });
}
-void WorkspaceView::importWorkspace()
+void WorkspaceView::resetCurrentWorkspace()
{
- static QString lastDir;
- const QString currentDir = lastDir.isEmpty() ? "" : lastDir;
- const auto fileName = QFileDialog::getOpenFileName(this,
- Tr::tr("Import Workspace"),
- currentDir,
- "Workspaces (*" + m_manager->workspaceFileExtension() + ")");
-
- if (!fileName.isEmpty())
- lastDir = QFileInfo(fileName).absolutePath();
+ const QString fileName = currentWorkspace();
- m_workspaceModel.importWorkspace(fileName);
+ if (m_manager->resetWorkspacePreset(fileName) && fileName == *m_manager->activeWorkspace()) {
+ if (m_manager->reloadActiveWorkspace())
+ m_workspaceModel.resetWorkspaces();
+ }
}
-void WorkspaceView::exportCurrentWorkspace()
+void WorkspaceView::switchToCurrentWorkspace()
{
- static QString lastDir;
- const QString currentDir = lastDir.isEmpty() ? "" : lastDir;
- QFileInfo fileInfo(currentDir, m_manager->workspaceNameToFileName(currentWorkspace()));
+ Utils::expected_str<void> result = m_manager->openWorkspace(currentWorkspace());
- const auto fileName = QFileDialog::getSaveFileName(this,
- Tr::tr("Export Workspace"),
- fileInfo.absoluteFilePath(),
- "Workspaces (*" + m_manager->workspaceFileExtension() + ")");
+ if (!result)
+ QMessageBox::warning(this, Tr::tr("Cannot Switch Workspace"), result.error());
- if (!fileName.isEmpty())
- lastDir = QFileInfo(fileName).absolutePath();
+ emit workspaceSwitched();
+}
- m_workspaceModel.exportWorkspace(fileName, currentWorkspace());
+void WorkspaceView::deleteSelectedWorkspaces()
+{
+ deleteWorkspaces(selectedWorkspaces());
}
-void WorkspaceView::cloneCurrentWorkspace()
+void WorkspaceView::importWorkspace()
{
- m_workspaceModel.cloneWorkspace(this, currentWorkspace());
+ static QString previousDirectory;
+ const QString currentDirectory = previousDirectory.isEmpty() ? "" : previousDirectory;
+ const auto filePath
+ = QFileDialog::getOpenFileName(this,
+ Tr::tr("Import Workspace"),
+ currentDirectory,
+ QString("Workspaces (*.%1)").arg(workspaceFileExtension));
+
+ // If the user presses Cancel, it returns a null string
+ if (filePath.isEmpty())
+ return;
+
+ previousDirectory = QFileInfo(filePath).absolutePath();
+
+ const Utils::expected_str<QString> newFileName = m_manager->importWorkspace(filePath);
+ if (newFileName)
+ m_workspaceModel.resetWorkspaces();
+ else
+ QMessageBox::warning(this, Tr::tr("Cannot Import Workspace"), newFileName.error());
}
-void WorkspaceView::renameCurrentWorkspace()
+void WorkspaceView::exportCurrentWorkspace()
{
- m_workspaceModel.renameWorkspace(this, currentWorkspace());
+ static QString previousDirectory;
+ const QString currentDirectory = previousDirectory.isEmpty() ? "" : previousDirectory;
+ QFileInfo fileInfo(currentDirectory, currentWorkspace());
+
+ const auto filePath
+ = QFileDialog::getSaveFileName(this,
+ Tr::tr("Export Workspace"),
+ fileInfo.absoluteFilePath(),
+ QString("Workspaces (*.%1)").arg(workspaceFileExtension));
+
+ // If the user presses Cancel, it returns a null string
+ if (filePath.isEmpty())
+ return;
+
+ previousDirectory = QFileInfo(filePath).absolutePath();
+
+ const Utils::expected_str<QString> result = m_manager->exportWorkspace(filePath,
+ currentWorkspace());
+
+ if (!result)
+ QMessageBox::warning(this, Tr::tr("Cannot Export Workspace"), result.error());
}
-void WorkspaceView::resetCurrentWorkspace()
+void WorkspaceView::moveWorkspaceUp()
{
- m_workspaceModel.resetWorkspace(currentWorkspace());
+ const QString w = currentWorkspace();
+ bool hasMoved = m_manager->moveWorkspaceUp(w);
+ if (hasMoved) {
+ m_workspaceModel.resetWorkspaces();
+ selectWorkspace(w);
+ }
}
-void WorkspaceView::switchToCurrentWorkspace()
+void WorkspaceView::moveWorkspaceDown()
{
- m_workspaceModel.switchToWorkspace(currentWorkspace());
+ const QString w = currentWorkspace();
+ bool hasMoved = m_manager->moveWorkspaceDown(w);
+ if (hasMoved) {
+ m_workspaceModel.resetWorkspaces();
+ selectWorkspace(w);
+ }
}
QString WorkspaceView::currentWorkspace()
@@ -155,17 +247,24 @@ WorkspaceModel *WorkspaceView::workspaceModel()
void WorkspaceView::selectActiveWorkspace()
{
- selectWorkspace(m_manager->activeWorkspace());
+ selectWorkspace(m_manager->activeWorkspace()->fileName());
}
-void WorkspaceView::selectWorkspace(const QString &workspaceName)
+void WorkspaceView::selectWorkspace(const QString &fileName)
{
- int row = m_workspaceModel.indexOfWorkspace(workspaceName);
+ int row = m_workspaceModel.indexOfWorkspace(fileName);
selectionModel()->setCurrentIndex(model()->index(row, 0),
QItemSelectionModel::ClearAndSelect
| QItemSelectionModel::Rows);
}
+QStringList WorkspaceView::selectedWorkspaces() const
+{
+ return Utils::transform(selectionModel()->selectedRows(), [this](const QModelIndex &index) {
+ return m_workspaceModel.workspaceAt(index.row());
+ });
+}
+
void WorkspaceView::showEvent(QShowEvent *event)
{
Utils::TreeView::showEvent(event);
@@ -179,19 +278,83 @@ void WorkspaceView::keyPressEvent(QKeyEvent *event)
TreeView::keyPressEvent(event);
return;
}
- const QStringList workspaces = selectedWorkspaces();
- if (!Utils::anyOf(workspaces, [this](const QString &workspace) {
- return workspace == m_manager->activeWorkspace();
+ const QStringList fileNames = selectedWorkspaces();
+ if (!Utils::anyOf(fileNames, [this](const QString &fileName) {
+ return fileName == *m_manager->activeWorkspace();
})) {
- deleteWorkspaces(workspaces);
+ deleteWorkspaces(fileNames);
}
}
-QStringList WorkspaceView::selectedWorkspaces() const
+void WorkspaceView::dropEvent(QDropEvent *event)
{
- return Utils::transform(selectionModel()->selectedRows(), [this](const QModelIndex &index) {
- return m_workspaceModel.workspaceAt(index.row());
- });
+ const QModelIndex dropIndex = indexAt(event->pos());
+ const DropIndicatorPosition dropIndicator = dropIndicatorPosition();
+
+ const auto droppedWorkspaces = selectedWorkspaces();
+ int from = m_manager->workspaceIndex(droppedWorkspaces.first());
+ int to = dropIndex.row();
+
+ if (dropIndicator == QAbstractItemView::AboveItem && from < to)
+ --to;
+ if (dropIndicator == QAbstractItemView::BelowItem && from > to)
+ ++to;
+
+ bool hasMoved = m_manager->moveWorkspace(from, to);
+
+ if (hasMoved) {
+ m_workspaceModel.resetWorkspaces();
+ selectionModel()->setCurrentIndex(model()->index(to, 0),
+ QItemSelectionModel::ClearAndSelect
+ | QItemSelectionModel::Rows);
+ }
+
+ event->acceptProposedAction();
+}
+
+void WorkspaceView::deleteWorkspaces(const QStringList &fileNames)
+{
+ if (!confirmWorkspaceDelete(fileNames))
+ return;
+
+ m_manager->deleteWorkspaces(fileNames);
+ m_workspaceModel.resetWorkspaces();
+}
+
+bool WorkspaceView::confirmWorkspaceDelete(const QStringList &fileNames)
+{
+ const QString title = fileNames.size() == 1 ? Tr::tr("Delete Workspace")
+ : Tr::tr("Delete Workspaces");
+ const QString question
+ = fileNames.size() == 1
+ ? Tr::tr("Delete workspace %1?").arg(fileNames.first())
+ : Tr::tr("Delete these workspaces?\n %1").arg(fileNames.join("\n "));
+ return QMessageBox::question(parentWidget(), title, question, QMessageBox::Yes | QMessageBox::No)
+ == QMessageBox::Yes;
+}
+
+void WorkspaceView::runWorkspaceNameInputDialog(
+ WorkspaceNameInputDialog *workspaceInputDialog,
+ std::function<Utils::expected_str<QString>(const QString &)> callback)
+{
+ if (workspaceInputDialog->exec() == QDialog::Accepted) {
+ const QString newWorkspace = workspaceInputDialog->value();
+ if (newWorkspace.isEmpty() || m_manager->workspaces().contains(newWorkspace))
+ return;
+
+ const Utils::expected_str<QString> fileName = callback(newWorkspace);
+ if (!fileName)
+ return;
+
+ m_workspaceModel.resetWorkspaces();
+
+ if (workspaceInputDialog->isSwitchToRequested()) {
+ m_manager->openWorkspace(*fileName);
+ emit workspaceSwitched();
+ }
+
+ selectWorkspace(*fileName);
+ }
}
} // namespace ADS
diff --git a/src/libs/advanceddockingsystem/workspaceview.h b/src/libs/advanceddockingsystem/workspaceview.h
index cb507794dbb..79ecd364bd1 100644
--- a/src/libs/advanceddockingsystem/workspaceview.h
+++ b/src/libs/advanceddockingsystem/workspaceview.h
@@ -3,12 +3,12 @@
#pragma once
+#include "workspaceinputdialog.h"
#include "workspacemodel.h"
+#include <utils/expected.h>
#include <utils/itemviews.h>
-#include <QAbstractTableModel>
-
namespace ADS {
class DockManager;
@@ -22,32 +22,42 @@ public:
explicit WorkspaceView(DockManager *manager, QWidget *parent = nullptr);
void createNewWorkspace();
- void deleteSelectedWorkspaces();
void cloneCurrentWorkspace();
void renameCurrentWorkspace();
void resetCurrentWorkspace();
void switchToCurrentWorkspace();
+ void deleteSelectedWorkspaces();
void importWorkspace();
void exportCurrentWorkspace();
+ void moveWorkspaceUp();
+ void moveWorkspaceDown();
+
QString currentWorkspace();
WorkspaceModel *workspaceModel();
void selectActiveWorkspace();
- void selectWorkspace(const QString &workspaceName);
+ void selectWorkspace(const QString &fileName);
QStringList selectedWorkspaces() const;
signals:
- void workspaceActivated(const QString &workspace);
- void workspacesSelected(const QStringList &workspaces);
+ void workspaceActivated(const QString &fileName);
+ void workspacesSelected(const QStringList &fileNames);
void workspaceSwitched();
private:
void showEvent(QShowEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
+ void dropEvent(QDropEvent *event) override;
+
+ void deleteWorkspaces(const QStringList &fileNames);
+
+ bool confirmWorkspaceDelete(const QStringList &fileNames);
- void deleteWorkspaces(const QStringList &workspaces);
+ void runWorkspaceNameInputDialog(
+ WorkspaceNameInputDialog *workspaceInputDialog,
+ std::function<Utils::expected_str<QString>(const QString &)> callback);
DockManager *m_manager;
WorkspaceModel m_workspaceModel;
diff --git a/src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h b/src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h
index 5c8cd3af063..30b0cce9981 100644
--- a/src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h
+++ b/src/libs/qmlpuppetcommunication/commands/puppettocreatorcommand.h
@@ -19,7 +19,11 @@ public:
RenderModelNodePreviewImage,
Import3DSupport,
NodeAtPos,
- None };
+ BakeLightsProgress,
+ BakeLightsFinished,
+ BakeLightsAborted,
+ None
+ };
PuppetToCreatorCommand(Type type, const QVariant &data);
PuppetToCreatorCommand() = default;
diff --git a/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h b/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h
index 57abf115e17..67f0fa4c5c2 100644
--- a/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h
+++ b/src/libs/qmlpuppetcommunication/interfaces/nodeinstanceglobal.h
@@ -48,7 +48,8 @@ enum class View3DActionType {
SelectGridColor,
ResetBackgroundColor,
SyncBackgroundColor,
- GetNodeAtPos
+ GetNodeAtPos,
+ SetBakeLightsView3D
};
constexpr bool isNanotraceEnabled()
diff --git a/src/libs/sqlite/sqliteids.h b/src/libs/sqlite/sqliteids.h
index febc094242c..e7a4f9fbae2 100644
--- a/src/libs/sqlite/sqliteids.h
+++ b/src/libs/sqlite/sqliteids.h
@@ -56,7 +56,7 @@ public:
return first.id - second.id;
}
- constexpr bool isValid() const { return id >= 0; }
+ constexpr bool isValid() const { return id > 0; }
explicit operator bool() const { return isValid(); }
@@ -67,7 +67,7 @@ public:
[[noreturn, deprecated]] InternalIntegerType operator&() const { throw std::exception{}; }
private:
- InternalIntegerType id = -1;
+ InternalIntegerType id = 0;
};
template<typename Container>
diff --git a/src/libs/sqlite/sqlitelibraryinitializer.cpp b/src/libs/sqlite/sqlitelibraryinitializer.cpp
index 927157dba76..0e90348c231 100644
--- a/src/libs/sqlite/sqlitelibraryinitializer.cpp
+++ b/src/libs/sqlite/sqlitelibraryinitializer.cpp
@@ -17,7 +17,7 @@ LibraryInitializer::LibraryInitializer()
DatabaseBackend::initializeSqliteLibrary();
}
-LibraryInitializer::~LibraryInitializer()
+LibraryInitializer::~LibraryInitializer() noexcept(false)
{
DatabaseBackend::shutdownSqliteLibrary();
}
diff --git a/src/libs/sqlite/sqlitelibraryinitializer.h b/src/libs/sqlite/sqlitelibraryinitializer.h
index 27c891a1f43..bb42e822f82 100644
--- a/src/libs/sqlite/sqlitelibraryinitializer.h
+++ b/src/libs/sqlite/sqlitelibraryinitializer.h
@@ -14,7 +14,7 @@ public:
private:
LibraryInitializer();
- ~LibraryInitializer();
+ ~LibraryInitializer() noexcept(false);
};
} // namespace Sqlite
diff --git a/src/libs/sqlite/sqlitereadstatement.h b/src/libs/sqlite/sqlitereadstatement.h
index ac764166ce7..3df47efc741 100644
--- a/src/libs/sqlite/sqlitereadstatement.h
+++ b/src/libs/sqlite/sqlitereadstatement.h
@@ -34,57 +34,39 @@ public:
template<typename ResultType, typename... QueryTypes>
auto valueWithTransaction(const QueryTypes &...queryValues)
{
- DeferredTransaction transaction{Base::database()};
-
- auto resultValue = Base::template value<ResultType>(queryValues...);
-
- transaction.commit();
-
- return resultValue;
+ return withDeferredTransaction(Base::database(), [&] {
+ return Base::template value<ResultType>(queryValues...);
+ });
}
template<typename ResultType, typename... QueryTypes>
auto optionalValueWithTransaction(const QueryTypes &...queryValues)
{
- DeferredTransaction transaction{Base::database()};
-
- auto resultValue = Base::template optionalValue<ResultType>(queryValues...);
-
- transaction.commit();
-
- return resultValue;
+ return withDeferredTransaction(Base::database(), [&] {
+ return Base::template optionalValue<ResultType>(queryValues...);
+ });
}
template<typename ResultType, typename... QueryTypes>
auto valuesWithTransaction(std::size_t reserveSize, const QueryTypes &...queryValues)
{
- DeferredTransaction transaction{Base::database()};
-
- auto resultValues = Base::template values<ResultType>(reserveSize, queryValues...);
-
- transaction.commit();
-
- return resultValues;
+ return withDeferredTransaction(Base::database(), [&] {
+ return Base::template values<ResultType>(reserveSize, queryValues...);
+ });
}
template<typename Callable, typename... QueryTypes>
void readCallbackWithTransaction(Callable &&callable, const QueryTypes &...queryValues)
{
- DeferredTransaction transaction{Base::database()};
-
- Base::readCallback(std::forward<Callable>(callable), queryValues...);
-
- transaction.commit();
+ withDeferredTransaction(Base::database(), [&] {
+ Base::readCallback(std::forward<Callable>(callable), queryValues...);
+ });
}
template<typename Container, typename... QueryTypes>
void readToWithTransaction(Container &container, const QueryTypes &...queryValues)
{
- DeferredTransaction transaction{Base::database()};
-
- Base::readTo(container, queryValues...);
-
- transaction.commit();
+ withDeferredTransaction(Base::database(), [&] { Base::readTo(container, queryValues...); });
}
protected:
diff --git a/src/libs/sqlite/sqlitereadwritestatement.h b/src/libs/sqlite/sqlitereadwritestatement.h
index 69d4865d6c7..08f1aeda04c 100644
--- a/src/libs/sqlite/sqlitereadwritestatement.h
+++ b/src/libs/sqlite/sqlitereadwritestatement.h
@@ -34,66 +34,48 @@ public:
template<typename ResultType, typename... QueryTypes>
auto valueWithTransaction(const QueryTypes &...queryValues)
{
- ImmediateTransaction transaction{Base::database()};
-
- auto resultValue = Base::template value<ResultType>(queryValues...);
-
- transaction.commit();
-
- return resultValue;
+ return withImmediateTransaction(Base::database(), [&] {
+ return Base::template value<ResultType>(queryValues...);
+ });
}
template<typename ResultType, typename... QueryTypes>
auto optionalValueWithTransaction(const QueryTypes &...queryValues)
{
- ImmediateTransaction transaction{Base::database()};
-
- auto resultValue = Base::template optionalValue<ResultType>(queryValues...);
-
- transaction.commit();
-
- return resultValue;
+ return withImmediateTransaction(Base::database(), [&] {
+ return Base::template optionalValue<ResultType>(queryValues...);
+ });
}
template<typename ResultType, typename... QueryTypes>
auto valuesWithTransaction(std::size_t reserveSize, const QueryTypes &...queryValues)
{
- ImmediateTransaction transaction{Base::database()};
-
- auto resultValues = Base::template values<ResultType>(reserveSize, queryValues...);
-
- transaction.commit();
-
- return resultValues;
+ return withImmediateTransaction(Base::database(), [&] {
+ return Base::template values<ResultType>(reserveSize, queryValues...);
+ });
}
template<typename Callable, typename... QueryTypes>
void readCallbackWithTransaction(Callable &&callable, const QueryTypes &...queryValues)
{
- ImmediateTransaction transaction{Base::database()};
-
- Base::readCallback(std::forward<Callable>(callable), queryValues...);
-
- transaction.commit();
+ withImmediateTransaction(Base::database(), [&] {
+ Base::readCallback(std::forward<Callable>(callable), queryValues...);
+ });
}
template<typename Container, typename... QueryTypes>
void readToWithTransaction(Container &container, const QueryTypes &...queryValues)
{
- ImmediateTransaction transaction{Base::database()};
-
- Base::readTo(container, queryValues...);
-
- transaction.commit();
+ withImmediateTransaction(Base::database(), [&] {
+ Base::readTo(container, queryValues...);
+ });
}
void executeWithTransaction()
{
- ImmediateTransaction transaction{Base::database()};
-
- Base::execute();
-
- transaction.commit();
+ withImmediateTransaction(Base::database(), [&] {
+ Base::execute();
+ });
}
};
diff --git a/src/libs/sqlite/sqlitesessions.cpp b/src/libs/sqlite/sqlitesessions.cpp
index 0dea908e5f8..96119cd20fb 100644
--- a/src/libs/sqlite/sqlitesessions.cpp
+++ b/src/libs/sqlite/sqlitesessions.cpp
@@ -67,7 +67,7 @@ void Sessions::create()
{
sqlite3_session *newSession = nullptr;
int resultCode = sqlite3session_create(database.backend().sqliteDatabaseHandle(),
- std::string(databaseName.data()).c_str(),
+ std::string(databaseName).c_str(),
&newSession);
session.reset(newSession);
diff --git a/src/libs/sqlite/sqlitetransaction.h b/src/libs/sqlite/sqlitetransaction.h
index 45f8eebc337..2cc4a7bf5fe 100644
--- a/src/libs/sqlite/sqlitetransaction.h
+++ b/src/libs/sqlite/sqlitetransaction.h
@@ -60,7 +60,6 @@ protected:
{
}
-
protected:
TransactionInterface &m_interface;
std::unique_lock<TransactionInterface> m_locker{m_interface};
@@ -183,6 +182,38 @@ public:
using Base::Base;
};
+template<typename Transaction, typename TransactionInterface, typename Callable>
+auto withTransaction(TransactionInterface &transactionInterface, Callable &&callable)
+ -> std::invoke_result_t<Callable>
+{
+ Transaction transaction{transactionInterface};
+
+ if constexpr (std::is_void_v<std::invoke_result_t<Callable>>) {
+ callable();
+
+ transaction.commit();
+ } else {
+ auto results = callable();
+
+ transaction.commit();
+
+ return results;
+ }
+}
+
+template<typename TransactionInterface, typename Callable>
+auto withDeferredTransaction(TransactionInterface &transactionInterface, Callable &&callable)
+{
+ if constexpr (std::is_void_v<std::invoke_result_t<Callable>>) {
+ withTransaction<DeferredTransaction<TransactionInterface>>(transactionInterface,
+ std::forward<Callable>(callable));
+ } else {
+ return withTransaction<DeferredTransaction<TransactionInterface>>(transactionInterface,
+ std::forward<Callable>(
+ callable));
+ }
+}
+
template<typename TransactionInterface>
DeferredTransaction(TransactionInterface &) -> DeferredTransaction<TransactionInterface>;
@@ -226,6 +257,20 @@ public:
using Base::Base;
};
+template<typename TransactionInterface, typename Callable>
+auto withImmediateTransaction(TransactionInterface &transactionInterface, Callable &&callable)
+{
+ if constexpr (std::is_void_v<std::invoke_result_t<Callable>>) {
+ withTransaction<ImmediateTransaction<TransactionInterface>>(transactionInterface,
+ std::forward<Callable>(
+ callable));
+ } else {
+ return withTransaction<ImmediateTransaction<TransactionInterface>>(transactionInterface,
+ std::forward<Callable>(
+ callable));
+ }
+}
+
template<typename TransactionInterface>
ImmediateTransaction(TransactionInterface &) -> ImmediateTransaction<TransactionInterface>;
diff --git a/src/libs/utils/CMakeLists.txt b/src/libs/utils/CMakeLists.txt
index 51511b117db..8322ad8a452 100644
--- a/src/libs/utils/CMakeLists.txt
+++ b/src/libs/utils/CMakeLists.txt
@@ -186,9 +186,11 @@ add_qtc_library(Utils
tooltip/tips.cpp tooltip/tips.h
tooltip/tooltip.cpp tooltip/tooltip.h
touchbar/touchbar.h
+ transientscroll.cpp transientscroll.h
treemodel.cpp treemodel.h
treeviewcombobox.cpp treeviewcombobox.h
uncommentselection.cpp uncommentselection.h
+ uniqueobjectptr.h
unixutils.cpp unixutils.h
url.cpp url.h
utils.qrc
diff --git a/src/libs/utils/smallstring.h b/src/libs/utils/smallstring.h
index 90118a017ae..f4cd6b749f4 100644
--- a/src/libs/utils/smallstring.h
+++ b/src/libs/utils/smallstring.h
@@ -278,11 +278,6 @@ public:
return Q_LIKELY(isShortString()) ? m_data.shortString : m_data.reference.pointer;
}
- const char *constData() const noexcept
- {
- return data();
- }
-
iterator begin() noexcept
{
return data();
@@ -315,7 +310,7 @@ public:
const_iterator begin() const noexcept
{
- return constData();
+ return data();
}
const_iterator end() const noexcept
diff --git a/src/libs/utils/transientscroll.cpp b/src/libs/utils/transientscroll.cpp
new file mode 100644
index 00000000000..844d48de3ad
--- /dev/null
+++ b/src/libs/utils/transientscroll.cpp
@@ -0,0 +1,222 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "transientscroll.h"
+
+#include <QAbstractScrollArea>
+#include <QMouseEvent>
+#include <QPointer>
+#include <QStyle>
+#include <QStyleOption>
+
+using namespace Utils;
+
+static constexpr char transientScrollAreaSupportName[] = "transientScrollAreSupport";
+
+class Utils::ScrollAreaPrivate
+{
+public:
+ ScrollAreaPrivate(QAbstractScrollArea *area)
+ : area(area)
+ {
+ verticalScrollBar = new ScrollBar(area);
+ area->setVerticalScrollBar(verticalScrollBar);
+
+ horizontalScrollBar = new ScrollBar(area);
+ area->setHorizontalScrollBar(horizontalScrollBar);
+
+ area->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ area->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ }
+
+ inline QRect scrollBarRect(ScrollBar *scrollBar)
+ {
+ QRect rect = viewPort ? viewPort->rect() : area->rect();
+ if (scrollBar->orientation() == Qt::Vertical) {
+ int mDiff = rect.width() - scrollBar->sizeHint().width();
+ return rect.adjusted(mDiff, 0, mDiff, 0);
+ } else {
+ int mDiff = rect.height() - scrollBar->sizeHint().height();
+ return rect.adjusted(0, mDiff, 0, mDiff);
+ }
+ }
+
+ inline bool checkToFlashScroll(QPointer<ScrollBar> scrollBar, const QPoint &pos)
+ {
+ if (scrollBar.isNull())
+ return false;
+
+ if (!scrollBar->style()->styleHint(
+ QStyle::SH_ScrollBar_Transient,
+ nullptr, scrollBar))
+ return false;
+
+ if (scrollBarRect(scrollBar).contains(pos)) {
+ scrollBar->flash();
+ return true;
+ }
+
+ return false;
+ }
+
+ inline bool checkToFlashScroll(const QPoint &pos)
+ {
+ bool coversScroll = checkToFlashScroll(verticalScrollBar, pos);
+ if (!coversScroll)
+ coversScroll |= checkToFlashScroll(horizontalScrollBar, pos);
+
+ return coversScroll;
+ }
+
+ inline void installViewPort(QObject *eventHandler) {
+ QWidget *viewPort = area->viewport();
+ if (viewPort
+ && viewPort != this->viewPort
+ && viewPort->style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, viewPort)
+ && (area->verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOff
+ || area->horizontalScrollBarPolicy() != Qt::ScrollBarAlwaysOff)) {
+ viewPort->installEventFilter(eventHandler);
+ this->viewPort = viewPort;
+ }
+ }
+
+ inline void uninstallViewPort(QObject *eventHandler) {
+ if (viewPort) {
+ viewPort->removeEventFilter(eventHandler);
+ this->viewPort = nullptr;
+ }
+ }
+
+ QAbstractScrollArea *area = nullptr;
+ QPointer<QWidget> viewPort = nullptr;
+ QPointer<ScrollBar> verticalScrollBar;
+ QPointer<ScrollBar> horizontalScrollBar;
+};
+
+TransientScrollAreaSupport::TransientScrollAreaSupport(QAbstractScrollArea *scrollArea)
+ : QObject(scrollArea)
+ , d(new ScrollAreaPrivate(scrollArea))
+{
+ scrollArea->installEventFilter(this);
+}
+
+void TransientScrollAreaSupport::support(QAbstractScrollArea *scrollArea)
+{
+ QObject *prevSupport = scrollArea->property(transientScrollAreaSupportName)
+ .value<QObject *>();
+ if (!prevSupport)
+ scrollArea->setProperty(transientScrollAreaSupportName,
+ QVariant::fromValue(
+ new TransientScrollAreaSupport(scrollArea))
+ );
+}
+
+TransientScrollAreaSupport::~TransientScrollAreaSupport()
+{
+ delete d;
+}
+
+bool TransientScrollAreaSupport::eventFilter(QObject *watched, QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::Enter: {
+ if (watched == d->area)
+ d->installViewPort(this);
+ }
+ break;
+ case QEvent::Leave: {
+ if (watched == d->area)
+ d->uninstallViewPort(this);
+ }
+ break;
+ case QEvent::MouseMove: {
+ if (watched == d->viewPort){
+ QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
+ if (mouseEvent) {
+ if (d->checkToFlashScroll(mouseEvent->pos()))
+ return true;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ return QObject::eventFilter(watched, event);
+}
+
+class Utils::ScrollBarPrivate {
+public:
+ bool flashed = false;
+ int flashTimer = 0;
+};
+
+ScrollBar::ScrollBar(QWidget *parent)
+ : QScrollBar(parent)
+ , d(new ScrollBarPrivate)
+{
+}
+
+ScrollBar::~ScrollBar()
+{
+ delete d;
+}
+
+QSize ScrollBar::sizeHint() const
+{
+ QSize sh = QScrollBar::sizeHint();
+ if (style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, this)) {
+ constexpr int thickness = 10;
+ if (orientation() == Qt::Horizontal)
+ sh.setHeight(thickness);
+ else
+ sh.setWidth(thickness);
+ } else {
+ constexpr int thickness = 12;
+ if (orientation() == Qt::Horizontal)
+ sh.setHeight(thickness);
+ else
+ sh.setWidth(thickness);
+ }
+ return sh;
+}
+
+void ScrollBar::flash()
+{
+ if (!d->flashed && style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, this)) {
+ d->flashed = true;
+ if (!isVisible())
+ show();
+ else
+ update();
+ }
+ if (!d->flashTimer)
+ d->flashTimer = startTimer(0);
+}
+
+void ScrollBar::initStyleOption(QStyleOptionSlider *option) const
+{
+ QScrollBar::initStyleOption(option);
+
+ if (d->flashed && style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, this))
+ option->state |= QStyle::State_On;
+}
+
+bool ScrollBar::event(QEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::Timer:
+ if (static_cast<QTimerEvent *>(event)->timerId() == d->flashTimer) {
+ if (d->flashed && style()->styleHint(QStyle::SH_ScrollBar_Transient, nullptr, this)) {
+ d->flashed = false;
+ update();
+ }
+ killTimer(d->flashTimer);
+ d->flashTimer = 0;
+ }
+ break;
+ default:
+ break;
+ }
+ return QScrollBar::event(event);
+}
diff --git a/src/libs/utils/transientscroll.h b/src/libs/utils/transientscroll.h
new file mode 100644
index 00000000000..2042bbf0fb0
--- /dev/null
+++ b/src/libs/utils/transientscroll.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "utils_global.h"
+
+#include <QScrollBar>
+
+class QAbstractScrollArea;
+
+namespace Utils {
+class ScrollAreaPrivate;
+class ScrollBarPrivate;
+
+class QTCREATOR_UTILS_EXPORT TransientScrollAreaSupport : public QObject
+{
+ Q_OBJECT
+public:
+ static void support(QAbstractScrollArea *scrollArea);
+ virtual ~TransientScrollAreaSupport();
+
+protected:
+ virtual bool eventFilter(QObject *watched, QEvent *event) override;
+
+private:
+ explicit TransientScrollAreaSupport(QAbstractScrollArea *scrollArea);
+
+ ScrollAreaPrivate *d = nullptr;
+};
+
+class QTCREATOR_UTILS_EXPORT ScrollBar : public QScrollBar
+{
+ Q_OBJECT
+public:
+ explicit ScrollBar(QWidget *parent = nullptr);
+ virtual ~ScrollBar();
+
+ QSize sizeHint() const override;
+
+ virtual void flash();
+
+protected:
+ virtual void initStyleOption(QStyleOptionSlider *option) const override;
+ bool event(QEvent *event) override;
+
+private:
+ ScrollBarPrivate *d = nullptr;
+};
+
+}
diff --git a/src/libs/utils/uniqueobjectptr.h b/src/libs/utils/uniqueobjectptr.h
new file mode 100644
index 00000000000..1a06394dfa3
--- /dev/null
+++ b/src/libs/utils/uniqueobjectptr.h
@@ -0,0 +1,86 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <QPointer>
+
+#include <memory.h>
+#include <type_traits>
+
+namespace Utils {
+
+namespace Internal {
+
+template<typename Type>
+class UniqueObjectInternalPointer : public QPointer<Type>
+{
+public:
+ using QPointer<Type>::QPointer;
+
+ template<typename UpType,
+ typename = std::enable_if_t<std::is_convertible_v<UpType *, Type *>
+ && !std::is_same_v<std::decay_t<UpType>, std::decay_t<Type>>>>
+ UniqueObjectInternalPointer(const UniqueObjectInternalPointer<UpType> &p) noexcept
+ : QPointer<Type>{p.data()}
+ {}
+};
+
+template<typename Type>
+struct UniqueObjectPtrDeleter
+{
+ using pointer = UniqueObjectInternalPointer<Type>;
+
+ constexpr UniqueObjectPtrDeleter() noexcept = default;
+ template<typename UpType, typename = std::enable_if_t<std::is_convertible_v<UpType *, Type *>>>
+ constexpr UniqueObjectPtrDeleter(const UniqueObjectPtrDeleter<UpType> &) noexcept
+ {}
+
+ constexpr void operator()(pointer p) const
+ {
+ static_assert(!std::is_void_v<Type>, "can't delete pointer to incomplete type");
+ static_assert(sizeof(Type) > 0, "can't delete pointer to incomplete type");
+
+ delete p.data();
+ }
+};
+
+template<typename Type>
+struct UniqueObjectPtrLateDeleter
+{
+ using pointer = UniqueObjectInternalPointer<Type>;
+
+ constexpr UniqueObjectPtrLateDeleter() noexcept = default;
+ template<typename UpType, typename = std::enable_if_t<std::is_convertible_v<UpType *, Type *>>>
+ constexpr UniqueObjectPtrLateDeleter(const UniqueObjectPtrLateDeleter<UpType> &) noexcept
+ {}
+
+ constexpr void operator()(pointer p) const
+ {
+ static_assert(!std::is_void_v<Type>, "can't delete pointer to incomplete type");
+ static_assert(sizeof(Type) > 0, "can't delete pointer to incomplete type");
+
+ p->deleteLater();
+ }
+};
+
+} // namespace Internal
+
+template<typename Type>
+using UniqueObjectPtr = std::unique_ptr<Type, Internal::UniqueObjectPtrDeleter<Type>>;
+
+template<typename Type, typename... Arguments>
+auto makeUniqueObjectPtr(Arguments &&...arguments)
+{
+ return UniqueObjectPtr<Type>{new Type(std::forward<Arguments>(arguments)...)};
+}
+
+template<typename Type>
+using UniqueObjectLatePtr = std::unique_ptr<Type, Internal::UniqueObjectPtrLateDeleter<Type>>;
+
+template<typename Type, typename... Arguments>
+auto makeUniqueObjectLatePtr(Arguments &&...arguments)
+{
+ return UniqueObjectLatePtr<Type>{new Type(std::forward<Arguments>(arguments)...)};
+}
+} // namespace Utils
diff --git a/src/libs/utils/utils.qbs b/src/libs/utils/utils.qbs
index 18dcf1675cb..3196d9b34b0 100644
--- a/src/libs/utils/utils.qbs
+++ b/src/libs/utils/utils.qbs
@@ -337,6 +337,7 @@ Project {
"headerviewstretcher.h",
"uncommentselection.cpp",
"uncommentselection.h",
+ "uniqueobjectptr.h"
"unixutils.cpp",
"unixutils.h",
"url.cpp",
diff --git a/src/plugins/CMakeLists.txt b/src/plugins/CMakeLists.txt
index 33aa3db6a04..a6a2edb2989 100644
--- a/src/plugins/CMakeLists.txt
+++ b/src/plugins/CMakeLists.txt
@@ -58,15 +58,18 @@ add_subdirectory(scxmleditor)
add_subdirectory(subversion)
add_subdirectory(compilationdatabaseprojectmanager)
add_subdirectory(languageclient)
-add_subdirectory(qmldesignerbase)
-
+if (WITH_QMLDESIGNER)
+ add_subdirectory(qmldesignerbase)
+endif()
# Level 6:
add_subdirectory(cmakeprojectmanager)
add_subdirectory(debugger)
add_subdirectory(coco)
add_subdirectory(gitlab)
-add_subdirectory(qmlprojectmanager)
+if (WITH_QMLDESIGNER)
+ add_subdirectory(qmlprojectmanager)
+endif()
# Level 7:
add_subdirectory(android)
@@ -91,14 +94,17 @@ add_subdirectory(squish)
# Level 8:
add_subdirectory(boot2qt)
-unset(qmldesigner_builddir)
-if (WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
- # Workaround for @CMakeFiles\QmlDesigner.rsp ld.lld.exe: The filename or extension is too long.
- # Clang on Windows is having problems with QmlDesigner.rsp which is bigger than 32KiB
- set(qmldesigner_builddir ${PROJECT_BINARY_DIR}/qmldsgnr)
+if (WITH_QMLDESIGNER)
+ unset(qmldesigner_builddir)
+ if (WIN32 AND CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+ # Workaround for @CMakeFiles\QmlDesigner.rsp ld.lld.exe: The filename or extension is too long.
+ # Clang on Windows is having problems with QmlDesigner.rsp which is bigger than 32KiB
+ set(qmldesigner_builddir ${PROJECT_BINARY_DIR}/qmldsgnr)
+ endif()
+ add_subdirectory(qmldesigner ${qmldesigner_builddir})
+ add_subdirectory(studiowelcome)
+ add_subdirectory(insight)
endif()
-add_subdirectory(qmldesigner ${qmldesigner_builddir})
-add_subdirectory(studiowelcome)
add_subdirectory(qnx)
add_subdirectory(webassembly)
add_subdirectory(mcusupport)
diff --git a/src/plugins/coreplugin/manhattanstyle.cpp b/src/plugins/coreplugin/manhattanstyle.cpp
index b729ab0c191..0f16100e11e 100644
--- a/src/plugins/coreplugin/manhattanstyle.cpp
+++ b/src/plugins/coreplugin/manhattanstyle.cpp
@@ -95,23 +95,6 @@ bool panelWidget(const QWidget *widget)
}
// Consider making this a QStyle state
-static bool isQmlEditorMenu(const QWidget *widget)
-{
- const QMenu *menu = qobject_cast<const QMenu *> (widget);
- if (!menu)
- return false;
-
- const QWidget *p = widget;
- while (p) {
- if (p->property("qmlEditorMenu").toBool())
- return styleEnabled(widget);
- p = p->parentWidget();
- }
-
- return false;
-}
-
-// Consider making this a QStyle state
bool lightColored(const QWidget *widget)
{
if (!widget)
@@ -135,251 +118,10 @@ static bool isDarkFusionStyle(const QStyle *style)
&& strcmp(style->metaObject()->className(), "QFusionStyle") == 0;
}
-QColor qmlEditorTextColor(bool enabled,
- bool active,
- bool checked)
-{
- Theme::Color themePenColorId = enabled ? (active
- ? (checked ? Theme::DSsubPanelBackground
- : Theme::DSpanelBackground)
- : Theme::DStextColor)
- : Theme::DStextColorDisabled;
-
- return creatorTheme()->color(themePenColorId);
-}
-
-QPixmap getDeletePixmap(bool enabled,
- bool active,
- const QSize &sizeLimit)
-{
- using Utils::Theme;
- using Utils::creatorTheme;
- using namespace Utils::StyleHelper;
-
- const double xRatio = 19;
- const double yRatio = 9;
- double sizeConst = std::min(xRatio * sizeLimit.height(), yRatio * sizeLimit.width());
- sizeConst = std::max(xRatio, sizeConst);
-
- const int height = sizeConst/xRatio;
- const int width = sizeConst/yRatio;
- QPixmap retval(width, height);
- QPainter p(&retval);
- const qreal devicePixelRatio = p.device()->devicePixelRatio();
-
- QPixmap pixmap;
- QString pixmapName = QLatin1String("StyleHelper::drawDelete")
- + "-" + QString::number(sizeConst)
- + "-" + QString::number(enabled)
- + "-" + QString::number(active)
- + "-" + QString::number(devicePixelRatio);
-
- if (!QPixmapCache::find(pixmapName, &pixmap)) {
- QImage image(width * devicePixelRatio, height * devicePixelRatio, QImage::Format_ARGB32_Premultiplied);
- image.fill(Qt::transparent);
- QPainter painter(&image);
-
- auto drawDelete = [&painter, yRatio](const QRect &rect, const QColor &color) -> void
- {
- static const QStyle* const style = QApplication::style();
- if (!style)
- return;
-
- const int height = rect.height();
- const int width = rect.width();
- const int insideW = height / 2;
- const int penWidth = std::ceil(height / yRatio);
- const int pixelGuard = penWidth / 2;
- const QRect xRect = {insideW + (4 * penWidth),
- 2 * penWidth,
- 4 * penWidth,
- 5 * penWidth};
-
- // Workaround for QTCREATORBUG-28470
- painter.save();
- painter.setOpacity(color.alphaF());
-
- QPen pen(color, penWidth);
- pen.setJoinStyle(Qt::MiterJoin);
- painter.setPen(pen);
-
- QPainterPath pp(QPointF(pixelGuard, insideW));
- pp.lineTo(insideW, pixelGuard);
- pp.lineTo(width - pixelGuard, pixelGuard);
- pp.lineTo(width - pixelGuard, height - pixelGuard);
- pp.lineTo(insideW, height - pixelGuard);
- pp.lineTo(pixelGuard, insideW);
-
- painter.drawPath(pp);
-
- // drawing X
- painter.setPen(QPen(color, 1));
- QPoint stepOver(penWidth, 0);
-
- pp.clear();
- pp.moveTo(xRect.topLeft());
- pp.lineTo(xRect.topLeft() + stepOver);
- pp.lineTo(xRect.bottomRight());
- pp.lineTo(xRect.bottomRight() - stepOver);
- pp.lineTo(xRect.topLeft());
- painter.fillPath(pp, QBrush(color));
-
- pp.clear();
- pp.moveTo(xRect.topRight());
- pp.lineTo(xRect.topRight() - stepOver);
- pp.lineTo(xRect.bottomLeft());
- pp.lineTo(xRect.bottomLeft() + stepOver);
- pp.lineTo(xRect.topRight());
- painter.fillPath(pp, QBrush(color));
-
- painter.restore();
- };
-
- if (enabled && creatorTheme()->flag(Theme::ToolBarIconShadow))
- drawDelete(image.rect().translated(0, devicePixelRatio), StyleHelper::toolBarDropShadowColor());
-
- drawDelete(image.rect(), qmlEditorTextColor(enabled, active, false));
-
- painter.end();
- pixmap = QPixmap::fromImage(image);
- pixmap.setDevicePixelRatio(devicePixelRatio);
- QPixmapCache::insert(pixmapName, pixmap);
- }
- return pixmap;
-}
-
-struct ManhattanShortcut {
- ManhattanShortcut(const QStyleOptionMenuItem *option,
- const QString &shortcutText)
- : shortcutText(shortcutText)
- , enabled(option->state & QStyle::State_Enabled)
- , active(option->state & QStyle::State_Selected)
- , font(option->font)
- , fm(font)
- , defaultHeight(fm.height())
- , palette(option->palette)
- , spaceConst(fm.boundingRect(".").width())
- {
- reset();
- }
-
- QSize getSize()
- {
- if (isFirstParticle)
- calcResult();
- return _size;
- }
-
- QPixmap getPixmap()
- {
- if (!isFirstParticle && !_pixmap.isNull())
- return _pixmap;
-
- _pixmap = QPixmap(getSize());
- _pixmap.fill(Qt::transparent);
- QPainter painter(&_pixmap);
- painter.setFont(font);
- QPen pPen = painter.pen();
- pPen.setColor(qmlEditorTextColor(enabled, active, false));
- painter.setPen(pPen);
- calcResult(&painter);
- painter.end();
-
- return _pixmap;
- }
-
-private:
- void applySize(const QSize &itemSize) {
- width += itemSize.width();
- height = std::max(height, itemSize.height());
- if (isFirstParticle)
- isFirstParticle = false;
- else
- width += spaceConst;
- };
-
- void addText(const QString &txt, QPainter *painter = nullptr)
- {
- if (txt.size()) {
- int textWidth = fm.boundingRect(txt).width();
- QSize itemSize = {textWidth, defaultHeight};
- if (painter) {
- QRect placeRect({width, 0}, itemSize);
- painter->drawText(placeRect, txt, textOption);
- }
- applySize(itemSize);
- }
- };
-
- void addPixmap(const QPixmap &pixmap, QPainter *painter = nullptr)
- {
- if (painter)
- painter->drawPixmap(QRect({width, 0}, pixmap.size()), pixmap);
-
- applySize(pixmap.size());
- };
-
- void calcResult(QPainter *painter = nullptr)
- {
- reset();
-#ifndef QT_NO_SHORTCUT
- if (!shortcutText.isEmpty()) {
- int fwdIndex = 0;
- QRegularExpressionMatch mMatch = backspaceDetect.match(shortcutText);
- int matchCount = mMatch.lastCapturedIndex();
-
- for (int i = 0; i <= matchCount; ++i) {
- QString mStr = mMatch.captured(i);
- QPixmap pixmap = getDeletePixmap(enabled,
- active,
- {defaultHeight * 3, defaultHeight});
-
- int lIndex = shortcutText.indexOf(mStr, fwdIndex);
- int diffChars = lIndex - fwdIndex;
- addText(shortcutText.mid(fwdIndex, diffChars), painter);
- addPixmap(pixmap, painter);
- fwdIndex = lIndex + mStr.size();
- }
- addText(shortcutText.mid(fwdIndex), painter);
- }
-#endif
- _size = {width, height};
- }
-
- void reset()
- {
- isFirstParticle = true;
- width = 0;
- height = 0;
- }
-
- const QString shortcutText;
- const bool enabled;
- const bool active;
- const QFont font;
- const QFontMetrics fm;
- const int defaultHeight;
- const QPalette palette;
- const int spaceConst;
- static const QTextOption textOption;
- static const QRegularExpression backspaceDetect;
- bool isFirstParticle = true;
-
- int width = 0;
- int height = 0;
- QSize _size;
- QPixmap _pixmap;
-};
-const QRegularExpression ManhattanShortcut::backspaceDetect("\\+*backspace\\+*",
- QRegularExpression::CaseInsensitiveOption);
-const QTextOption ManhattanShortcut::textOption(Qt::AlignLeft | Qt::AlignVCenter);
-
-
class ManhattanStylePrivate
{
public:
explicit ManhattanStylePrivate();
- void init();
public:
const QIcon extButtonIcon;
@@ -387,15 +129,15 @@ public:
StyleAnimator animator;
};
-ManhattanStylePrivate::ManhattanStylePrivate() :
- extButtonIcon(Utils::Icons::TOOLBAR_EXTENSION.icon()),
- closeButtonPixmap(Utils::Icons::CLOSE_FOREGROUND.pixmap())
+ManhattanStylePrivate::ManhattanStylePrivate()
+ : extButtonIcon(Utils::Icons::TOOLBAR_EXTENSION.icon())
+ , closeButtonPixmap(Utils::Icons::CLOSE_FOREGROUND.pixmap())
{
}
ManhattanStyle::ManhattanStyle(const QString &baseStyleName)
- : QProxyStyle(QStyleFactory::create(baseStyleName)),
- d(new ManhattanStylePrivate())
+ : QProxyStyle(QStyleFactory::create(baseStyleName))
+ , d(new ManhattanStylePrivate())
{
Core::Internal::GeneralSettings::applyToolbarStyleFromSettings();
}
@@ -406,7 +148,10 @@ ManhattanStyle::~ManhattanStyle()
d = nullptr;
}
-QPixmap ManhattanStyle::generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const
+QPixmap ManhattanStyle::generatedIconPixmap(
+ QIcon::Mode iconMode,
+ const QPixmap &pixmap,
+ const QStyleOption *opt) const
{
return QProxyStyle::generatedIconPixmap(iconMode, pixmap, opt);
}
@@ -425,67 +170,25 @@ QSize ManhattanStyle::sizeFromContents(ContentsType type, const QStyleOption *op
if (panelWidget(widget))
newSize += QSize(14, 0);
break;
- case CT_MenuItem:
- if (isQmlEditorMenu(widget)) {
- if (const auto mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
- const int leftMargin = pixelMetric(QStyle::PM_LayoutLeftMargin, option, widget);
- const int rightMargin = pixelMetric(QStyle::PM_LayoutRightMargin, option, widget);
- const int horizontalSpacing = pixelMetric(QStyle::PM_LayoutHorizontalSpacing, option, widget);
- const int iconHeight = pixelMetric(QStyle::PM_SmallIconSize, option, widget) + horizontalSpacing;
- int width = leftMargin + rightMargin;
- if (mbi->menuHasCheckableItems || mbi->maxIconWidth)
- width += iconHeight + horizontalSpacing;
-
- if (!mbi->text.isEmpty()) {
- QString itemText = mbi->text;
- QString shortcutText;
- int tabIndex = itemText.indexOf("\t");
- if (tabIndex > -1) {
- shortcutText = itemText.mid(tabIndex + 1);
- itemText = itemText.left(tabIndex);
- }
-
- if (itemText.size())
- width += option->fontMetrics.boundingRect(itemText).width() + horizontalSpacing;
-
- if (shortcutText.size()) {
- QSize shortcutSize = ManhattanShortcut(mbi, shortcutText).getSize();
- width += shortcutSize.width() + 2 * horizontalSpacing;
- }
- }
-
- if (mbi->menuItemType == QStyleOptionMenuItem::SubMenu)
- width += iconHeight + horizontalSpacing;
-
- newSize.setWidth(width);
-
- switch (mbi->menuItemType) {
- case QStyleOptionMenuItem::Normal:
- case QStyleOptionMenuItem::DefaultItem:
- case QStyleOptionMenuItem::SubMenu:
- newSize.setHeight(19);
- break;
- default:
- newSize += QSize(0, 7);
- break;
- }
- }
- }
- break;
default:
break;
}
-
return newSize;
}
-QRect ManhattanStyle::subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const
+QRect ManhattanStyle::subElementRect(
+ SubElement element,
+ const QStyleOption *option,
+ const QWidget *widget) const
{
return QProxyStyle::subElementRect(element, option, widget);
}
-QRect ManhattanStyle::subControlRect(ComplexControl control, const QStyleOptionComplex *option,
- SubControl subControl, const QWidget *widget) const
+QRect ManhattanStyle::subControlRect(
+ ComplexControl control,
+ const QStyleOptionComplex *option,
+ SubControl subControl,
+ const QWidget *widget) const
{
#if QT_VERSION < QT_VERSION_CHECK(6, 2, 5)
// Workaround for QTBUG-101581, can be removed when building with Qt 6.2.5 or higher
@@ -495,30 +198,7 @@ QRect ManhattanStyle::subControlRect(ComplexControl control, const QStyleOptionC
return QRect(); // breaks the scrollbar, but avoids the crash
}
#endif
-
- QRect retval = QProxyStyle::subControlRect(control, option, subControl, widget);;
- if (panelWidget(widget)) {
- if (const QStyleOptionSlider *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
- switch (subControl) {
- case SubControl::SC_SliderGroove:
- return option->rect;
- case SubControl::SC_SliderHandle:
- {
- int thickness = 2;
- QPoint center = retval.center();
- const QRect &rect = slider->rect;
- if (slider->orientation == Qt::Horizontal)
- return QRect(center.x() - thickness, rect.top(), (thickness * 2) + 1, rect.height());
- else
- return QRect(rect.left(), center.y() - thickness, rect.width(), (thickness * 2) + 1);
- }
- break;
- default:
- break;
- }
- }
- }
- return retval;
+ return QProxyStyle::subControlRect(control, option, subControl, widget);
}
QStyle::SubControl ManhattanStyle::hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option,
@@ -548,61 +228,31 @@ int ManhattanStyle::pixelMetric(PixelMetric metric, const QStyleOption *option,
retval = 16;
break;
case PM_SmallIconSize:
- if (isQmlEditorMenu(widget))
- retval = 10;
- else
- retval = 16;
+ retval = 16;
break;
case PM_DockWidgetHandleExtent:
case PM_DockWidgetSeparatorExtent:
- return 1;
- case PM_LayoutLeftMargin:
- case PM_LayoutRightMargin:
- if (isQmlEditorMenu(widget))
- retval = 7;
- break;
- case PM_LayoutHorizontalSpacing:
- if (isQmlEditorMenu(widget))
- retval = 12;
- break;
- case PM_MenuHMargin:
- if (isQmlEditorMenu(widget))
- retval = 5;
- break;
- case PM_SubMenuOverlap:
- if (isQmlEditorMenu(widget))
- retval = 10;
+ retval = 1;
break;
case PM_MenuPanelWidth:
case PM_MenuBarHMargin:
case PM_MenuBarVMargin:
case PM_ToolBarFrameWidth:
- if (panelWidget(widget) || isQmlEditorMenu(widget))
+ if (panelWidget(widget))
retval = 1;
break;
case PM_ButtonShiftVertical:
case PM_ButtonShiftHorizontal:
case PM_MenuBarPanelWidth:
case PM_ToolBarItemMargin:
- if (StyleHelper::isQDSTheme()) {
- retval = 0;
- break;
- }
- [[fallthrough]];
case PM_ToolBarItemSpacing:
if (panelWidget(widget))
retval = 0;
- if (StyleHelper::isQDSTheme())
- retval = 4;
break;
case PM_DefaultFrameWidth:
if (qobject_cast<const QLineEdit*>(widget) && panelWidget(widget))
return 1;
break;
- case PM_ToolBarExtensionExtent:
- if (StyleHelper::isQDSTheme())
- retval = 29;
- break;
default:
break;
}
@@ -739,17 +389,20 @@ QIcon ManhattanStyle::standardIcon(StandardPixmap standardIcon, const QStyleOpti
case QStyle::SP_ToolBarHorizontalExtensionButton:
icon = d->extButtonIcon;
break;
- default:
+ case QStyle::SP_ComputerIcon:
+ {
icon = QProxyStyle::standardIcon(standardIcon, option, widget);
- break;
- }
- if (standardIcon == QStyle::SP_ComputerIcon) {
// Ubuntu has in some versions a 16x16 icon, see QTCREATORBUG-12832
const QList<QSize> &sizes = icon.availableSizes();
if (Utils::allOf(sizes, [](const QSize &size) { return size.width() < 32;}))
icon = QIcon(":/utils/images/Desktop.png");
}
+ break;
+ default:
+ icon = QProxyStyle::standardIcon(standardIcon, option, widget);
+ break;
+ }
return icon;
}
@@ -929,8 +582,6 @@ void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption
{
if (panelWidget(widget)) {
drawPrimitiveForPanelWidget(element, option, painter, widget);
- } else if (isQmlEditorMenu(widget)) {
- drawPrimitiveForQmlEditor(element, option, painter, widget);
} else {
const bool tweakDarkTheme =
(element == PE_Frame
@@ -944,7 +595,6 @@ void ManhattanStyle::drawPrimitive(PrimitiveElement element, const QStyleOption
drawPrimitiveTweakedForDarkTheme(element, option, painter, widget);
else
QProxyStyle::drawPrimitive(element, option, painter, widget);
- return;
}
}
@@ -953,61 +603,8 @@ void ManhattanStyle::drawPrimitiveForPanelWidget(PrimitiveElement element,
QPainter *painter,
const QWidget *widget) const
{
- bool animating = (option->state & State_Animating);
int state = option->state;
QRect rect = option->rect;
- QRect oldRect;
- QRect newRect;
- if (widget && (element == PE_PanelButtonTool) && !animating) {
- auto w = const_cast<QWidget *> (widget);
- int oldState = w->property("_q_stylestate").toInt();
- oldRect = w->property("_q_stylerect").toRect();
- newRect = w->rect();
- w->setProperty("_q_stylestate", (int)option->state);
- w->setProperty("_q_stylerect", w->rect());
-
- // Determine the animated transition
- bool doTransition = ((state & State_On) != (oldState & State_On) ||
- (state & State_MouseOver) != (oldState & State_MouseOver));
- if (oldRect != newRect)
- {
- doTransition = false;
- d->animator.stopAnimation(widget);
- }
-
- if (doTransition) {
- QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
- QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
- Animation *anim = d->animator.widgetAnimation(widget);
- QStyleOption opt = *option;
- opt.state = (QStyle::State)oldState;
- opt.state |= State_Animating;
- startImage.fill(0);
- auto t = new Transition;
- t->setWidget(w);
- QPainter startPainter(&startImage);
- if (!anim) {
- drawPrimitive(element, &opt, &startPainter, widget);
- } else {
- anim->paint(&startPainter, &opt);
- d->animator.stopAnimation(widget);
- }
- QStyleOption endOpt = *option;
- endOpt.state |= State_Animating;
- t->setStartImage(startImage);
- d->animator.startAnimation(t);
- endImage.fill(0);
- QPainter endPainter(&endImage);
- drawPrimitive(element, &endOpt, &endPainter, widget);
- t->setEndImage(endImage);
- if (oldState & State_MouseOver)
- t->setDuration(150);
- else
- t->setDuration(75);
- t->setStartTime(QTime::currentTime());
- }
- }
-
switch (element) {
case PE_IndicatorDockWidgetResizeHandle:
painter->fillRect(option->rect, creatorTheme()->color(Theme::DockWidgetResizeHandleColor));
@@ -1060,13 +657,65 @@ void ManhattanStyle::drawPrimitiveForPanelWidget(PrimitiveElement element,
break;
case PE_PanelButtonTool: {
- Animation *anim = d->animator.widgetAnimation(widget);
- if (!animating && anim) {
+ painter->save();
+ const bool animating = (state & State_Animating);
+
+ if (widget && !animating) {
+ auto w = const_cast<QWidget *> (widget);
+ int oldState = w->property("_q_stylestate").toInt();
+ QRect oldRect = w->property("_q_stylerect").toRect();
+ QRect newRect = w->rect();
+ w->setProperty("_q_stylestate", (int)option->state);
+ w->setProperty("_q_stylerect", w->rect());
+
+ // Determine the animated transition
+ bool doTransition = ((state & State_On) != (oldState & State_On) ||
+ (state & State_MouseOver) != (oldState & State_MouseOver));
+ if (oldRect != newRect) {
+ doTransition = false;
+ d->animator.stopAnimation(widget);
+ }
+
+ if (doTransition) {
+ QImage startImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
+ QImage endImage(option->rect.size(), QImage::Format_ARGB32_Premultiplied);
+ Animation *anim = d->animator.widgetAnimation(widget);
+ QStyleOption opt = *option;
+ opt.state = (QStyle::State)oldState;
+ opt.state |= State_Animating;
+ startImage.fill(0);
+ auto t = new Transition;
+ t->setWidget(w);
+ QPainter startPainter(&startImage);
+ if (!anim) {
+ drawPrimitive(element, &opt, &startPainter, widget);
+ } else {
+ anim->paint(&startPainter, &opt);
+ d->animator.stopAnimation(widget);
+ }
+ QStyleOption endOpt = *option;
+ endOpt.state |= State_Animating;
+ t->setStartImage(startImage);
+ d->animator.startAnimation(t);
+ endImage.fill(0);
+ QPainter endPainter(&endImage);
+ drawPrimitive(element, &endOpt, &endPainter, widget);
+ t->setEndImage(endImage);
+ if (oldState & State_MouseOver)
+ t->setDuration(150);
+ else
+ t->setDuration(75);
+ t->setStartTime(QTime::currentTime());
+ }
+ }
+
+ Animation *anim = d->animator.widgetAnimation(widget);
+
+ if (!animating && anim) {
anim->paint(painter, option);
- } else {
+ } else {
const bool pressed = option->state & State_Sunken || option->state & State_On
- || (widget && widget->property(StyleHelper::C_HIGHLIGHT_WIDGET)
- .toBool());
+ || (widget && widget->property(StyleHelper::C_HIGHLIGHT_WIDGET).toBool());
painter->setPen(StyleHelper::sidebarShadow());
if (pressed) {
StyleHelper::drawPanelBgRect(
@@ -1082,18 +731,19 @@ void ManhattanStyle::drawPrimitiveForPanelWidget(PrimitiveElement element,
StyleHelper::drawPanelBgRect(
painter, rect, creatorTheme()->color(Theme::FancyToolButtonHoverColor));
}
- if (option->state & State_HasFocus && (option->state & State_KeyboardFocusChange)) {
- QColor highlight = option->palette.highlight().color();
- highlight.setAlphaF(0.4f);
- painter->setPen(QPen(highlight.lighter(), 1));
- highlight.setAlphaF(0.3f);
- painter->setBrush(highlight);
- painter->setRenderHint(QPainter::Antialiasing);
- const QRectF rect = option->rect;
- painter->drawRoundedRect(rect.adjusted(2.5, 2.5, -2.5, -2.5), 2, 2);
- }
- }
+ if (option->state & State_HasFocus && (option->state & State_KeyboardFocusChange)) {
+ QColor highlight = option->palette.highlight().color();
+ highlight.setAlphaF(0.4f);
+ painter->setPen(QPen(highlight.lighter(), 1));
+ highlight.setAlphaF(0.3f);
+ painter->setBrush(highlight);
+ painter->setRenderHint(QPainter::Antialiasing);
+ const QRectF rect = option->rect;
+ painter->drawRoundedRect(rect.adjusted(2.5, 2.5, -2.5, -2.5), 2, 2);
+ }
}
+ painter->restore();
+ }
break;
case PE_PanelStatusBar:
@@ -1185,227 +835,11 @@ void ManhattanStyle::drawPrimitiveForPanelWidget(PrimitiveElement element,
}
}
-void ManhattanStyle::drawPrimitiveForQmlEditor(PrimitiveElement element,
- const QStyleOption *option,
- QPainter *painter,
- const QWidget *widget) const
-{
- const auto mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option);
- if (!mbi) {
- QProxyStyle::drawPrimitive(element, option, painter, widget);
- return;
- }
-
- switch (element) {
- case PE_IndicatorArrowUp:
- case PE_IndicatorArrowDown:
- {
- QStyleOptionMenuItem item = *mbi;
- item.palette = QPalette(Qt::white);
- StyleHelper::drawMinimalArrow(element, painter, &item);
- }
- break;
- case PE_IndicatorArrowRight:
- drawQmlEditorIcon(element, option, "cascadeIconRight", painter, widget);
- break;
- case PE_IndicatorArrowLeft:
- drawQmlEditorIcon(element, option, "cascadeIconLeft", painter, widget);
- break;
- case PE_PanelButtonCommand:
- break;
- case PE_IndicatorMenuCheckMark:
- drawQmlEditorIcon(element, option, "tickIcon", painter, widget);
- break;
- case PE_FrameMenu:
- case PE_PanelMenu:
- {
- painter->save();
- painter->setBrush(creatorTheme()->color(Theme::DSsubPanelBackground));
- painter->setPen(Qt::NoPen);
- painter->drawRect(option->rect);
- painter->restore();
- }
- break;
- default:
- QProxyStyle::drawPrimitive(element, option, painter, widget);
- break;
- }
-}
-
-void ManhattanStyle::drawControlForQmlEditor(ControlElement element,
- const QStyleOption *option,
- QPainter *painter,
- const QWidget *widget) const
-{
- Q_UNUSED(element)
- if (const auto mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
- painter->save();
- const int iconHeight = pixelMetric(QStyle::PM_SmallIconSize, option, widget);
- const int horizontalSpacing = pixelMetric(QStyle::PM_LayoutHorizontalSpacing, option, widget);
- const int iconWidth = iconHeight;
- const bool isActive = mbi->state & State_Selected;
- const bool isDisabled = !(mbi->state & State_Enabled);
- const bool isCheckable = mbi->checkType != QStyleOptionMenuItem::NotCheckable;
- const bool isChecked = isCheckable ? mbi->checked : false;
- int startMargin = pixelMetric(QStyle::PM_LayoutLeftMargin, option, widget);
- int endMargin = pixelMetric(QStyle::PM_LayoutRightMargin, option, widget);
- int forwardX = 0;
-
- if (option->direction == Qt::RightToLeft)
- std::swap(startMargin, endMargin);
-
- QStyleOptionMenuItem item = *mbi;
-
- if (isActive) {
- painter->fillRect(item.rect, creatorTheme()->color(Theme::DSinteraction));
- }
- forwardX += startMargin;
-
- if (item.menuItemType == QStyleOptionMenuItem::Separator) {
- int commonHeight = item.rect.center().y();
- int additionalMargin = forwardX /*hmargin*/;
- QLineF separatorLine (item.rect.left() + additionalMargin,
- commonHeight,
- item.rect.right() - additionalMargin,
- commonHeight);
-
- painter->setPen(creatorTheme()->color(Theme::DSstateSeparatorColor));
- painter->drawLine(separatorLine);
- item.text.clear();
- painter->restore();
- return;
- }
-
- QPixmap iconPixmap;
- QIcon::Mode mode = isDisabled ? QIcon::Disabled : ((isActive) ? QIcon::Active : QIcon::Normal);
- QIcon::State state = isChecked ? QIcon::On : QIcon::Off;
- QColor themePenColor = qmlEditorTextColor(!isDisabled, isActive, isChecked);
-
- if (!item.icon.isNull()) {
- iconPixmap = item.icon.pixmap(QSize(iconHeight, iconHeight), mode, state);
- } else if (isCheckable) {
- iconPixmap = QPixmap(iconHeight, iconHeight);
- iconPixmap.fill(Qt::transparent);
-
- if (item.checked) {
- QStyleOptionMenuItem so = item;
- so.rect = iconPixmap.rect();
- QPainter dPainter(&iconPixmap);
- dPainter.setPen(themePenColor);
- drawPrimitive(PE_IndicatorMenuCheckMark, &so, &dPainter, widget);
- }
- }
-
- if (!iconPixmap.isNull()) {
- QRect vCheckRect = visualRect(item.direction,
- item.rect,
- QRect(item.rect.x() + forwardX,
- item.rect.y(),
- iconWidth,
- item.rect.height()));
-
- QRect pmr(QPoint(0, 0), iconPixmap.deviceIndependentSize().toSize());
- pmr.moveCenter(vCheckRect.center());
- painter->setPen(themePenColor);
- painter->drawPixmap(pmr.topLeft(), iconPixmap);
-
- item.checkType = QStyleOptionMenuItem::NotCheckable;
- item.checked = false;
- item.icon = {};
- }
- if (item.menuHasCheckableItems || item.maxIconWidth > 0) {
- forwardX += iconWidth + horizontalSpacing;
- }
-
- QString shortcutText;
- int tabIndex = item.text.indexOf("\t");
- if (tabIndex > -1) {
- shortcutText = item.text.mid(tabIndex + 1);
- item.text = item.text.left(tabIndex);
- }
-
- if (item.text.size()) {
- painter->save();
-
- QRect vTextRect = visualRect(item.direction,
- item.rect,
- item.rect.adjusted(forwardX, 0 , 0 , 0));
-
- Qt::Alignment alignmentFlags = item.direction == Qt::LeftToRight ? Qt::AlignLeft
- : Qt::AlignRight;
- alignmentFlags |= Qt::AlignVCenter;
-
- int textFlags = Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
- if (!proxy()->styleHint(SH_UnderlineShortcut, &item, widget))
- textFlags |= Qt::TextHideMnemonic;
- textFlags |= alignmentFlags;
-
- painter->setPen(themePenColor);
- painter->drawText(vTextRect, textFlags, item.text);
- painter->restore();
- }
-
- if (item.menuItemType == QStyleOptionMenuItem::SubMenu) {
- PrimitiveElement dropDirElement = item.direction == Qt::LeftToRight ? PE_IndicatorArrowRight
- : PE_IndicatorArrowLeft;
-
- QSize elSize(iconHeight, iconHeight);
- int xOffset = iconHeight + endMargin;
- int yOffset = (item.rect.height() - iconHeight) / 2;
- QRect dropRect(item.rect.topRight(), elSize);
- dropRect.adjust(-xOffset, yOffset, -xOffset, yOffset);
-
- QStyleOptionMenuItem so = item;
- so.rect = visualRect(item.direction,
- item.rect,
- dropRect);
-
- drawPrimitive(dropDirElement, &so, painter, widget);
- } else if (!shortcutText.isEmpty()) {
- QPixmap pix = ManhattanShortcut(&item, shortcutText).getPixmap();
-
- if (pix.width()) {
- int xOffset = pix.width() + (iconHeight / 2) + endMargin;
- QRect shortcutRect = item.rect.translated({item.rect.width() - xOffset, 0});
- shortcutRect.setSize({pix.width(), item.rect.height()});
- shortcutRect = visualRect(item.direction,
- item.rect,
- shortcutRect);
- drawItemPixmap(painter,
- shortcutRect,
- Qt::AlignRight | Qt::AlignVCenter,
- pix);
- }
- }
- painter->restore();
- }
-}
-
-void ManhattanStyle::drawQmlEditorIcon(PrimitiveElement element,
- const QStyleOption *option,
- const char *propertyName,
- QPainter *painter,
- const QWidget *widget) const
-{
- if (option->styleObject && option->styleObject->property(propertyName).isValid()) {
- const auto mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option);
- if (mbi) {
- const bool checkable = mbi->checkType != QStyleOptionMenuItem::NotCheckable;
- const bool isDisabled = !(mbi->state & State_Enabled);
- const bool isActive = mbi->state & State_Selected;
- QIcon icon = mbi->styleObject->property(propertyName).value<QIcon>();
- QIcon::Mode mode = isDisabled ? QIcon::Disabled : ((isActive) ? QIcon::Active : QIcon::Normal);
- QIcon::State state = (checkable && mbi->checked) ? QIcon::On : QIcon::Off;
- QPixmap pix = icon.pixmap(option->rect.size(), mode, state);
- drawItemPixmap(painter, option->rect, Qt::AlignCenter, pix);
- return;
- }
- }
- QProxyStyle::drawPrimitive(element, option, painter, widget);
-}
-
-void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *option,
- QPainter *painter, const QWidget *widget) const
+void ManhattanStyle::drawControl(
+ ControlElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget) const
{
if (!panelWidget(widget) && !qobject_cast<const QMenu *>(widget)) {
QProxyStyle::drawControl(element, option, painter, widget);
@@ -1428,10 +862,7 @@ void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *opt
item.palette = pal;
}
- if (isQmlEditorMenu(widget))
- drawControlForQmlEditor(element, &item, painter, widget);
- else
- QProxyStyle::drawControl(element, &item, painter, widget);
+ QProxyStyle::drawControl(element, &item, painter, widget);
}
painter->restore();
break;
@@ -1592,13 +1023,6 @@ void ManhattanStyle::drawControl(ControlElement element, const QStyleOption *opt
}
break;
- case CE_MenuEmptyArea:
- if (isQmlEditorMenu(widget))
- drawPrimitive(PE_PanelMenu, option, painter, widget);
- else
- QProxyStyle::drawControl(element, option, painter, widget);
-
- break;
case CE_ToolBar:
{
QRect rect = option->rect;
@@ -1820,170 +1244,6 @@ void ManhattanStyle::drawComplexControl(ComplexControl control, const QStyleOpti
painter->restore();
}
break;
- case CC_Slider:
- if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
- QRect groove = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
- QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
-
- bool horizontal = slider->orientation == Qt::Horizontal;
- bool ticksAbove = slider->tickPosition & QSlider::TicksAbove;
- bool ticksBelow = slider->tickPosition & QSlider::TicksBelow;
- bool enabled = option->state & QStyle::State_Enabled;
- bool grooveHover = slider->activeSubControls & SC_SliderGroove;
- bool handleHover = slider->activeSubControls & SC_SliderHandle;
- bool interaction = option->state & State_Sunken;
- bool activeFocus = option->state & State_HasFocus && option->state & State_KeyboardFocusChange;
-
- int sliderPaintingOffset = horizontal
- ? handle.center().x()
- : handle.center().y();
-
- int borderRadius = 4;
-
- painter->save();
- painter->setRenderHint(QPainter::RenderHint::Antialiasing);
-
- int lineWidth = pixelMetric(QStyle::PM_DefaultFrameWidth, option, widget);
- Theme::Color themeframeColor = enabled
- ? interaction
- ? Theme::DSstateControlBackgroundColor_hover // Pressed
- : grooveHover
- ? Theme::DSstateSeparatorColor // GrooveHover
- : Theme::DSpopupBackground // Idle
- : Theme::DSpopupBackground; // Disabled
-
- QColor frameColor = creatorTheme()->color(themeframeColor);
-
- if ((option->subControls & SC_SliderGroove) && groove.isValid()) {
- Theme::Color bgPlusColor = enabled
- ? interaction
- ? Theme::DSstateControlBackgroundColor_hover // Pressed
- : grooveHover
- ? Theme::DSstateSeparatorColor // GrooveHover
- : Theme::DStoolbarBackground // Idle
- : Theme::DStoolbarBackground; // Disabled
- Theme::Color bgMinusColor = Theme::DSpopupBackground;
-
- QRect minusRect(groove);
- QRect plusRect(groove);
-
- if (horizontal) {
- if (slider->upsideDown) {
- minusRect.setLeft(sliderPaintingOffset);
- plusRect.setRight(sliderPaintingOffset);
- } else {
- minusRect.setRight(sliderPaintingOffset);
- plusRect.setLeft(sliderPaintingOffset);
- }
- } else {
- if (slider->upsideDown) {
- minusRect.setBottom(sliderPaintingOffset);
- plusRect.setTop(sliderPaintingOffset);
- } else {
- minusRect.setTop(sliderPaintingOffset);
- plusRect.setBottom(sliderPaintingOffset);
- }
- }
-
- painter->save();
- painter->setPen(Qt::NoPen);
- painter->setBrush(creatorTheme()->color(bgPlusColor));
- painter->drawRoundedRect(plusRect, borderRadius, borderRadius);
- painter->setBrush(creatorTheme()->color(bgMinusColor));
- painter->drawRoundedRect(minusRect, borderRadius, borderRadius);
- painter->restore();
- }
-
- if (option->subControls & SC_SliderTickmarks) {
- Theme::Color tickPen = enabled
- ? activeFocus
- ? Theme::DSstateBackgroundColor_hover
- : Theme::DSBackgroundColorAlternate
- : Theme::DScontrolBackgroundDisabled;
-
- painter->setPen(tickPen);
- int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget);
- int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
- int interval = slider->tickInterval;
- if (interval <= 0) {
- interval = slider->singleStep;
- if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
- available)
- - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
- 0, available) < 3)
- interval = slider->pageStep;
- }
- if (interval <= 0)
- interval = 1;
-
- int v = slider->minimum;
- int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
- while (v <= slider->maximum + 1) {
- if (v == slider->maximum + 1 && interval == 1)
- break;
- const int v_ = qMin(v, slider->maximum);
- int pos = sliderPositionFromValue(slider->minimum, slider->maximum,
- v_, (horizontal
- ? slider->rect.width()
- : slider->rect.height()) - len,
- slider->upsideDown) + len / 2;
- int extra = 2 - ((v_ == slider->minimum || v_ == slider->maximum) ? 1 : 0);
-
- if (horizontal) {
- if (ticksAbove) {
- painter->drawLine(pos, slider->rect.top() + extra,
- pos, slider->rect.top() + tickSize);
- }
- if (ticksBelow) {
- painter->drawLine(pos, slider->rect.bottom() - extra,
- pos, slider->rect.bottom() - tickSize);
- }
- } else {
- if (ticksAbove) {
- painter->drawLine(slider->rect.left() + extra, pos,
- slider->rect.left() + tickSize, pos);
- }
- if (ticksBelow) {
- painter->drawLine(slider->rect.right() - extra, pos,
- slider->rect.right() - tickSize, pos);
- }
- }
- // in the case where maximum is max int
- int nextInterval = v + interval;
- if (nextInterval < v)
- break;
- v = nextInterval;
- }
- }
-
- // draw handle
- if ((option->subControls & SC_SliderHandle) ) {
- Theme::Color handleColor = enabled
- ? interaction
- ? Theme::DSinteraction // Interaction
- : grooveHover || handleHover
- ? Theme::DStabActiveText // Hover
- : Theme::PalettePlaceholderText // Idle
- : Theme::DStoolbarIcon_blocked; // Disabled
-
- int halfSliderThickness = horizontal
- ? handle.width() / 2
- : handle.height() / 2;
- painter->setBrush(creatorTheme()->color(handleColor));
- painter->setPen(Qt::NoPen);
- painter->drawRoundedRect(handle,
- halfSliderThickness,
- halfSliderThickness);
- }
-
- if (groove.isValid()) {
- painter->setBrush(Qt::NoBrush);
- painter->setPen(QPen(frameColor, lineWidth));
- painter->drawRoundedRect(groove, borderRadius, borderRadius);
- }
- painter->restore();
- }
- break;
default:
QProxyStyle::drawComplexControl(control, option, painter, widget);
break;
diff --git a/src/plugins/coreplugin/manhattanstyle.h b/src/plugins/coreplugin/manhattanstyle.h
index 07079c7d2dd..ae9cd42a1fa 100644
--- a/src/plugins/coreplugin/manhattanstyle.h
+++ b/src/plugins/coreplugin/manhattanstyle.h
@@ -16,25 +16,77 @@ class CORE_EXPORT ManhattanStyle : public QProxyStyle
public:
explicit ManhattanStyle(const QString &baseStyleName);
- ~ManhattanStyle() override;
+ virtual ~ManhattanStyle() override;
+
+ void drawPrimitive(
+ PrimitiveElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget = nullptr) const override;
+
+ void drawControl(
+ ControlElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget = nullptr) const override;
+
+ void drawComplexControl(
+ ComplexControl control,
+ const QStyleOptionComplex *option,
+ QPainter *painter,
+ const QWidget *widget = nullptr) const override;
+
+ QSize sizeFromContents(
+ ContentsType type,
+ const QStyleOption *option,
+ const QSize &size,
+ const QWidget *widget) const override;
+
+ QRect subElementRect(
+ SubElement element,
+ const QStyleOption *option,
+ const QWidget *widget) const override;
+
+ QRect subControlRect(
+ ComplexControl control,
+ const QStyleOptionComplex *option,
+ SubControl subControl,
+ const QWidget *widget) const override;
+
+ int styleHint(
+ StyleHint hint,
+ const QStyleOption *option = nullptr,
+ const QWidget *widget = nullptr,
+ QStyleHintReturn *returnData = nullptr) const override;
+
+ int pixelMetric(
+ PixelMetric metric,
+ const QStyleOption *option = nullptr,
+ const QWidget *widget = nullptr) const override;
- void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const override;
- void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget = nullptr) const override;
- void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget = nullptr) const override;
+ QPalette standardPalette() const override;
- QSize sizeFromContents(ContentsType type, const QStyleOption *option, const QSize &size, const QWidget *widget) const override;
- QRect subElementRect(SubElement element, const QStyleOption *option, const QWidget *widget) const override;
- QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *widget) const override;
- SubControl hitTestComplexControl(ComplexControl control, const QStyleOptionComplex *option, const QPoint &pos, const QWidget *widget = nullptr) const override;
- QPixmap standardPixmap(StandardPixmap standardPixmap, const QStyleOption *opt, const QWidget *widget = nullptr) const override;
- QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const override;
- int styleHint(StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, QStyleHintReturn *returnData = nullptr) const override;
- QPixmap generatedIconPixmap(QIcon::Mode iconMode, const QPixmap &pixmap, const QStyleOption *opt) const override;
+ QIcon standardIcon(
+ StandardPixmap standardIcon,
+ const QStyleOption *option = nullptr,
+ const QWidget *widget = nullptr) const override;
- int pixelMetric(PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const override;
+ SubControl hitTestComplexControl(
+ ComplexControl control,
+ const QStyleOptionComplex *option,
+ const QPoint &pos,
+ const QWidget *widget = nullptr) const override;
- QPalette standardPalette() const override;
+ QPixmap standardPixmap(
+ StandardPixmap standardPixmap,
+ const QStyleOption *opt,
+ const QWidget *widget = nullptr) const override;
+
+ QPixmap generatedIconPixmap(
+ QIcon::Mode iconMode,
+ const QPixmap &pixmap,
+ const QStyleOption *opt) const override;
void polish(QWidget *widget) override;
void polish(QPalette &pal) override;
@@ -44,28 +96,16 @@ public:
void unpolish(QApplication *app) override;
private:
- void drawPrimitiveForPanelWidget(PrimitiveElement element,
- const QStyleOption *option,
- QPainter *painter,
- const QWidget *widget) const;
-
- void drawPrimitiveForQmlEditor(PrimitiveElement element,
- const QStyleOption *option,
- QPainter *painter,
- const QWidget *widget) const;
-
- void drawControlForQmlEditor(ControlElement element,
- const QStyleOption *option,
- QPainter *painter,
- const QWidget *widget = nullptr) const;
-
- void drawQmlEditorIcon(PrimitiveElement element,
- const QStyleOption *option,
- const char *propertyName,
- QPainter *painter,
- const QWidget *widget = nullptr) const;
-
- static void drawButtonSeparator(QPainter *painter, const QRect &rect, bool reverse);
-
- ManhattanStylePrivate *d;
+ void drawPrimitiveForPanelWidget(
+ PrimitiveElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget) const;
+
+ static void drawButtonSeparator(
+ QPainter *painter,
+ const QRect &rect,
+ bool reverse);
+
+ ManhattanStylePrivate *d = nullptr;
};
diff --git a/src/plugins/coreplugin/outputpane.cpp b/src/plugins/coreplugin/outputpane.cpp
index 67e57448aac..81473320bbd 100644
--- a/src/plugins/coreplugin/outputpane.cpp
+++ b/src/plugins/coreplugin/outputpane.cpp
@@ -183,6 +183,10 @@ void OutputPanePlaceHolder::showEvent(QShowEvent *)
d->m_initialized = true;
setHeight(Internal::OutputPaneManager::outputPaneHeightSetting());
}
+ if (OutputPanePlaceHolderPrivate::m_current == this) {
+ Internal::OutputPaneManager *om = Internal::OutputPaneManager::instance();
+ om->updateStatusButtons(true);
+ }
}
OutputPanePlaceHolder *OutputPanePlaceHolder::getCurrent()
diff --git a/src/plugins/coreplugin/outputpanemanager.cpp b/src/plugins/coreplugin/outputpanemanager.cpp
index 906a940a40d..b26caf92322 100644
--- a/src/plugins/coreplugin/outputpanemanager.cpp
+++ b/src/plugins/coreplugin/outputpanemanager.cpp
@@ -497,6 +497,9 @@ void OutputPaneManager::initialize()
m_instance->m_titleLabel->setMinimumWidth(
minTitleWidth + m_instance->m_titleLabel->contentsMargins().left()
+ m_instance->m_titleLabel->contentsMargins().right());
+ const int currentIdx = m_instance->currentIndex();
+ if (QTC_GUARD(currentIdx >= 0 && currentIdx < g_outputPanes.size()))
+ m_instance->m_titleLabel->setText(g_outputPanes[currentIdx].pane->displayName());
m_instance->m_buttonsWidget->layout()->addWidget(m_instance->m_manageButton);
connect(m_instance->m_manageButton,
&QAbstractButton::clicked,
@@ -575,7 +578,12 @@ void OutputPaneManager::readSettings()
}
settings->endArray();
- m_outputPaneHeightSetting = settings->value(QLatin1String("OutputPanePlaceHolder/Height"), 0).toInt();
+ m_outputPaneHeightSetting
+ = settings->value(QLatin1String("OutputPanePlaceHolder/Height"), 0).toInt();
+ const int currentIdx
+ = settings->value(QLatin1String("OutputPanePlaceHolder/CurrentIndex"), 0).toInt();
+ if (QTC_GUARD(currentIdx >= 0 && currentIdx < g_outputPanes.size()))
+ setCurrentIndex(currentIdx);
}
void OutputPaneManager::slotNext()
@@ -682,7 +690,8 @@ void OutputPaneManager::setCurrentIndex(int idx)
OutputPaneData &data = g_outputPanes[idx];
IOutputPane *pane = data.pane;
data.button->show();
- pane->visibilityChanged(true);
+ if (OutputPanePlaceHolder::isCurrentVisible())
+ pane->visibilityChanged(true);
bool canNavigate = pane->canNavigate();
m_prevAction->setEnabled(canNavigate && pane->canPrevious());
@@ -737,6 +746,7 @@ void OutputPaneManager::saveSettings() const
if (OutputPanePlaceHolder *curr = OutputPanePlaceHolder::getCurrent())
heightSetting = curr->nonMaximizedSize();
settings->setValue(QLatin1String("OutputPanePlaceHolder/Height"), heightSetting);
+ settings->setValue(QLatin1String("OutputPanePlaceHolder/CurrentIndex"), currentIndex());
}
void OutputPaneManager::clearPage()
diff --git a/src/plugins/insight/CMakeLists.txt b/src/plugins/insight/CMakeLists.txt
new file mode 100644
index 00000000000..ec262638eef
--- /dev/null
+++ b/src/plugins/insight/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_qtc_plugin(Insight
+ CONDITION TARGET QtCreator::QmlDesigner
+ PLUGIN_DEPENDS
+ QtCreator::Core QtCreator::QtSupport QtCreator::QmlDesigner QtCreator::QmlProjectManager QtCreator::ProjectExplorer
+ DEPENDS
+ QtCreator::Utils
+ Qt6::Core Qt6::CorePrivate Qt6::Widgets
+ Qt6::Qml Qt6::QmlPrivate Qt6::Quick Qt6::QuickWidgets
+ SOURCES
+ insightplugin.cpp insightplugin.h
+ insightmodel.cpp insightmodel.h
+ insightview.cpp insightview.h
+ insightwidget.cpp insightwidget.h
+)
diff --git a/src/plugins/insight/Insight.json.in b/src/plugins/insight/Insight.json.in
new file mode 100644
index 00000000000..0ac25523677
--- /dev/null
+++ b/src/plugins/insight/Insight.json.in
@@ -0,0 +1,21 @@
+{
+ \"Name\" : \"Insight\",
+ \"Version\" : \"$$QTCREATOR_VERSION\",
+ \"CompatVersion\" : \"$$QTCREATOR_COMPAT_VERSION\",
+ \"Revision\" : \"$$QTC_PLUGIN_REVISION\",
+ \"Vendor\" : \"The Qt Company Ltd\",
+ \"Copyright\" : \"(C) $$QTCREATOR_COPYRIGHT_YEAR The Qt Company Ltd\",
+ \"License\" : [ \"Commercial Usage\",
+ \"\",
+ \"Licensees holding valid Qt Commercial licenses may use this plugin in accordance with the Qt 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.\",
+ \"\",
+ \"GNU General Public License Usage\",
+ \"\",
+ \"Alternatively, this plugin 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 plugin. 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.\"
+ ],
+ \"Category\" : \"Qt Quick\",
+ \"Description\" : \"Qt Insight Support for Design Studio.\",
+ \"DisabledByDefault\" : true,
+ \"Url\" : \"http://www.qt.io\",
+ $$dependencyList
+}
diff --git a/src/plugins/insight/insightmodel.cpp b/src/plugins/insight/insightmodel.cpp
new file mode 100644
index 00000000000..728c469a58f
--- /dev/null
+++ b/src/plugins/insight/insightmodel.cpp
@@ -0,0 +1,860 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "insightmodel.h"
+#include "insightview.h"
+
+#include <auxiliarydataproperties.h>
+#include <externaldependenciesinterface.h>
+#include <plaintexteditmodifier.h>
+#include <rewriterview.h>
+#include <signalhandlerproperty.h>
+#include <qmldesignerplugin.h>
+
+#include <projectexplorer/project.h>
+#include <projectexplorer/projectmanager.h>
+#include <projectexplorer/projecttree.h>
+#include <projectexplorer/session.h>
+#include <projectexplorer/target.h>
+
+#include <qtsupport/qtkitinformation.h>
+
+#include <utils/filepath.h>
+#include <utils/qtcassert.h>
+
+#include <QAbstractListModel>
+#include <QApplication>
+#include <QDebug>
+
+namespace QmlDesigner {
+
+namespace {
+
+constexpr QStringView insightConfFile{u"qtinsight.conf"};
+constexpr QStringView qtdsConfFile{u"qtdsinsight.conf"};
+constexpr QStringView dataFolder{u"qtinsight"};
+
+constexpr QStringView insightImport{u"QtInsightTracker"};
+constexpr QStringView signalHandler{u"Component.onCompleted"};
+constexpr QStringView regExp{u"InsightTracker\\.enabled\\s*=\\s*(true|false)"};
+
+constexpr std::string_view defaultColor{"#000000"};
+constexpr std::string_view predefinedStr{"predefined"};
+constexpr std::string_view customStr{"custom"};
+
+constexpr QStringView defaultCategoryName{u"New Category"};
+
+// JSON attribut names
+constexpr std::string_view categoriesAtt{"categories"};
+constexpr std::string_view tokenAtt{"token"};
+constexpr std::string_view syncAtt{"sync"};
+constexpr std::string_view intervalAtt{"interval"};
+constexpr std::string_view secondsAtt{"seconds"};
+constexpr std::string_view minutesAtt{"minutes"};
+
+constexpr std::string_view nameAtt{"name"};
+constexpr std::string_view typeAtt{"type"};
+constexpr std::string_view colorAtt{"color"};
+
+QByteArray fileToByteArray(const QString &filePath)
+{
+ QFile file(filePath);
+
+ if (!file.exists()) {
+ qWarning() << "File does not exist" << filePath;
+ return {};
+ }
+
+ if (!file.open(QIODevice::ReadOnly)) {
+ qWarning() << "Could not open" << filePath << file.error() << file.errorString();
+ return {};
+ }
+
+ return file.readAll();
+}
+
+QString fileToString(const QString &filePath)
+{
+ return QString::fromUtf8(fileToByteArray(filePath));
+}
+
+bool isNodeEnabled(const ModelNode &node)
+{
+ SignalHandlerProperty property = node.signalHandlerProperty(signalHandler.toUtf8());
+
+ QString src = property.source();
+ const QRegularExpression re(regExp.toString());
+ QRegularExpressionMatch match = re.match(src);
+
+ if (match.hasMatch() && !match.capturedView(1).isEmpty())
+ return QVariant(match.captured(1)).toBool();
+
+ return false;
+}
+
+void setNodeEnabled(const ModelNode &node, bool value)
+{
+ const QString valueAsStr = QVariant(value).toString();
+
+ if (node.hasSignalHandlerProperty(signalHandler.toUtf8())) {
+ SignalHandlerProperty property = node.signalHandlerProperty(signalHandler.toUtf8());
+
+ QString src = property.source();
+ const QRegularExpression re(regExp.toString());
+ QRegularExpressionMatch match = re.match(src);
+
+ if (match.hasMatch() && !match.capturedView(1).isEmpty())
+ src.replace(match.capturedStart(1), match.capturedLength(1), valueAsStr);
+
+ property.setSource(src);
+ } else {
+ SignalHandlerProperty property = node.signalHandlerProperty(signalHandler.toUtf8());
+ property.setSource("InsightTracker.enabled = " + valueAsStr);
+ }
+}
+
+json readJSON(const QString &filePath)
+{
+ const QByteArray data = fileToByteArray(filePath);
+ if (data.isEmpty()) {
+ qWarning() << "File is empty" << filePath;
+ return {};
+ }
+
+ json document;
+
+ try {
+ document = json::parse(data.data());
+ } catch (json::parse_error &e) {
+ qWarning() << "JSON parse error" << e.what();
+ return {};
+ }
+
+ return document;
+}
+
+bool writeJSON(const QString &filePath, const json &document)
+{
+ QFile file(filePath);
+
+ if (!file.open(QIODevice::WriteOnly)) {
+ qWarning() << "Could not open file" << filePath << file.error() << file.errorString();
+ return false;
+ }
+
+ auto result = file.write(document.dump(4).c_str());
+
+ if (result == -1)
+ qWarning() << "Could not write file" << filePath << file.error() << file.errorString();
+
+ file.close();
+
+ return true;
+}
+
+json createCategory(std::string_view name,
+ std::string_view type = customStr,
+ std::string_view color = defaultColor)
+{
+ return json::object({{nameAtt, name}, {typeAtt, type}, {colorAtt, color}});
+}
+
+// Checks if a is fully, partially or not at all contained in b.
+Qt::CheckState checkState(const std::vector<std::string> &a, const std::vector<std::string> &b)
+{
+ unsigned count = 0;
+ std::for_each(a.begin(), a.end(), [&](const std::string &s) {
+ if (std::find(b.begin(), b.end(), s) != b.end())
+ ++count;
+ });
+
+ if (count == 0)
+ return Qt::Unchecked;
+ else if (count == a.size())
+ return Qt::Checked;
+
+ return Qt::PartiallyChecked;
+}
+
+struct ModelBuilder
+{
+ ModelBuilder(const QString &filePath, ExternalDependenciesInterface &externalDependencies)
+ {
+ const QString fileContent = fileToString(filePath);
+ if (fileContent.isEmpty()) {
+ qWarning() << "File is empty" << filePath;
+ return;
+ }
+
+ document = std::make_unique<QTextDocument>(fileContent);
+ modifier = std::make_unique<NotIndentingTextEditModifier>(document.get(),
+ QTextCursor{document.get()});
+
+ rewriter = std::make_unique<RewriterView>(externalDependencies, RewriterView::Amend);
+ rewriter->setCheckSemanticErrors(false);
+ rewriter->setCheckLinkErrors(false);
+ rewriter->setTextModifier(modifier.get());
+
+ model = QmlDesigner::Model::create("QtQuick.Item", 2, 1);
+ model->setRewriterView(rewriter.get());
+ }
+
+ std::unique_ptr<QTextDocument> document;
+ std::unique_ptr<NotIndentingTextEditModifier> modifier;
+ std::unique_ptr<RewriterView> rewriter;
+ ModelPointer model;
+};
+
+} // namespace
+
+InsightModel::InsightModel(InsightView *view, ExternalDependenciesInterface &externalDependencies)
+ : m_insightView(view)
+ , m_externalDependencies(externalDependencies)
+ , m_fileSystemWatcher(new Utils::FileSystemWatcher(this))
+{
+ QObject::connect(ProjectExplorer::ProjectManager::instance(),
+ &ProjectExplorer::ProjectManager::startupProjectChanged,
+ this,
+ [&](ProjectExplorer::Project *project) {
+ if (project)
+ m_initialized = false;
+ });
+
+ QObject::connect(m_fileSystemWatcher,
+ &Utils::FileSystemWatcher::fileChanged,
+ this,
+ &InsightModel::handleFileChange);
+}
+
+int InsightModel::rowCount(const QModelIndex &) const
+{
+ return m_qtdsConfig.empty() ? 0 : m_qtdsConfig.size();
+}
+
+QVariant InsightModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid() || index.row() >= rowCount() || m_qtdsConfig.empty())
+ return QVariant();
+
+ json::json_pointer ptr;
+ ptr.push_back(std::to_string(index.row()));
+
+ if (!m_qtdsConfig.contains(ptr))
+ return QVariant();
+
+ auto element = m_qtdsConfig[ptr];
+
+ switch (role) {
+ case CategoryName:
+ return QString::fromStdString(element.value(nameAtt, ""));
+ case CategoryColor:
+ return QString::fromStdString(element.value(colorAtt, ""));
+ case CategoryType:
+ return QString::fromStdString(element.value(typeAtt, ""));
+ case CategoryActive: {
+ auto categories = activeCategories();
+ auto category = element.value(nameAtt, "");
+ return std::find(std::begin(categories), std::end(categories), category)
+ != std::end(categories);
+ }
+ default:
+ return QVariant();
+ }
+}
+
+QHash<int, QByteArray> InsightModel::roleNames() const
+{
+ static QHash<int, QByteArray> roleNames{{CategoryName, "categoryName"},
+ {CategoryColor, "categoryColor"},
+ {CategoryType, "categoryType"},
+ {CategoryActive, "categoryActive"}};
+ return roleNames;
+}
+
+void InsightModel::setup()
+{
+ if (m_initialized)
+ return;
+
+ const QString projectUrl = m_externalDependencies.projectUrl().toLocalFile();
+
+ m_mainQmlInfo = QFileInfo(projectUrl + "/main.qml");
+ m_configInfo = QFileInfo(projectUrl + "/" + insightConfFile);
+ m_qtdsConfigInfo = QFileInfo(projectUrl + "/" + qtdsConfFile);
+
+ parseMainQml();
+ parseDefaultConfig();
+ parseConfig();
+ parseQtdsConfig();
+
+ beginResetModel();
+
+ if (m_qtdsConfig.empty())
+ createQtdsConfig();
+ else
+ updateQtdsConfig();
+
+ endResetModel();
+
+ updateCheckState();
+
+ if (m_enabled) {
+ // Flush config files and start listening to modifications
+ writeJSON(m_configInfo.absoluteFilePath(), m_config);
+ writeJSON(m_qtdsConfigInfo.absoluteFilePath(), m_qtdsConfig);
+ }
+
+ m_fileSystemWatcher->addFile(m_mainQmlInfo.absoluteFilePath(),
+ Utils::FileSystemWatcher::WatchModifiedDate);
+ m_fileSystemWatcher->addFile(m_configInfo.absoluteFilePath(),
+ Utils::FileSystemWatcher::WatchModifiedDate);
+ m_fileSystemWatcher->addFile(m_qtdsConfigInfo.absoluteFilePath(),
+ Utils::FileSystemWatcher::WatchModifiedDate);
+
+ m_initialized = true;
+}
+
+void InsightModel::addCategory()
+{
+ int counter = 0;
+ QString newCategory = defaultCategoryName.toString();
+
+ while (hasCategory(newCategory)) {
+ ++counter;
+ newCategory = QString(QStringLiteral("%1%2")).arg(defaultCategoryName).arg(counter);
+ }
+
+ json tmp = m_qtdsConfig;
+ tmp.push_back(createCategory(newCategory.toStdString()));
+ writeJSON(m_qtdsConfigInfo.absoluteFilePath(), tmp);
+}
+
+void InsightModel::removeCateogry(int idx)
+{
+ json::json_pointer ptr;
+ ptr.push_back(std::to_string(idx));
+ ptr.push_back(std::string(nameAtt));
+
+ // Check if category is active and remove it there as well
+ auto active = activeCategories();
+ auto category = m_qtdsConfig.contains(ptr) ? m_qtdsConfig[ptr].get<std::string>() : "";
+ auto it = std::find(std::begin(active), std::end(active), category);
+ if (it != std::end(active)) {
+ active.erase(it);
+
+ json tmp = m_config;
+ tmp[categoriesAtt] = active;
+ writeJSON(m_configInfo.absoluteFilePath(), tmp);
+ }
+
+ json tmp = m_qtdsConfig;
+ tmp.erase(idx);
+ writeJSON(m_qtdsConfigInfo.absoluteFilePath(), tmp);
+}
+
+bool InsightModel::renameCategory(int idx, const QString &name)
+{
+ if (hasCategory(name))
+ return false;
+
+ json::json_pointer ptr;
+ ptr.push_back(std::to_string(idx));
+ ptr.push_back(std::string(nameAtt));
+
+ // Check if category is active and rename it there as well
+ auto active = activeCategories();
+ auto category = m_qtdsConfig.contains(ptr) ? m_qtdsConfig[ptr].get<std::string>() : "";
+ auto it = std::find(std::begin(active), std::end(active), category);
+ if (it != std::end(active)) {
+ *it = name.toStdString();
+
+ json tmp = m_config;
+ tmp[categoriesAtt] = active;
+ writeJSON(m_configInfo.absoluteFilePath(), tmp);
+ }
+
+ json tmp = m_qtdsConfig;
+ tmp[ptr] = name.toStdString();
+ writeJSON(m_qtdsConfigInfo.absoluteFilePath(), tmp);
+ return true;
+}
+
+void InsightModel::setCategoryActive(int idx, bool value)
+{
+ json::json_pointer ptr;
+ ptr.push_back(std::to_string(idx));
+ ptr.push_back(std::string(nameAtt));
+
+ auto categoryName = m_qtdsConfig.contains(ptr) ? m_qtdsConfig[ptr].get<std::string>() : "";
+ auto categories = activeCategories();
+
+ if (value) { // active = true
+ if (std::find(std::begin(categories), std::end(categories), categoryName)
+ == std::end(categories))
+ categories.push_back(categoryName);
+ } else { // active = false
+ categories.erase(std::remove(categories.begin(), categories.end(), categoryName),
+ categories.end());
+ }
+
+ json tmp = m_config;
+ tmp[categoriesAtt] = categories;
+ writeJSON(m_configInfo.absoluteFilePath(), tmp);
+}
+
+bool InsightModel::enabled() const
+{
+ return m_enabled;
+}
+
+void InsightModel::setEnabled(bool value)
+{
+ if (!m_mainQmlInfo.exists()) {
+ qWarning() << "File does not exist" << m_mainQmlInfo.absoluteFilePath();
+ return;
+ }
+
+ ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(), m_externalDependencies);
+
+ if (!builder.model) {
+ qWarning() << "Could not create model" << m_mainQmlInfo.absoluteFilePath();
+ return;
+ }
+
+ // Add import if it does not exist yet
+ Import import = Import::createLibraryImport(insightImport.toString(), "1.0");
+ if (!builder.model->hasImport(import, true, true) && value) {
+ builder.model->changeImports({import}, {});
+ }
+
+ bool insightEnabled = isNodeEnabled(builder.rewriter->rootModelNode());
+ if (insightEnabled == value)
+ return;
+
+ setNodeEnabled(builder.rewriter->rootModelNode(), value);
+
+ QFile file(m_mainQmlInfo.absoluteFilePath());
+
+ if (!file.open(QIODevice::WriteOnly)) {
+ qWarning() << "Could not open" << m_mainQmlInfo.absoluteFilePath() << file.error()
+ << file.errorString();
+ return;
+ }
+
+ auto result = file.write(builder.rewriter->textModifierContent().toUtf8());
+
+ if (result == -1)
+ qWarning() << "Could not write file" << m_mainQmlInfo.absoluteFilePath() << file.error()
+ << file.errorString();
+
+ // If enabled and config files do not exist yet, write them
+ if (value) {
+ if (!m_configInfo.exists())
+ writeJSON(m_configInfo.absoluteFilePath(), m_config);
+ if (!m_qtdsConfigInfo.exists())
+ writeJSON(m_qtdsConfigInfo.absoluteFilePath(), m_qtdsConfig);
+ }
+
+ m_enabled = value;
+ setAuxiliaryEnabled(m_enabled);
+
+ QmlDesignerPlugin::instance()->viewManager().resetPropertyEditorView();
+}
+
+QString InsightModel::token() const
+{
+ if (m_config.empty())
+ return {};
+
+ return QString::fromStdString(m_config.value(tokenAtt, ""));
+}
+
+void InsightModel::setToken(const QString &value)
+{
+ writeConfigValue(json::json_pointer("/" + std::string(tokenAtt)), value.toStdString());
+}
+
+int InsightModel::minutes() const
+{
+ if (m_config.empty())
+ return {};
+
+ json::json_pointer ptr;
+ ptr.push_back(std::string(syncAtt));
+ ptr.push_back(std::string(intervalAtt));
+ ptr.push_back(std::string(minutesAtt));
+
+ return m_config.value(ptr, 0);
+}
+
+void InsightModel::setMinutes(int value)
+{
+ json::json_pointer ptr;
+ ptr.push_back(std::string(syncAtt));
+ ptr.push_back(std::string(intervalAtt));
+ ptr.push_back(std::string(minutesAtt));
+
+ writeConfigValue(ptr, value);
+}
+
+void InsightModel::selectAllPredefined()
+{
+ selectAll(predefinedCategories(), m_predefinedCheckState);
+}
+
+void InsightModel::selectAllCustom()
+{
+ selectAll(customCategories(), m_customCheckState);
+}
+
+void InsightModel::handleFileChange(const QString &path)
+{
+ if (m_mainQmlInfo.absoluteFilePath() == path)
+ parseMainQml();
+ else if (m_configInfo.absoluteFilePath() == path)
+ parseConfig();
+ else if (m_qtdsConfigInfo.absoluteFilePath() == path) {
+ beginResetModel();
+ parseQtdsConfig();
+ endResetModel();
+ }
+}
+
+void InsightModel::setAuxiliaryEnabled(bool value)
+{
+ ModelNode root = m_insightView->rootModelNode();
+ if (root.isValid())
+ root.setAuxiliaryData(insightEnabledProperty, value);
+}
+
+void InsightModel::setAuxiliaryCategories(const std::vector<std::string> &categories)
+{
+ ModelNode root = m_insightView->rootModelNode();
+ if (root.isValid()) {
+ QStringList c;
+ std::for_each(categories.begin(), categories.end(), [&](const std::string &s) {
+ c.append(QString::fromStdString(s));
+ });
+
+ root.setAuxiliaryData(insightCategoriesProperty, c);
+ }
+}
+
+void InsightModel::hideCursor()
+{
+ if (QApplication::overrideCursor())
+ return;
+
+ QApplication::setOverrideCursor(QCursor(Qt::BlankCursor));
+
+ if (QWidget *w = QApplication::activeWindow())
+ m_lastPos = QCursor::pos(w->screen());
+}
+
+void InsightModel::restoreCursor()
+{
+ if (!QApplication::overrideCursor())
+ return;
+
+ QApplication::restoreOverrideCursor();
+
+ if (QWidget *w = QApplication::activeWindow())
+ QCursor::setPos(w->screen(), m_lastPos);
+}
+
+void InsightModel::holdCursorInPlace()
+{
+ if (!QApplication::overrideCursor())
+ return;
+
+ if (QWidget *w = QApplication::activeWindow())
+ QCursor::setPos(w->screen(), m_lastPos);
+}
+
+int InsightModel::devicePixelRatio()
+{
+ if (QWidget *w = QApplication::activeWindow())
+ return w->devicePixelRatio();
+
+ return 1;
+}
+
+void InsightModel::parseMainQml()
+{
+ ModelBuilder builder(m_mainQmlInfo.absoluteFilePath(), m_externalDependencies);
+
+ if (!builder.model)
+ return;
+
+ Import import = Import::createLibraryImport(insightImport.toString(), "1.0");
+ if (!builder.model->hasImport(import, true, true))
+ return;
+
+ bool insightEnabled = isNodeEnabled(builder.rewriter->rootModelNode());
+
+ if (m_enabled != insightEnabled) {
+ m_enabled = insightEnabled;
+ emit enabledChanged();
+
+ setAuxiliaryEnabled(m_enabled);
+ }
+}
+
+void InsightModel::parseDefaultConfig()
+{
+ // Load default insight config from plugin
+ const ProjectExplorer::Target *target = ProjectExplorer::ProjectTree::currentTarget();
+ if (target) {
+ const QtSupport::QtVersion *qtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
+ m_defaultConfig = readJSON(qtVersion->dataPath().toString() + "/" + dataFolder + "/"
+ + insightConfFile);
+ }
+}
+
+void InsightModel::parseConfig()
+{
+ json target = readJSON(m_configInfo.absoluteFilePath());
+
+ if (target.empty()) {
+ if (m_defaultConfig.empty()) {
+ qWarning() << "Could not find default or user insight config.";
+ return;
+ }
+ // Copy default config
+ m_config = m_defaultConfig;
+
+ // Try to overwrite seconds entry in config as it is set in the default config to 60,
+ // but currently not supported in QtDS.
+ json::json_pointer ptr;
+ ptr.push_back(std::string(syncAtt));
+ ptr.push_back(std::string(intervalAtt));
+
+ if (m_config.contains(ptr))
+ m_config[ptr][secondsAtt] = 0;
+ } else {
+ bool resetModel = false;
+
+ if (m_config.empty()) {
+ m_config = target;
+
+ emit tokenChanged();
+ emit minutesChanged();
+ resetModel = true;
+ } else {
+ json patch = json::diff(m_config, target);
+
+ m_config = target;
+ for (auto it : patch) {
+ if (!it.contains("path"))
+ continue;
+
+ json::json_pointer tmp(it["path"].get<std::string>());
+
+ if (tmp.back() == tokenAtt)
+ emit tokenChanged();
+
+ if (tmp.back() == minutesAtt)
+ emit minutesChanged();
+
+ if (!tmp.to_string().compare(1, categoriesAtt.size(), categoriesAtt))
+ resetModel = true;
+ }
+ }
+
+ if (resetModel) {
+ updateCheckState();
+ beginResetModel();
+ endResetModel();
+ }
+ }
+}
+
+void InsightModel::parseQtdsConfig()
+{
+ m_qtdsConfig = readJSON(m_qtdsConfigInfo.absoluteFilePath());
+ updateCheckState();
+ setAuxiliaryCategories(customCategories());
+}
+
+// Create new QtDS Insight configuration
+void InsightModel::createQtdsConfig()
+{
+ json categories = json::array();
+
+ auto active = activeCategories();
+ auto predefined = predefinedCategories();
+
+ std::vector<std::string> custom;
+
+ std::set_difference(std::make_move_iterator(active.begin()),
+ std::make_move_iterator(active.end()),
+ std::make_move_iterator(predefined.begin()),
+ std::make_move_iterator(predefined.end()),
+ std::back_inserter(custom));
+
+ for (const auto &c : predefined)
+ categories.push_back(createCategory(c, predefinedStr));
+
+ for (const auto &c : custom)
+ categories.push_back(createCategory(c));
+
+ m_qtdsConfig = categories;
+}
+
+// Update existing QtDS Insight configuration
+void InsightModel::updateQtdsConfig()
+{
+ auto contains = [&](const json &arr, const std::string &val) {
+ for (auto it : arr) {
+ if (val == it[nameAtt].get<std::string>())
+ return true;
+ }
+ return false;
+ };
+
+ auto active = activeCategories();
+ auto predefined = predefinedCategories();
+ std::vector<std::string> custom;
+
+ std::set_difference(std::make_move_iterator(active.begin()),
+ std::make_move_iterator(active.end()),
+ std::make_move_iterator(predefined.begin()),
+ std::make_move_iterator(predefined.end()),
+ std::back_inserter(custom));
+
+ for (const auto &c : predefined) {
+ if (!contains(m_qtdsConfig, c))
+ m_qtdsConfig.push_back(createCategory(c, predefinedStr));
+ }
+
+ for (const auto &c : custom) {
+ if (!contains(m_qtdsConfig, c))
+ m_qtdsConfig.push_back(createCategory(c));
+ }
+}
+
+void InsightModel::selectAll(const std::vector<std::string> &categories, Qt::CheckState checkState)
+{
+ auto active = activeCategories();
+
+ if (checkState == Qt::Unchecked || checkState == Qt::PartiallyChecked) {
+ // Select all
+ std::for_each(categories.begin(), categories.end(), [&](const std::string &s) {
+ if (std::find(active.begin(), active.end(), s) == active.end())
+ active.push_back(s);
+ });
+ } else {
+ // Unselect all
+ std::vector<std::string> diff;
+
+ std::set_difference(active.begin(),
+ active.end(),
+ categories.begin(),
+ categories.end(),
+ std::inserter(diff, diff.begin()));
+ active = diff;
+ }
+
+ json tmp = m_config;
+ tmp[categoriesAtt] = active;
+ writeJSON(m_configInfo.absoluteFilePath(), tmp);
+}
+
+std::vector<std::string> InsightModel::predefinedCategories() const
+{
+ std::vector<std::string> categories;
+ if (!m_defaultConfig.empty() && m_defaultConfig.contains(categoriesAtt))
+ categories = m_defaultConfig[categoriesAtt].get<std::vector<std::string>>();
+
+ std::sort(categories.begin(), categories.end());
+ categories.erase(std::unique(categories.begin(), categories.end()), categories.end());
+
+ return categories;
+}
+
+std::vector<std::string> InsightModel::activeCategories() const
+{
+ std::vector<std::string> categories;
+ if (!m_config.empty() && m_config.contains(categoriesAtt))
+ categories = m_config[categoriesAtt].get<std::vector<std::string>>();
+
+ std::sort(categories.begin(), categories.end());
+ categories.erase(std::unique(categories.begin(), categories.end()), categories.end());
+
+ return categories;
+}
+
+std::vector<std::string> InsightModel::customCategories() const
+{
+ std::vector<std::string> categories;
+ if (!m_qtdsConfig.empty()) {
+ for (auto it : m_qtdsConfig) {
+ if (it.contains(typeAtt) && it.contains(nameAtt)
+ && it[typeAtt].get<std::string>() == customStr)
+ categories.push_back(it[nameAtt].get<std::string>());
+ }
+ }
+
+ std::sort(categories.begin(), categories.end());
+ categories.erase(std::unique(categories.begin(), categories.end()), categories.end());
+
+ return categories;
+}
+
+std::vector<std::string> InsightModel::categories() const
+{
+ std::vector<std::string> categories;
+ if (!m_qtdsConfig.empty()) {
+ for (auto it : m_qtdsConfig) {
+ if (it.contains(nameAtt))
+ categories.push_back(it[nameAtt].get<std::string>());
+ }
+ }
+
+ return categories;
+}
+
+bool InsightModel::hasCategory(const QString &name) const
+{
+ auto c = categories();
+ return std::find(std::begin(c), std::end(c), name.toStdString()) != std::end(c);
+}
+
+void InsightModel::updateCheckState()
+{
+ auto active = activeCategories();
+ auto predefined = predefinedCategories();
+ auto custom = customCategories();
+
+ Qt::CheckState predefinedCheckState = checkState(predefined, active);
+ Qt::CheckState customCheckState = checkState(custom, active);
+
+ if (m_predefinedCheckState != predefinedCheckState) {
+ m_predefinedCheckState = predefinedCheckState;
+ emit predefinedSelectStateChanged();
+ }
+
+ if (m_customCheckState != customCheckState) {
+ m_customCheckState = customCheckState;
+ emit customSelectStateChanged();
+ }
+}
+
+template<typename T>
+void InsightModel::writeConfigValue(const json::json_pointer &ptr, T value)
+{
+ T configValue{};
+
+ if (!m_config.empty())
+ configValue = m_config.value(ptr, configValue);
+
+ if (configValue == value)
+ return;
+
+ json tmp = m_config;
+ tmp[ptr] = value;
+
+ writeJSON(m_configInfo.absoluteFilePath(), tmp);
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/insight/insightmodel.h b/src/plugins/insight/insightmodel.h
new file mode 100644
index 00000000000..b21d7e36205
--- /dev/null
+++ b/src/plugins/insight/insightmodel.h
@@ -0,0 +1,132 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <model.h>
+
+#include <QAbstractListModel>
+#include <QFileInfo>
+#include <QPointer>
+#include <QPoint>
+
+#include <utils/filesystemwatcher.h>
+
+#include <3rdparty/json/json.hpp>
+
+namespace QmlDesigner {
+
+class InsightView;
+
+typedef nlohmann::json json;
+
+class InsightModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool enabled READ enabled NOTIFY enabledChanged)
+ Q_PROPERTY(QString token READ token NOTIFY tokenChanged)
+ Q_PROPERTY(int minutes READ minutes NOTIFY minutesChanged)
+ Q_PROPERTY(Qt::CheckState predefinedSelectState MEMBER m_predefinedCheckState NOTIFY
+ predefinedSelectStateChanged)
+ Q_PROPERTY(Qt::CheckState customSelectState MEMBER m_customCheckState NOTIFY customSelectStateChanged)
+
+ enum {
+ CategoryName = Qt::DisplayRole,
+ CategoryColor = Qt::UserRole,
+ CategoryType,
+ CategoryActive
+ };
+
+public:
+ InsightModel(InsightView *view, class ExternalDependenciesInterface &externalDependencies);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ QHash<int, QByteArray> roleNames() const override;
+
+ void setup();
+
+ Q_INVOKABLE void addCategory();
+ Q_INVOKABLE void removeCateogry(int idx);
+ Q_INVOKABLE bool renameCategory(int idx, const QString &name);
+
+ Q_INVOKABLE void setCategoryActive(int idx, bool value);
+
+ bool enabled() const;
+ Q_INVOKABLE void setEnabled(bool value);
+
+ QString token() const;
+ Q_INVOKABLE void setToken(const QString &value);
+
+ int minutes() const;
+ Q_INVOKABLE void setMinutes(int value);
+
+ Q_INVOKABLE void selectAllPredefined();
+ Q_INVOKABLE void selectAllCustom();
+
+ void handleFileChange(const QString &path);
+
+ void setAuxiliaryEnabled(bool value);
+ void setAuxiliaryCategories(const std::vector<std::string> &categories);
+
+ Q_INVOKABLE void hideCursor();
+ Q_INVOKABLE void restoreCursor();
+ Q_INVOKABLE void holdCursorInPlace();
+
+ Q_INVOKABLE int devicePixelRatio();
+
+signals:
+ void enabledChanged();
+ void tokenChanged();
+ void minutesChanged();
+
+ void predefinedSelectStateChanged();
+ void customSelectStateChanged();
+
+private:
+ void parseMainQml();
+ void parseDefaultConfig();
+ void parseConfig();
+ void parseQtdsConfig();
+
+ void createQtdsConfig();
+ void updateQtdsConfig();
+
+ void selectAll(const std::vector<std::string> &categories, Qt::CheckState checkState);
+
+ std::vector<std::string> predefinedCategories() const;
+ std::vector<std::string> activeCategories() const;
+ std::vector<std::string> customCategories() const;
+ std::vector<std::string> categories() const;
+
+ bool hasCategory(const QString &name) const;
+ void updateCheckState();
+
+ template<typename T>
+ void writeConfigValue(const json::json_pointer &ptr, T value);
+
+private:
+ QPointer<InsightView> m_insightView;
+ ExternalDependenciesInterface &m_externalDependencies;
+
+ Utils::FileSystemWatcher *m_fileSystemWatcher;
+
+ bool m_enabled = false;
+ bool m_initialized = false;
+
+ QFileInfo m_mainQmlInfo;
+ QFileInfo m_configInfo;
+ QFileInfo m_qtdsConfigInfo;
+
+ json m_defaultConfig;
+ json m_config;
+ json m_qtdsConfig;
+
+ Qt::CheckState m_predefinedCheckState;
+ Qt::CheckState m_customCheckState;
+
+ QPoint m_lastPos;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/insight/insightplugin.cpp b/src/plugins/insight/insightplugin.cpp
new file mode 100644
index 00000000000..4ad151e80da
--- /dev/null
+++ b/src/plugins/insight/insightplugin.cpp
@@ -0,0 +1,31 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "insightplugin.h"
+
+#include "insightview.h"
+
+#include <qmldesigner/dynamiclicensecheck.h>
+#include <qmldesignerplugin.h>
+
+namespace QmlDesigner {
+
+InsightPlugin::InsightPlugin() = default;
+InsightPlugin::~InsightPlugin() = default;
+
+bool InsightPlugin::initialize(const QStringList & /*arguments*/, QString * /*errorMessage*/)
+{
+ return true;
+}
+
+bool InsightPlugin::delayedInitialize()
+{
+ auto *designerPlugin = QmlDesignerPlugin::instance();
+ auto &viewManager = designerPlugin->viewManager();
+ viewManager.registerView(std::make_unique<InsightView>(
+ QmlDesignerPlugin::externalDependenciesForPluginInitializationOnly()));
+
+ return true;
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/insight/insightplugin.h b/src/plugins/insight/insightplugin.h
new file mode 100644
index 00000000000..c090e09bb76
--- /dev/null
+++ b/src/plugins/insight/insightplugin.h
@@ -0,0 +1,22 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <extensionsystem/iplugin.h>
+
+namespace QmlDesigner {
+
+class InsightPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QtCreatorPlugin" FILE "Insight.json")
+public:
+ InsightPlugin();
+ ~InsightPlugin();
+
+ bool initialize(const QStringList &arguments, QString *errorMessage);
+ bool delayedInitialize();
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/insight/insightview.cpp b/src/plugins/insight/insightview.cpp
new file mode 100644
index 00000000000..a06cb5e8736
--- /dev/null
+++ b/src/plugins/insight/insightview.cpp
@@ -0,0 +1,57 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "insightview.h"
+#include "insightmodel.h"
+#include "insightwidget.h"
+
+#include <utils/qtcassert.h>
+
+#include <QDebug>
+#include <QFile>
+#include <QFileInfo>
+#include <QTextDocument>
+
+namespace QmlDesigner {
+
+InsightView::InsightView(ExternalDependenciesInterface &externalDependencies)
+ : AbstractView(externalDependencies)
+ , m_insightModel(std::make_unique<InsightModel>(this, externalDependencies))
+{
+ Q_ASSERT(m_insightModel);
+}
+
+InsightView::~InsightView()
+{
+ delete m_insightWidget.data();
+}
+
+void InsightView::modelAttached(Model *model)
+{
+ if (model == AbstractView::model())
+ return;
+
+ QTC_ASSERT(model, return );
+ AbstractView::modelAttached(model);
+
+ m_insightModel->setup();
+}
+
+WidgetInfo InsightView::widgetInfo()
+{
+ if (!m_insightWidget)
+ m_insightWidget = new InsightWidget(this, m_insightModel.get());
+
+ return createWidgetInfo(m_insightWidget.data(),
+ "QtInsight",
+ WidgetInfo::RightPane,
+ 0,
+ tr("Qt Insight"));
+}
+
+bool InsightView::hasWidget() const
+{
+ return true;
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/insight/insightview.h b/src/plugins/insight/insightview.h
new file mode 100644
index 00000000000..e39f34239c2
--- /dev/null
+++ b/src/plugins/insight/insightview.h
@@ -0,0 +1,40 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <abstractview.h>
+
+#include <QJsonArray>
+#include <QJsonDocument>
+#include <QJsonObject>
+
+#include <3rdparty/json/json.hpp>
+
+namespace QmlDesigner {
+
+class InsightModel;
+class InsightWidget;
+
+class InsightView : public AbstractView
+{
+ Q_OBJECT
+
+public:
+ explicit InsightView(ExternalDependenciesInterface &externalDependencies);
+ ~InsightView() override;
+
+ // AbstractView
+ void modelAttached(Model *model) override;
+
+ WidgetInfo widgetInfo() override;
+ bool hasWidget() const override;
+
+public slots:
+
+private:
+ std::unique_ptr<InsightModel> m_insightModel;
+ QPointer<InsightWidget> m_insightWidget;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/insight/insightwidget.cpp b/src/plugins/insight/insightwidget.cpp
new file mode 100644
index 00000000000..aaf152bea31
--- /dev/null
+++ b/src/plugins/insight/insightwidget.cpp
@@ -0,0 +1,123 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "insightwidget.h"
+#include "insightmodel.h"
+#include "insightview.h"
+
+#include <componentcore/theme.h>
+#include <designersettings.h>
+#include <qmldesignerconstants.h>
+#include <qmldesignerplugin.h>
+
+#include <invalidqmlsourceexception.h>
+
+#include <coreplugin/messagebox.h>
+#include <coreplugin/icore.h>
+
+#include <utils/qtcassert.h>
+#include <utils/stylehelper.h>
+
+#include <QApplication>
+#include <QFileInfo>
+#include <QShortcut>
+#include <QBoxLayout>
+#include <QKeySequence>
+
+#include <QQmlContext>
+#include <QQmlEngine>
+#include <QQuickItem>
+
+enum {
+ debug = false
+};
+
+namespace QmlDesigner {
+
+static QString propertyEditorResourcesPath()
+{
+#ifdef SHARE_QML_PATH
+ if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
+ return QLatin1String(SHARE_QML_PATH) + "/propertyEditorQmlSources";
+#endif
+ return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString();
+}
+
+InsightWidget::InsightWidget(InsightView *insightView, InsightModel *insightModel)
+ : m_insightView(insightView)
+ , m_qmlSourceUpdateShortcut(nullptr)
+{
+ engine()->addImportPath(qmlSourcesPath());
+ engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
+ engine()->addImportPath(qmlSourcesPath() + "/imports");
+
+ m_qmlSourceUpdateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F11), this);
+ connect(m_qmlSourceUpdateShortcut,
+ &QShortcut::activated,
+ this,
+ &InsightWidget::reloadQmlSource);
+
+ setResizeMode(QQuickWidget::SizeRootObjectToView);
+ setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+
+ rootContext()->setContextProperties({{"insightModel", QVariant::fromValue(insightModel)}});
+
+ Theme::setupTheme(engine());
+
+ setWindowTitle(tr("Qt Insight", "Title of the widget"));
+ setMinimumWidth(195);
+ setMinimumHeight(195);
+
+ // init the first load of the QML UI elements
+ reloadQmlSource();
+}
+
+InsightWidget::~InsightWidget() = default;
+
+QString InsightWidget::qmlSourcesPath()
+{
+#ifdef SHARE_QML_PATH
+ if (qEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
+ return QLatin1String(SHARE_QML_PATH) + "/insight";
+#endif
+ return Core::ICore::resourcePath("qmldesigner/insight").toString();
+}
+
+void InsightWidget::showEvent(QShowEvent *event)
+{
+ QQuickWidget::showEvent(event);
+ update();
+}
+
+void InsightWidget::focusOutEvent(QFocusEvent *focusEvent)
+{
+ QmlDesignerPlugin::emitUsageStatisticsTime(Constants::EVENT_INSIGHT_TIME, m_usageTimer.elapsed());
+ QQuickWidget::focusOutEvent(focusEvent);
+}
+
+void InsightWidget::focusInEvent(QFocusEvent *focusEvent)
+{
+ m_usageTimer.restart();
+ QQuickWidget::focusInEvent(focusEvent);
+}
+
+void InsightWidget::reloadQmlSource()
+{
+ QString statesListQmlFilePath = qmlSourcesPath() + QStringLiteral("/Main.qml");
+ QTC_ASSERT(QFileInfo::exists(statesListQmlFilePath), return );
+ engine()->clearComponentCache();
+ setSource(QUrl::fromLocalFile(statesListQmlFilePath));
+
+ if (!rootObject()) {
+ QString errorString;
+ for (const QQmlError &error : errors())
+ errorString += "\n" + error.toString();
+
+ Core::AsynchronousMessageBox::warning(tr("Cannot Create QtQuick View"),
+ tr("InsightWidget: %1 cannot be created.%2")
+ .arg(qmlSourcesPath(), errorString));
+ return;
+ }
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/insight/insightwidget.h b/src/plugins/insight/insightwidget.h
new file mode 100644
index 00000000000..aba18f81969
--- /dev/null
+++ b/src/plugins/insight/insightwidget.h
@@ -0,0 +1,45 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <QElapsedTimer>
+#include <QPointer>
+#include <QQmlPropertyMap>
+#include <QQuickWidget>
+
+QT_BEGIN_NAMESPACE
+class QShortcut;
+QT_END_NAMESPACE
+
+namespace QmlDesigner {
+
+class NodeInstanceView;
+class InsightModel;
+class InsightView;
+
+class InsightWidget : public QQuickWidget
+{
+ Q_OBJECT
+
+public:
+ InsightWidget(InsightView *insightView, InsightModel *insightModel);
+ ~InsightWidget() override;
+
+ static QString qmlSourcesPath();
+
+protected:
+ void showEvent(QShowEvent *) override;
+ void focusOutEvent(QFocusEvent *focusEvent) override;
+ void focusInEvent(QFocusEvent *focusEvent) override;
+
+private:
+ void reloadQmlSource();
+
+private:
+ QPointer<InsightView> m_insightView;
+ QShortcut *m_qmlSourceUpdateShortcut;
+ QElapsedTimer m_usageTimer;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/mcusupport/CMakeLists.txt b/src/plugins/mcusupport/CMakeLists.txt
index 778f0a70394..81fadd4ddfb 100644
--- a/src/plugins/mcusupport/CMakeLists.txt
+++ b/src/plugins/mcusupport/CMakeLists.txt
@@ -23,6 +23,7 @@ add_qtc_plugin(McuSupport
mcuhelpers.cpp mcuhelpers.h
settingshandler.cpp settingshandler.h
mcuqmlprojectnode.cpp mcuqmlprojectnode.h
+ mcubuildstep.cpp mcubuildstep.h
)
add_subdirectory(test)
diff --git a/src/plugins/mcusupport/mcubuildstep.cpp b/src/plugins/mcusupport/mcubuildstep.cpp
new file mode 100644
index 00000000000..a26e8ed0d1e
--- /dev/null
+++ b/src/plugins/mcusupport/mcubuildstep.cpp
@@ -0,0 +1,171 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "mcubuildstep.h"
+#include "mcukitmanager.h"
+#include "mculegacyconstants.h"
+#include "mcusupportconstants.h"
+
+#include <cmakeprojectmanager/cmakekitinformation.h>
+
+#include <projectexplorer/buildstep.h>
+#include <projectexplorer/buildsteplist.h>
+#include <projectexplorer/buildsystem.h>
+#include <projectexplorer/deployconfiguration.h>
+#include <projectexplorer/kit.h>
+#include <projectexplorer/kitmanager.h>
+#include <projectexplorer/target.h>
+#include <projectexplorer/task.h>
+#include <projectexplorer/taskhub.h>
+
+#include <qmlprojectmanager/qmlprojectmanagertr.h>
+
+#include <qtsupport/qtsupportconstants.h>
+
+#include <utils/aspects.h>
+#include <utils/filepath.h>
+
+#include <QVersionNumber>
+
+namespace McuSupport::Internal {
+
+const Utils::Id DeployMcuProcessStep::id = "QmlProject.Mcu.DeployStep";
+
+void DeployMcuProcessStep::showError(const QString &text)
+{
+ ProjectExplorer::DeploymentTask task(ProjectExplorer::Task::Error, text);
+ ProjectExplorer::TaskHub::addTask(task);
+}
+
+DeployMcuProcessStep::DeployMcuProcessStep(ProjectExplorer::BuildStepList *bc, Utils::Id id)
+ : AbstractProcessStep(bc, id)
+ , m_tmpDir()
+{
+ if (!buildSystem()) {
+ showError(QmlProjectManager::Tr::tr("Failed to find valid build system"));
+ return;
+ }
+
+ if (!m_tmpDir.isValid()) {
+ showError(QmlProjectManager::Tr::tr("Failed to create valid build directory"));
+ return;
+ }
+
+ ProjectExplorer::Kit *kit = MCUBuildStepFactory::findMostRecentQulKit();
+ if (!kit)
+ return;
+
+ QString root = findKitInformation(kit, Internal::Legacy::Constants::QUL_CMAKE_VAR);
+ auto rootPath = Utils::FilePath::fromString(root);
+
+ auto cmd = addAspect<Utils::StringAspect>();
+ cmd->setSettingsKey("QmlProject.Mcu.ProcessStep.Command");
+ cmd->setDisplayStyle(Utils::StringAspect::PathChooserDisplay);
+ cmd->setExpectedKind(Utils::PathChooser::Command);
+ cmd->setLabelText(QmlProjectManager::Tr::tr("Command:"));
+ cmd->setFilePath(rootPath.pathAppended("/bin/qmlprojectexporter"));
+
+ const char *importPathConstant = QtSupport::Constants::KIT_QML_IMPORT_PATH;
+ Utils::FilePath projectDir = buildSystem()->projectDirectory();
+ Utils::FilePath qulIncludeDir = Utils::FilePath::fromVariant(kit->value(importPathConstant));
+ QStringList includeDirs {
+ Utils::ProcessArgs::quoteArg(qulIncludeDir.toString()),
+ Utils::ProcessArgs::quoteArg(qulIncludeDir.pathAppended("Timeline").toString())
+ };
+
+ const char *toolChainConstant = Internal::Constants::KIT_MCUTARGET_TOOLCHAIN_KEY;
+ QStringList arguments = {
+ Utils::ProcessArgs::quoteArg(buildSystem()->projectFilePath().toString()),
+ "--platform", findKitInformation(kit, "QUL_PLATFORM"),
+ "--toolchain", kit->value(toolChainConstant).toString(),
+ "--include-dirs", includeDirs.join(","),
+ };
+
+ auto args = addAspect<Utils::StringAspect>();
+ args->setSettingsKey("QmlProject.Mcu.ProcessStep.Arguments");
+ args->setDisplayStyle(Utils::StringAspect::LineEditDisplay);
+ args->setLabelText(QmlProjectManager::Tr::tr("Arguments:"));
+ args->setValue(Utils::ProcessArgs::joinArgs(arguments));
+
+ auto outDir = addAspect<Utils::StringAspect>();
+ outDir->setSettingsKey("QmlProject.Mcu.ProcessStep.BuildDirectory");
+ outDir->setDisplayStyle(Utils::StringAspect::PathChooserDisplay);
+ outDir->setExpectedKind(Utils::PathChooser::Directory);
+ outDir->setLabelText(QmlProjectManager::Tr::tr("Build directory:"));
+ outDir->setPlaceHolderText(m_tmpDir.path());
+
+ setCommandLineProvider([this, cmd, args, outDir]() -> Utils::CommandLine {
+ auto directory = outDir->value();
+ if (directory.isEmpty())
+ directory = m_tmpDir.path();
+
+ Utils::CommandLine cmdLine(cmd->filePath());
+ cmdLine.addArgs(args->value(), Utils::CommandLine::Raw);
+ cmdLine.addArg("--outdir");
+ cmdLine.addArg(directory);
+ return cmdLine;
+ });
+}
+
+QString DeployMcuProcessStep::findKitInformation(ProjectExplorer::Kit *kit, const QString &key)
+{
+ using namespace CMakeProjectManager;
+ const auto config = CMakeConfigurationKitAspect::configuration(kit).toList();
+ const auto keyName = key.toUtf8();
+ for (const CMakeProjectManager::CMakeConfigItem &configItem : config) {
+ if (configItem.key == keyName)
+ return QString::fromUtf8(configItem.value);
+ }
+ return {};
+}
+
+MCUBuildStepFactory::MCUBuildStepFactory()
+ : BuildStepFactory()
+{
+ setDisplayName(QmlProjectManager::Tr::tr("Qt for MCUs Deploy Step"));
+ registerStep<DeployMcuProcessStep>(DeployMcuProcessStep::id);
+}
+
+ProjectExplorer::Kit *MCUBuildStepFactory::findMostRecentQulKit()
+{
+ ProjectExplorer::Kit *mcuKit = nullptr;
+ for (auto availableKit : ProjectExplorer::KitManager::kits()) {
+ if (!availableKit)
+ continue;
+
+ auto qulVersion = McuKitManager::kitQulVersion(availableKit);
+ if (qulVersion.isNull())
+ continue;
+
+ if (!mcuKit)
+ mcuKit = availableKit;
+
+ if (qulVersion > McuKitManager::kitQulVersion(mcuKit))
+ mcuKit = availableKit;
+ }
+ return mcuKit;
+}
+
+void MCUBuildStepFactory::updateDeployStep(ProjectExplorer::Target *target, bool enabled)
+{
+ if (!target)
+ return;
+
+ ProjectExplorer::DeployConfiguration *deployConfiguration = target->activeDeployConfiguration();
+ ProjectExplorer::BuildStepList *stepList = deployConfiguration->stepList();
+ ProjectExplorer::BuildStep *step = stepList->firstStepWithId(DeployMcuProcessStep::id);
+ if (!step && enabled) {
+ if (findMostRecentQulKit()) {
+ stepList->appendStep(DeployMcuProcessStep::id);
+ } else {
+ DeployMcuProcessStep::showError(
+ QmlProjectManager::Tr::tr("Failed to find valid Qt for MCUs kit"));
+ }
+ } else {
+ if (!step)
+ return;
+ step->setEnabled(enabled);
+ }
+}
+
+} // namespace McuSupport::Internal
diff --git a/src/plugins/mcusupport/mcubuildstep.h b/src/plugins/mcusupport/mcubuildstep.h
new file mode 100644
index 00000000000..aebca09eba8
--- /dev/null
+++ b/src/plugins/mcusupport/mcubuildstep.h
@@ -0,0 +1,37 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+#pragma once
+
+#include <projectexplorer/abstractprocessstep.h>
+#include <projectexplorer/buildstep.h>
+#include <projectexplorer/kit.h>
+#include <projectexplorer/project.h>
+
+#include <utils/id.h>
+
+#include <QTemporaryDir>
+
+namespace McuSupport::Internal {
+
+class DeployMcuProcessStep : public ProjectExplorer::AbstractProcessStep
+{
+public:
+ static const Utils::Id id;
+ static void showError(const QString &text);
+
+ DeployMcuProcessStep(ProjectExplorer::BuildStepList *bc, Utils::Id id);
+
+private:
+ QString findKitInformation(ProjectExplorer::Kit *kit, const QString &key);
+ QTemporaryDir m_tmpDir;
+};
+
+class MCUBuildStepFactory : public ProjectExplorer::BuildStepFactory
+{
+public:
+ MCUBuildStepFactory();
+ static ProjectExplorer::Kit *findMostRecentQulKit();
+ static void updateDeployStep(ProjectExplorer::Target *target, bool enabled);
+};
+
+} // namespace McuSupport::Internal
diff --git a/src/plugins/mcusupport/mcusupportplugin.cpp b/src/plugins/mcusupport/mcusupportplugin.cpp
index 8c1d2ea35f6..f2ec2ef69aa 100644
--- a/src/plugins/mcusupport/mcusupportplugin.cpp
+++ b/src/plugins/mcusupport/mcusupportplugin.cpp
@@ -3,6 +3,7 @@
#include "mcusupportplugin.h"
+#include "mcubuildstep.h"
#include "mcukitinformation.h"
#include "mcukitmanager.h"
#include "mcuqmlprojectnode.h"
@@ -98,6 +99,7 @@ public:
McuSupportOptions m_options{m_settingsHandler};
McuSupportOptionsPage optionsPage{m_options, m_settingsHandler};
McuDependenciesKitAspect environmentPathsKitAspect;
+ MCUBuildStepFactory mcuBuildStepFactory;
}; // class McuSupportPluginPrivate
static McuSupportPluginPrivate *dd{nullptr};
@@ -219,4 +221,9 @@ void McuSupportPlugin::askUserAboutRemovingUninstalledTargetsKits()
ICore::infoBar()->addInfo(info);
}
+void McuSupportPlugin::updateDeployStep(ProjectExplorer::Target *target, bool enabled)
+{
+ MCUBuildStepFactory::updateDeployStep(target, enabled);
+}
+
} // namespace McuSupport::Internal
diff --git a/src/plugins/mcusupport/mcusupportplugin.h b/src/plugins/mcusupport/mcusupportplugin.h
index cb27b138464..c092f51d00f 100644
--- a/src/plugins/mcusupport/mcusupportplugin.h
+++ b/src/plugins/mcusupport/mcusupportplugin.h
@@ -7,6 +7,8 @@
#include <extensionsystem/iplugin.h>
+#include <projectexplorer/target.h>
+
namespace McuSupport::Internal {
void printMessage(const QString &message, bool important);
@@ -25,6 +27,8 @@ public:
void askUserAboutMcuSupportKitsSetup();
static void askUserAboutMcuSupportKitsUpgrade(const SettingsHandler::Ptr &settingsHandler);
static void askUserAboutRemovingUninstalledTargetsKits();
+
+ Q_INVOKABLE static void updateDeployStep(ProjectExplorer::Target *target, bool enabled);
};
} // McuSupport::Internal
diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt
index 74fcd863302..fc160cdf528 100644
--- a/src/plugins/qmldesigner/CMakeLists.txt
+++ b/src/plugins/qmldesigner/CMakeLists.txt
@@ -1,16 +1,5 @@
#only if the plugin is requested by qtc_plugin_enabled continue if not stop as early as possible
-add_qtc_plugin(QmlDesigner
- PLUGIN_RECOMMENDS QmlPreview
- CONDITION Qt6_VERSION VERSION_GREATER_EQUAL 6.2.0 AND TARGET Qt::QuickWidgets AND TARGET Qt::Svg
- PROPERTIES COMPILE_WARNING_AS_ERROR ON
- PLUGIN_DEPENDS
- Core ProjectExplorer QmlDesignerBase QmlJSEditor QmakeProjectManager QmlProjectManager
- QtSupport
-)
-qtc_plugin_enabled(_qmlDesignerEnabled QmlDesigner)
-if (NOT _qmlDesignerEnabled)
- return()
-endif()
+
find_package(Qt6 COMPONENTS QmlDomPrivate QmlCompilerPrivate)
@@ -19,13 +8,10 @@ if (APPLE)
set(QmlDesignerPluginInstallPrefix "${IDE_PLUGIN_PATH}/QmlDesigner")
endif()
-
-env_with_default("QDS_USE_PROJECTSTORAGE" ENV_QDS_USE_PROJECTSTORAGE OFF)
-option(USE_PROJECTSTORAGE "Use ProjectStorage" ${ENV_QDS_USE_PROJECTSTORAGE})
-add_feature_info("ProjectStorage" ${USE_PROJECTSTORAGE} "")
+add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,Clang>:-Wno-error=maybe-uninitialized>")
+add_compile_options("$<$<COMPILE_LANG_AND_ID:CXX,GNU>:-Wno-error=maybe-uninitialized>")
add_qtc_library(QmlDesignerUtils STATIC
- PROPERTIES COMPILE_WARNING_AS_ERROR ON
DEPENDS
Qt::Gui Utils Qt::QmlPrivate
DEFINES QMLDESIGNERUTILS_LIBRARY
@@ -44,8 +30,15 @@ add_qtc_library(QmlDesignerUtils STATIC
qmldesignerutils_global.h
)
+extend_qtc_library(QmlDesignerUtils
+ CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR
+ PROPERTIES COMPILE_WARNING_AS_ERROR ON
+)
+
add_qtc_library(QmlDesignerCore STATIC
+ CONDITION Qt6_VERSION VERSION_GREATER_EQUAL 6.4.3 AND TARGET Qt6::QmlPrivate AND TARGET Qt6::QmlDomPrivate AND TARGET Qt6::QmlCompilerPrivate
EXCLUDE_FROM_INSTALL
+ PROPERTIES SKIP_AUTOUIC ON
DEPENDS
Threads::Threads
Qt::CorePrivate
@@ -53,6 +46,9 @@ add_qtc_library(QmlDesignerCore STATIC
Utils
Qt::Widgets
Qt::Qml
+ Qt::QmlPrivate
+ Qt6::QmlDomPrivate
+ Qt6::QmlCompilerPrivate
Core
ProjectExplorer
QmakeProjectManager
@@ -79,25 +75,27 @@ add_qtc_library(QmlDesignerCore STATIC
rewritertransaction.h
)
-extend_qtc_library(QmlDesignerCore
- CONDITION TARGET Qt6::QmlDomPrivate AND TARGET Qt6::QmlCompilerPrivate AND Qt6_VERSION VERSION_GREATER_EQUAL 6.5.0
- DEPENDS Qt6::QmlDomPrivate Qt6::QmlCompilerPrivate
- DEFINES QDS_HAS_QMLDOM
-)
+if(TARGET QmlDesignerCore)
+ env_with_default("QDS_USE_PROJECTSTORAGE" ENV_QDS_USE_PROJECTSTORAGE OFF)
+ option(USE_PROJECTSTORAGE "Use ProjectStorage" ${ENV_QDS_USE_PROJECTSTORAGE})
+ add_feature_info("ProjectStorage" ${USE_PROJECTSTORAGE} "")
+endif()
+
extend_qtc_library(QmlDesignerCore
- CONDITION UNIX AND NOT APPLE
- PUBLIC_DEPENDS rt
+ CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR
+ PROPERTIES COMPILE_WARNING_AS_ERROR ON
)
extend_qtc_library(QmlDesignerCore
- INCLUDES ${CMAKE_CURRENT_BINARY_DIR}
- SOURCES
- ${UI_SOURCES}
- ${UI_FILES}
+ CONDITION Qt6_VERSION VERSION_GREATER_EQUAL 6.5.0 AND Qt6_VERSION VERSION_LESS 6.6.0
+ PUBLIC_DEFINES QDS_BUILD_QMLPARSER
+)
+extend_qtc_library(QmlDesignerCore
+ CONDITION UNIX AND NOT APPLE
+ PUBLIC_DEPENDS rt
)
-set_source_files_properties(${UI_FILES} PROPERTIES SKIP_AUTOUIC ON)
extend_qtc_library(QmlDesignerCore
INCLUDES ${CMAKE_CURRENT_LIST_DIR}/designercore/exceptions
@@ -221,6 +219,7 @@ extend_qtc_library(QmlDesignerCore
metainfo.h
metainforeader.h
model.h
+ modelfwd.h
modelmerger.h
modelnode.h
modelnodepositionstorage.h
@@ -241,6 +240,7 @@ extend_qtc_library(QmlDesignerCore
qmlchangeset.h
qmlconnections.h
qmldesignercorelib_global.h
+ qmldesignercorelib_exports.h
qmlitemnode.h
qmlmodelnodefacade.h
qmlobjectnode.h
@@ -262,6 +262,7 @@ extend_qtc_library(QmlDesignerCore
INCLUDES
${CMAKE_CURRENT_LIST_DIR}/designercore/metainfo
SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/designercore/metainfo
+ DEFINES SHARE_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/../../../share/qtcreator/qmldesigner"
SOURCES
itemlibraryinfo.cpp
metainfo.cpp
@@ -326,8 +327,11 @@ extend_qtc_library(QmlDesignerCore
modelnodepositionrecalculator.cpp
modelnodepositionrecalculator.h
modelnodepositionstorage.cpp
+ modelresourcemanagementinterface.h
modeltotextmerger.cpp
modeltotextmerger.h
+ modelutils.cpp
+ modelutils.h
nodeabstractproperty.cpp
nodelistproperty.cpp
nodeproperty.cpp
@@ -354,6 +358,7 @@ extend_qtc_library(QmlDesignerCore
rewriteactioncompressor.h
rewriterview.cpp
signalhandlerproperty.cpp
+ skipiterator.h
stylesheetmerger.cpp
textmodifier.cpp
texttomodelmerger.cpp
@@ -374,6 +379,7 @@ extend_qtc_library(QmlDesignerCore
extend_qtc_library(QmlDesignerCore
SOURCES_PREFIX designercore/projectstorage
PUBLIC_INCLUDES designercore/projectstorage
+ SOURCES_PROPERTIES SKIP_AUTOMOC ON
SOURCES
commontypecache.h
directorypathcompressor.h
@@ -381,6 +387,7 @@ extend_qtc_library(QmlDesignerCore
filesystem.cpp filesystem.h
filestatus.h
filestatuscache.cpp filestatuscache.h
+ modulescanner.cpp modulescanner.h
nonlockingmutex.h
projectstorageexceptions.cpp projectstorageexceptions.h
projectstorageinterface.h
@@ -409,18 +416,17 @@ extend_qtc_library(QmlDesignerCore
qmldocumentparser.cpp qmldocumentparser.h
)
-file(GLOB PROJECTSTORAGE_EXCLUDED_SOURCES designercore/projectstorage/*.cpp)
-set_property(SOURCE ${PROJECTSTORAGE_EXCLUDED_SOURCES} PROPERTY SKIP_AUTOMOC ON)
-
-extend_qtc_plugin(QmlDesigner
- PUBLIC_DEPENDS
- QmlDesignerUtils
- QmlDesignerBase
- QmlPuppetCommunication
+add_qtc_plugin(QmlDesigner
+ PLUGIN_RECOMMENDS QmlPreview
+ CONDITION Qt6_VERSION VERSION_GREATER_EQUAL 6.4.3 AND TARGET QmlDesignerCore AND TARGET Qt::QuickWidgets AND TARGET Qt::Svg
+ PLUGIN_DEPENDS
+ Core ProjectExplorer QmlDesignerBase QmlJSEditor QmakeProjectManager QmlProjectManager
+ QtSupport
DEPENDS
- QmlDesignerCore
- QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem Sqlite
- Qt::QuickWidgets Qt::CorePrivate Qt::Xml Qt::Svg
+ QmlJS LanguageUtils QmlEditorWidgets AdvancedDockingSystem
+ Qt::QuickWidgets Qt::CorePrivate Qt::Xml Qt::Svg QmlDesignerCore Sqlite
+ PUBLIC_DEPENDS
+ QmlDesignerUtils QmlPuppetCommunication QmlDesignerBase
DEFINES
IDE_LIBRARY_BASENAME=\"${IDE_LIBRARY_BASE_PATH}\"
SHARE_QML_PATH="${CMAKE_CURRENT_SOURCE_DIR}/../../../share/qtcreator/qmldesigner"
@@ -474,6 +480,11 @@ extend_qtc_plugin(QmlDesigner
QMLDESIGNER_PLUGIN_PATH "${QmlDesignerPluginInstallPrefix}"
)
+extend_qtc_plugin(QmlDesigner
+ CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR
+ PROPERTIES COMPILE_WARNING_AS_ERROR ON
+)
+
function(get_and_add_as_subdirectory name repository git_tag build_dir source_dir source_subdir)
# make the configuration in the build dir
file(MAKE_DIRECTORY ${build_dir}/${name})
@@ -521,67 +532,6 @@ if (QTC_STATIC_BUILD AND TARGET QmlDesigner)
extend_qtc_target(QmlDesigner PUBLIC_DEPENDS TextEditor)
endif()
-add_qtc_plugin(assetexporterplugin
- PLUGIN_CLASS AssetExporterPlugin
- CONDITION TARGET QmlDesigner
- DEPENDS Core ProjectExplorer QmlDesigner Utils Qt::Qml Qt::QuickPrivate
- PUBLIC_INCLUDES assetexporterplugin
- SOURCES
- assetexporterplugin/assetexportdialog.h assetexporterplugin/assetexportdialog.cpp assetexporterplugin/assetexportdialog.ui
- assetexporterplugin/assetexporter.h assetexporterplugin/assetexporter.cpp
- assetexporterplugin/assetexporterplugin.h assetexporterplugin/assetexporterplugin.cpp
- assetexporterplugin/assetexporterview.h assetexporterplugin/assetexporterview.cpp
- assetexporterplugin/assetexportpluginconstants.h
- assetexporterplugin/componentexporter.h assetexporterplugin/componentexporter.cpp
- assetexporterplugin/exportnotification.h assetexporterplugin/exportnotification.cpp
- assetexporterplugin/filepathmodel.h assetexporterplugin/filepathmodel.cpp
- assetexporterplugin/dumpers/assetnodedumper.h assetexporterplugin/dumpers/assetnodedumper.cpp
- assetexporterplugin/dumpers/itemnodedumper.h assetexporterplugin/dumpers/itemnodedumper.cpp
- assetexporterplugin/dumpers/nodedumper.h assetexporterplugin/dumpers/nodedumper.cpp
- assetexporterplugin/dumpers/textnodedumper.h assetexporterplugin/dumpers/textnodedumper.cpp
- assetexporterplugin/assetexporterplugin.qrc
- PLUGIN_PATH ${QmlDesignerPluginInstallPrefix}
-)
-
-add_qtc_plugin(componentsplugin
- PLUGIN_CLASS ComponentsPlugin
- CONDITION TARGET QmlDesigner
- DEPENDS Core QmlDesigner Utils Qt::Qml
- DEFINES COMPONENTS_LIBRARY
- SOURCES
- componentsplugin/addtabdesigneraction.cpp componentsplugin/addtabdesigneraction.h
- componentsplugin/addtabtotabviewdialog.cpp componentsplugin/addtabtotabviewdialog.h
- componentsplugin/addtabtotabviewdialog.ui
- componentsplugin/componentsplugin.cpp componentsplugin/componentsplugin.h
- componentsplugin/componentsplugin.qrc
- componentsplugin/entertabdesigneraction.cpp componentsplugin/entertabdesigneraction.h
- componentsplugin/tabviewindexmodel.cpp componentsplugin/tabviewindexmodel.h
- PLUGIN_PATH ${QmlDesignerPluginInstallPrefix}
-)
-
-add_qtc_plugin(qmlpreviewplugin
- PLUGIN_CLASS QmlPreviewWidgetPlugin
- CONDITION TARGET QmlDesigner
- DEPENDS Core ProjectExplorer QmlDesigner Utils Qt::Qml
- SOURCES
- qmlpreviewplugin/qmlpreviewactions.cpp qmlpreviewplugin/qmlpreviewactions.h
- qmlpreviewplugin/qmlpreviewplugin.cpp qmlpreviewplugin/qmlpreviewplugin.h
- qmlpreviewplugin/qmlpreviewplugin.qrc
- PLUGIN_PATH ${QmlDesignerPluginInstallPrefix}
-)
-
-add_qtc_plugin(qtquickplugin
- PLUGIN_CLASS QtQuickPlugin
- CONDITION TARGET QmlDesigner
- DEPENDS Core QmlDesigner Utils Qt::Qml
- DEFINES QTQUICK_LIBRARY
- SOURCES
- qtquickplugin/qtquickplugin.cpp qtquickplugin/qtquickplugin.h
- qtquickplugin/qtquickplugin.qrc
- PLUGIN_PATH ${QmlDesignerPluginInstallPrefix}
-)
-
-add_subdirectory(studioplugin)
extend_qtc_plugin(QmlDesigner
SOURCES_PREFIX components
@@ -643,6 +593,9 @@ extend_qtc_plugin(QmlDesigner
edit3dactions.cpp edit3dactions.h
edit3dvisibilitytogglesmenu.cpp edit3dvisibilitytogglesmenu.h
backgroundcolorselection.cpp backgroundcolorselection.h
+ bakelights.cpp bakelights.h
+ bakelightsdatamodel.cpp bakelightsdatamodel.h
+ bakelightsconnectionmanager.cpp bakelightsconnectionmanager.h
edit3d.qrc
)
@@ -1129,3 +1082,106 @@ extend_qtc_plugin(QmlDesigner
CONDITION TARGET Nanotrace
DEPENDS Nanotrace
)
+
+add_qtc_plugin(assetexporterplugin
+ PLUGIN_CLASS AssetExporterPlugin
+ CONDITION TARGET QmlDesigner
+ PLUGIN_DEPENDS
+ Core ProjectExplorer QmlDesigner
+ DEPENDS Utils Qt::Qml Qt::QuickPrivate
+ PUBLIC_INCLUDES assetexporterplugin
+ PLUGIN_PATH ${QmlDesignerPluginInstallPrefix}
+)
+
+extend_qtc_plugin(assetexporterplugin
+ CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR
+ PROPERTIES COMPILE_WARNING_AS_ERROR ON
+)
+
+extend_qtc_plugin(assetexporterplugin
+ SOURCES_PREFIX assetexporterplugin
+ SOURCES
+ assetexportdialog.h assetexportdialog.cpp assetexportdialog.ui
+ assetexporter.h assetexporter.cpp
+ assetexporterplugin.h assetexporterplugin.cpp
+ assetexporterview.h assetexporterview.cpp
+ assetexportpluginconstants.h
+ componentexporter.h componentexporter.cpp
+ exportnotification.h exportnotification.cpp
+ filepathmodel.h filepathmodel.cpp
+ dumpers/assetnodedumper.h dumpers/assetnodedumper.cpp
+ dumpers/itemnodedumper.h dumpers/itemnodedumper.cpp
+ dumpers/nodedumper.h dumpers/nodedumper.cpp
+ dumpers/textnodedumper.h dumpers/textnodedumper.cpp
+ assetexporterplugin.qrc
+)
+
+add_qtc_plugin(componentsplugin
+ PLUGIN_CLASS ComponentsPlugin
+ CONDITION TARGET QmlDesigner
+ PLUGIN_DEPENDS Core QmlDesigner
+ DEPENDS Utils Qt::Qml
+ DEFINES COMPONENTS_LIBRARY
+
+ PLUGIN_PATH ${QmlDesignerPluginInstallPrefix}
+)
+
+extend_qtc_plugin(componentsplugin
+ CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR
+ PROPERTIES COMPILE_WARNING_AS_ERROR ON
+)
+
+extend_qtc_plugin(componentsplugin
+ SOURCES_PREFIX componentsplugin
+ SOURCES
+ addtabdesigneraction.cpp addtabdesigneraction.h
+ addtabtotabviewdialog.cpp addtabtotabviewdialog.h
+ addtabtotabviewdialog.ui
+ componentsplugin.cpp componentsplugin.h
+ componentsplugin.qrc
+ entertabdesigneraction.cpp entertabdesigneraction.h
+ tabviewindexmodel.cpp tabviewindexmodel.h
+)
+
+add_qtc_plugin(qmlpreviewplugin
+ PLUGIN_CLASS QmlPreviewWidgetPlugin
+ CONDITION TARGET QmlDesigner
+ PLUGIN_DEPENDS Core ProjectExplorer QmlDesigner
+ DEPENDS Utils Qt::Qml
+ PLUGIN_PATH ${QmlDesignerPluginInstallPrefix}
+)
+
+extend_qtc_plugin(qmlpreviewplugin
+ CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR
+ PROPERTIES COMPILE_WARNING_AS_ERROR ON
+)
+
+extend_qtc_plugin(qmlpreviewplugin
+ SOURCES_PREFIX qmlpreviewplugin
+ SOURCES
+ qmlpreviewactions.cpp qmlpreviewactions.h
+ qmlpreviewplugin.cpp qmlpreviewplugin.h
+ qmlpreviewplugin.qrc
+)
+
+add_qtc_plugin(qtquickplugin
+ PLUGIN_CLASS QtQuickPlugin
+ CONDITION TARGET QmlDesigner
+ PLUGIN_DEPENDS Core QmlDesigner
+ DEPENDS Utils Qt::Qml
+ DEFINES QTQUICK_LIBRARY
+ PLUGIN_PATH ${QmlDesignerPluginInstallPrefix}
+)
+
+extend_qtc_plugin(qtquickplugin
+ CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR
+ PROPERTIES COMPILE_WARNING_AS_ERROR ON
+)
+
+extend_qtc_plugin(qtquickplugin
+ SOURCES_PREFIX qtquickplugin
+ SOURCES
+ qtquickplugin.cpp qtquickplugin.h
+ qtquickplugin.qrc
+)
+add_subdirectory(studioplugin)
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
index faf4f1eb549..71cde5f0ba8 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.cpp
@@ -136,7 +136,7 @@ bool AssetsLibraryModel::renameFolder(const QString &folderPath, const QString &
return dir.rename(oldName, newName);
}
-bool AssetsLibraryModel::addNewFolder(const QString &folderPath)
+QString AssetsLibraryModel::addNewFolder(const QString &folderPath)
{
QString iterPath = folderPath;
QDir dir{folderPath};
@@ -147,7 +147,7 @@ bool AssetsLibraryModel::addNewFolder(const QString &folderPath)
dir.setPath(iterPath);
}
- return dir.mkpath(iterPath);
+ return dir.mkpath(iterPath) ? iterPath : "";
}
bool AssetsLibraryModel::urlPathExistsInModel(const QUrl &url) const
diff --git a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h
index f003ef2c541..e37bf8a109a 100644
--- a/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h
+++ b/src/plugins/qmldesigner/components/assetslibrary/assetslibrarymodel.h
@@ -45,7 +45,7 @@ public:
Q_INVOKABLE bool requestDeleteFiles(const QStringList &filePaths);
Q_INVOKABLE void deleteFiles(const QStringList &filePaths, bool dontAskAgain);
Q_INVOKABLE bool renameFolder(const QString &folderPath, const QString &newName);
- Q_INVOKABLE bool addNewFolder(const QString &folderPath);
+ Q_INVOKABLE QString addNewFolder(const QString &folderPath);
Q_INVOKABLE bool deleteFolderRecursively(const QModelIndex &folderIndex);
Q_INVOKABLE bool allFilePathsAreTextures(const QStringList &filePaths) const;
diff --git a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp
index 5112cc3f860..6cd3e814929 100644
--- a/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp
+++ b/src/plugins/qmldesigner/components/bindingeditor/bindingeditor.cpp
@@ -94,7 +94,7 @@ void BindingEditor::setBackendValue(const QVariant &backendValue)
m_backendValueTypeName = node.metaInfo()
.property(propertyEditorValue->name())
.propertyType()
- .typeName();
+ .simplifiedTypeName();
QString nodeId = node.id();
if (nodeId.isEmpty())
@@ -187,7 +187,7 @@ void BindingEditor::prepareBindings()
for (const auto &objnode : allNodes) {
BindingEditorDialog::BindingOption binding;
for (const auto &property : objnode.metaInfo().properties()) {
- const TypeName &propertyTypeName = property.propertyType().typeName();
+ const TypeName &propertyTypeName = property.propertyType().simplifiedTypeName();
if (skipTypeFiltering
|| (m_backendValueTypeName == propertyTypeName)
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp b/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp
index 14f55efa3f8..90bcc54fddc 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.cpp
@@ -95,7 +95,7 @@ void DesignerActionManagerView::nodeOrderChanged(const NodeListProperty &)
setupContext(SelectionContext::UpdateMode::NodeHierachy);
}
-void DesignerActionManagerView::importsChanged(const QList<Import> &, const QList<Import> &)
+void DesignerActionManagerView::importsChanged(const Imports &, const Imports &)
{
setupContext();
}
diff --git a/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h b/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h
index 41210602b38..9ccfe4e7379 100644
--- a/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h
+++ b/src/plugins/qmldesigner/components/componentcore/designeractionmanagerview.h
@@ -37,7 +37,7 @@ public:
void selectedNodesChanged(const QList<ModelNode> &,
const QList<ModelNode> &) override;
void nodeOrderChanged(const NodeListProperty &) override;
- void importsChanged(const QList<Import> &, const QList<Import> &) override;
+ void importsChanged(const Imports &, const Imports &) override;
void signalHandlerPropertiesChanged(const QVector<SignalHandlerProperty> &/*propertyList*/, PropertyChangeFlags /*propertyChange*/) override;
void variantPropertiesChanged(const QList<VariantProperty>& propertyList, PropertyChangeFlags propertyChangeFlag) override;
void bindingPropertiesChanged(const QList<BindingProperty>& propertyList, PropertyChangeFlags propertyChangeFlag) override;
diff --git a/src/plugins/qmldesigner/components/componentcore/designericons.h b/src/plugins/qmldesigner/components/componentcore/designericons.h
index f460707b915..749e4e1cce4 100644
--- a/src/plugins/qmldesigner/components/componentcore/designericons.h
+++ b/src/plugins/qmldesigner/components/componentcore/designericons.h
@@ -53,6 +53,7 @@ public:
AnchorsIcon,
AnnotationIcon,
ArrangeIcon,
+ BackspaceIcon,
CameraIcon,
CameraOrthographicIcon,
CameraPerspectiveIcon,
diff --git a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
index 10386425fe7..258ae0ba925 100644
--- a/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/modelnodeoperations.cpp
@@ -1650,7 +1650,11 @@ void openEffectMaker(const QString &filePath)
const QtSupport::QtVersion *baseQtVersion = QtSupport::QtKitAspect::qtVersion(target->kit());
if (baseQtVersion) {
+ Utils::Environment env = Utils::Environment::systemEnvironment();
+
auto effectMakerPath = baseQtVersion->binPath().pathAppended("qqem").withExecutableSuffix();
+ if (!effectMakerPath.exists() && env.osType() == Utils::OsTypeMac)
+ effectMakerPath = baseQtVersion->binPath().pathAppended("qqem.app/Contents/MacOS/qqem");
if (!effectMakerPath.exists()) {
qWarning() << __FUNCTION__ << "Cannot find EffectMaker app";
return;
@@ -1663,7 +1667,6 @@ void openEffectMaker(const QString &filePath)
arguments << "--create";
arguments << "--exportpath" << effectResPath.toString();
- Utils::Environment env = Utils::Environment::systemEnvironment();
if (env.osType() == Utils::OsTypeMac)
env.appendOrSet("QSG_RHI_BACKEND", "metal");
diff --git a/src/plugins/qmldesigner/components/componentcore/qmleditormenu.cpp b/src/plugins/qmldesigner/components/componentcore/qmleditormenu.cpp
index 173838f170d..e59fca7353e 100644
--- a/src/plugins/qmldesigner/components/componentcore/qmleditormenu.cpp
+++ b/src/plugins/qmldesigner/components/componentcore/qmleditormenu.cpp
@@ -149,4 +149,6 @@ QmlEditorStyleObject::QmlEditorStyleObject()
QmlEditorMenuPrivate::cascadeRight = DesignerIcons::rotateIcon(downIcon, -90);
QmlEditorMenuPrivate::tick = DesignerActionManager::instance()
.contextIcon(DesignerIcons::SimpleCheckIcon);
+ QmlEditorMenuPrivate::backspaceIcon = DesignerActionManager::instance()
+ .contextIcon(DesignerIcons::BackspaceIcon);
}
diff --git a/src/plugins/qmldesigner/components/componentcore/viewmanager.h b/src/plugins/qmldesigner/components/componentcore/viewmanager.h
index c54cf139e78..4201065f99f 100644
--- a/src/plugins/qmldesigner/components/componentcore/viewmanager.h
+++ b/src/plugins/qmldesigner/components/componentcore/viewmanager.h
@@ -67,7 +67,7 @@ public:
void disableWidgets();
void enableWidgets();
- void pushFileOnCrumbleBar(const Utils::FilePath &fileName);
+ void pushFileOnCrumbleBar(const ::Utils::FilePath &fileName);
void pushInFileComponentOnCrumbleBar(const ModelNode &modelNode);
void nextFileIsCalledInternally();
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp
index b3eb7542f8a..25a5756c28e 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionmodel.cpp
@@ -38,10 +38,7 @@ QStringList propertyNameListToStringList(const QmlDesigner::PropertyNameList &pr
bool isConnection(const QmlDesigner::ModelNode &modelNode)
{
- return (modelNode.type() == "Connections"
- || modelNode.type() == "QtQuick.Connections"
- || modelNode.type() == "Qt.Connections"
- || modelNode.type() == "QtQml.Connections");
+ return (modelNode.metaInfo().simplifiedTypeName() == "Connections");
}
} //namespace
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp b/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp
index 39e05a898ca..56fcc7ef6bf 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionview.cpp
@@ -183,7 +183,7 @@ void ConnectionView::auxiliaryDataChanged([[maybe_unused]] const ModelNode &node
selectionModel->clearSelection();
}
-void ConnectionView::importsChanged(const QList<Import> & /*addedImports*/, const QList<Import> & /*removedImports*/)
+void ConnectionView::importsChanged(const Imports & /*addedImports*/, const Imports & /*removedImports*/)
{
backendModel()->resetModel();
}
diff --git a/src/plugins/qmldesigner/components/connectioneditor/connectionview.h b/src/plugins/qmldesigner/components/connectioneditor/connectionview.h
index dcf61ad79d9..89c6c489105 100644
--- a/src/plugins/qmldesigner/components/connectioneditor/connectionview.h
+++ b/src/plugins/qmldesigner/components/connectioneditor/connectionview.h
@@ -50,7 +50,7 @@ public:
AuxiliaryDataKeyView key,
const QVariant &data) override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void currentStateChanged(const ModelNode &node) override;
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp
index 127ecb4225f..f272a4121df 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarymaterialsmodel.cpp
@@ -7,6 +7,8 @@
#include "contentlibrarymaterial.h"
#include "contentlibrarymaterialscategory.h"
#include "contentlibrarywidget.h"
+
+#include <designerpaths.h>
#include "filedownloader.h"
#include "fileextractor.h"
#include "multifiledownloader.h"
@@ -30,8 +32,7 @@ ContentLibraryMaterialsModel::ContentLibraryMaterialsModel(ContentLibraryWidget
: QAbstractListModel(parent)
, m_widget(parent)
{
- m_downloadPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)
- + "/QtDesignStudio/bundles/Materials";
+ m_downloadPath = Paths::bundlesPathSetting() + "/Materials";
m_baseUrl = QmlDesignerPlugin::settings()
.value(DesignerSettingsKey::DOWNLOADABLE_BUNDLES_URL)
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp
index 0d74be596f5..5cf88ab6fcd 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarytexturesmodel.cpp
@@ -4,8 +4,8 @@
#include "contentlibrarytexturesmodel.h"
#include "contentlibrarytexturescategory.h"
-#include "qmldesignerplugin.h"
+#include <designerpaths.h>
#include <qmldesignerbase/qmldesignerbaseplugin.h>
#include <utils/algorithm.h>
@@ -119,8 +119,10 @@ void ContentLibraryTexturesModel::loadTextureBundle(const QString &remoteUrl, co
for (const QFileInfo &tex : texFiles) {
QString fullRemoteUrl = QString("%1/%2/%3.zip").arg(remoteUrl, dir.fileName(),
tex.baseName());
- QString localDownloadPath = QString("%1/%2/%3").arg(QmlDesignerBasePlugin::bundlesPathSetting(),
- m_category, dir.fileName());
+ QString localDownloadPath = QString("%1/%2/%3")
+ .arg(Paths::bundlesPathSetting(),
+ m_category,
+ dir.fileName());
QString key = QString("%1/%2/%3").arg(m_category, dir.fileName(), tex.baseName());
QString fileExt;
QSize dimensions;
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp
index 9ce7a4e7377..3bb579273f6 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.cpp
@@ -144,7 +144,7 @@ void ContentLibraryView::modelAboutToBeDetached(Model *model)
AbstractView::modelAboutToBeDetached(model);
}
-void ContentLibraryView::importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports)
+void ContentLibraryView::importsChanged(const Imports &addedImports, const Imports &removedImports)
{
Q_UNUSED(addedImports)
Q_UNUSED(removedImports)
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h
index 1d27f6e260c..137034dd955 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibraryview.h
@@ -31,7 +31,7 @@ public:
// AbstractView
void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void active3DSceneChanged(qint32 sceneId) override;
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
const QList<ModelNode> &lastSelectedNodeList) override;
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp
index a1dfff5ef53..9cc9576bc6c 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.cpp
@@ -12,6 +12,7 @@
#include "utils/fileextractor.h"
#include <coreplugin/icore.h>
+#include <designerpaths.h>
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
@@ -117,13 +118,12 @@ ContentLibraryWidget::ContentLibraryWidget()
m_baseUrl = QmlDesignerPlugin::settings()
.value(DesignerSettingsKey::DOWNLOADABLE_BUNDLES_URL).toString()
- + "/textures/v1";
+ + "/textures";
m_texturesUrl = m_baseUrl + "/Textures";
m_environmentsUrl = m_baseUrl + "/Environments";
- m_downloadPath = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation)
- + "/QtDesignStudio/bundles";
+ m_downloadPath = Paths::bundlesPathSetting();
loadTextureBundle();
@@ -436,18 +436,4 @@ QPointer<ContentLibraryTexturesModel> ContentLibraryWidget::environmentsModel()
return m_environmentsModel;
}
-bool ContentLibraryWidget::markTextureDownloading()
-{
- if (m_anyTextureBeingDownloaded)
- return false;
-
- m_anyTextureBeingDownloaded = true;
- return true; // let the caller know it can begin download
-}
-
-void ContentLibraryWidget::markNoTextureDownloading()
-{
- m_anyTextureBeingDownloaded = false; // allow other textures to be downloaded
-}
-
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h
index 519d6fcf780..6d4ba51a300 100644
--- a/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h
+++ b/src/plugins/qmldesigner/components/contentlibrary/contentlibrarywidget.h
@@ -61,8 +61,6 @@ public:
Q_INVOKABLE void addTexture(QmlDesigner::ContentLibraryTexture *tex);
Q_INVOKABLE void addLightProbe(QmlDesigner::ContentLibraryTexture *tex);
Q_INVOKABLE void updateSceneEnvState();
- Q_INVOKABLE bool markTextureDownloading();
- Q_INVOKABLE void markNoTextureDownloading();
signals:
void bundleMaterialDragStarted(QmlDesigner::ContentLibraryMaterial *bundleMat);
@@ -102,7 +100,6 @@ private:
bool m_hasMaterialLibrary = false;
bool m_hasQuick3DImport = false;
bool m_isDragging = false;
- bool m_anyTextureBeingDownloaded = false;
QString m_baseUrl;
QString m_texturesUrl;
QString m_environmentsUrl;
diff --git a/src/plugins/qmldesigner/components/debugview/debugview.cpp b/src/plugins/qmldesigner/components/debugview/debugview.cpp
index 2888575e44c..2a62d7a6b2b 100644
--- a/src/plugins/qmldesigner/components/debugview/debugview.cpp
+++ b/src/plugins/qmldesigner/components/debugview/debugview.cpp
@@ -65,7 +65,7 @@ void DebugView::modelAboutToBeDetached(Model *model)
AbstractView::modelAboutToBeDetached(model);
}
-void DebugView::importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports)
+void DebugView::importsChanged(const Imports &addedImports, const Imports &removedImports)
{
if (isDebugViewEnabled()) {
QString message;
diff --git a/src/plugins/qmldesigner/components/debugview/debugview.h b/src/plugins/qmldesigner/components/debugview/debugview.h
index 885030545cf..e80c619c818 100644
--- a/src/plugins/qmldesigner/components/debugview/debugview.h
+++ b/src/plugins/qmldesigner/components/debugview/debugview.h
@@ -24,7 +24,7 @@ public:
void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void nodeCreated(const ModelNode &createdNode) override;
void nodeAboutToBeRemoved(const ModelNode &removedNode) override;
diff --git a/src/plugins/qmldesigner/components/edit3d/bakelights.cpp b/src/plugins/qmldesigner/components/edit3d/bakelights.cpp
new file mode 100644
index 00000000000..53c7e53df9d
--- /dev/null
+++ b/src/plugins/qmldesigner/components/edit3d/bakelights.cpp
@@ -0,0 +1,430 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "bakelights.h"
+
+#include "abstractview.h"
+#include "auxiliarydataproperties.h"
+#include "bakelightsdatamodel.h"
+#include "bakelightsconnectionmanager.h"
+#include "bindingproperty.h"
+#include "documentmanager.h"
+#include "modelnode.h"
+#include "nodeabstractproperty.h"
+#include "nodeinstanceview.h"
+#include "nodemetainfo.h"
+#include "plaintexteditmodifier.h"
+#include "rewriterview.h"
+#include "variantproperty.h"
+
+#include <coreplugin/icore.h>
+
+#include <qmljs/qmljsmodelmanagerinterface.h>
+
+#include <utils/algorithm.h>
+#include <utils/environment.h>
+#include <utils/filepath.h>
+#include <utils/qtcassert.h>
+
+#include <QEvent>
+#include <QQmlContext>
+#include <QQmlEngine>
+#include <QQuickView>
+#include <QSaveFile>
+#include <QTextCursor>
+#include <QTextDocument>
+#include <QTimer>
+#include <QVariant>
+
+namespace QmlDesigner {
+
+static QString propertyEditorResourcesPath()
+{
+#ifdef SHARE_QML_PATH
+ if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
+ return QLatin1String(SHARE_QML_PATH) + "/propertyEditorQmlSources";
+#endif
+ return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString();
+}
+
+static QString qmlSourcesPath()
+{
+#ifdef SHARE_QML_PATH
+ if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
+ return QLatin1String(SHARE_QML_PATH) + "/edit3dQmlSource";
+#endif
+ return Core::ICore::resourcePath("qmldesigner/edit3dQmlSource").toString();
+}
+
+BakeLights::BakeLights(AbstractView *view)
+ : QObject(view)
+ , m_view(view)
+{
+ m_view3dId = resolveView3dId(view);
+
+ if (m_view3dId.isEmpty()) {
+ // It should never get here, baking controls should be disabled in this case
+ qWarning() << __FUNCTION__ << "Active scene is not View3D";
+ deleteLater();
+ return;
+ }
+
+ showSetupDialog();
+}
+
+BakeLights::~BakeLights()
+{
+ cleanup();
+}
+
+ModelNode BakeLights::resolveView3dNode(AbstractView *view)
+{
+ if (!view || !view->model())
+ return {};
+
+ ModelNode activeView3D;
+ ModelNode activeScene = view->active3DSceneNode();
+
+ if (activeScene.isValid()) {
+ if (activeScene.metaInfo().isQtQuick3DView3D()) {
+ activeView3D = activeScene;
+ } else {
+ ModelNode sceneParent = activeScene.parentProperty().parentModelNode();
+ if (sceneParent.metaInfo().isQtQuick3DView3D())
+ activeView3D = sceneParent;
+ }
+ return activeView3D;
+ }
+
+ return {};
+}
+
+QString BakeLights::resolveView3dId(AbstractView *view)
+{
+ ModelNode activeView3D = resolveView3dNode(view);
+
+ if (activeView3D.isValid())
+ return activeView3D.id();
+
+ return {};
+}
+
+void BakeLights::raiseDialog()
+{
+ if (m_progressDialog)
+ m_progressDialog->raise();
+}
+
+bool BakeLights::manualMode() const
+{
+ return m_manualMode;
+}
+
+void BakeLights::setManualMode(bool enabled)
+{
+ if (m_manualMode != enabled) {
+ m_manualMode = enabled;
+ emit manualModeChanged();
+ }
+}
+
+void BakeLights::bakeLights()
+{
+ if (!m_view || !m_view->model())
+ return;
+
+ m_setupDialog->hide();
+ showProgressDialog();
+
+ // Start baking process
+ m_connectionManager = new BakeLightsConnectionManager;
+ m_rewriterView = new RewriterView{m_view->externalDependencies(), RewriterView::Amend};
+ m_nodeInstanceView = new NodeInstanceView{*m_connectionManager, m_view->externalDependencies()};
+
+ m_model = QmlDesigner::Model::create("QtQuick/Item", 2, 1);
+ m_model->setFileUrl(m_view->model()->fileUrl());
+
+ // Take the current unsaved state of the main model and apply it to our copy
+ auto textDocument = std::make_unique<QTextDocument>(
+ m_view->model()->rewriterView()->textModifier()->textDocument()->toRawText());
+
+ auto modifier = std::make_unique<NotIndentingTextEditModifier>(textDocument.get(),
+ QTextCursor{textDocument.get()});
+
+ m_rewriterView->setTextModifier(modifier.get());
+ m_model->setRewriterView(m_rewriterView);
+
+ auto rootModelNodeMetaInfo = m_rewriterView->rootModelNode().metaInfo();
+ bool is3DRoot = m_rewriterView->errors().isEmpty()
+ && (rootModelNodeMetaInfo.isQtQuick3DNode()
+ || rootModelNodeMetaInfo.isQtQuick3DMaterial());
+
+ if (!m_rewriterView->errors().isEmpty()
+ || (!m_rewriterView->rootModelNode().metaInfo().isGraphicalItem() && !is3DRoot)) {
+ emit progress(tr("Invalid root node, baking aborted."));
+ emit finished();
+ m_progressDialog->raise();
+ return;
+ }
+
+ m_nodeInstanceView->setTarget(m_view->nodeInstanceView()->target());
+
+ auto progressCallback = [this](const QString &msg) {
+ emit progress(msg);
+ };
+
+ auto finishedCallback = [this](const QString &msg) {
+ m_progressDialog->raise();
+ emit progress(msg);
+ emit finished();
+
+ // Puppet reset is needed to update baking results to current views
+ m_view->resetPuppet();
+ };
+
+ auto crashCallback = [this]() {
+ m_progressDialog->raise();
+ emit progress(tr("Baking process crashed, baking aborted."));
+ emit finished();
+ };
+
+ m_connectionManager->setProgressCallback(std::move(progressCallback));
+ m_connectionManager->setFinishedCallback(std::move(finishedCallback));
+ m_nodeInstanceView->setCrashCallback(std::move(crashCallback));
+
+ m_model->setNodeInstanceView(m_nodeInstanceView);
+
+ // InternalIds are not guaranteed to match between normal model and our copy of it, so
+ // we identify the View3D by its qml id.
+ m_nodeInstanceView->view3DAction(View3DActionType::SetBakeLightsView3D, m_view3dId);
+}
+
+void BakeLights::apply()
+{
+ // Uninitialized QVariant stored instead of false to remove the aux property in that case
+ m_dataModel->view3dNode().setAuxiliaryData(bakeLightsManualProperty,
+ m_manualMode ? QVariant{true} : QVariant{});
+
+ if (!m_manualMode)
+ m_dataModel->apply();
+
+ // Create folders for lightmaps if they do not exist
+ PropertyName loadPrefixPropName{"loadPrefix"};
+ const QList<ModelNode> bakedLightmapNodes = m_view->allModelNodesOfType(
+ m_view->model()->qtQuick3DBakedLightmapMetaInfo());
+ Utils::FilePath currentPath = DocumentManager::currentFilePath().absolutePath();
+ QSet<Utils::FilePath> pathSet;
+ for (const ModelNode &node : bakedLightmapNodes) {
+ if (node.hasVariantProperty(loadPrefixPropName)) {
+ QString prefix = node.variantProperty(loadPrefixPropName).value().toString();
+ Utils::FilePath fp = Utils::FilePath::fromString(prefix);
+ if (fp.isRelativePath()) {
+ fp = currentPath.pathAppended(prefix);
+ if (!fp.exists())
+ pathSet.insert(fp);
+ }
+ }
+ }
+ for (const Utils::FilePath &fp : std::as_const(pathSet))
+ fp.createDir();
+}
+
+void BakeLights::rebake()
+{
+ QTimer::singleShot(0, this, [this]() {
+ cleanup();
+ showSetupDialog();
+ });
+}
+
+void BakeLights::exposeModelsAndLights(const QString &nodeId)
+{
+ ModelNode compNode = m_view->modelNodeForId(nodeId);
+ if (!compNode.isValid() || !compNode.isComponent()
+ || compNode.metaInfo().componentFileName().isEmpty()) {
+ return;
+ }
+
+ RewriterView rewriter{m_view->externalDependencies(), RewriterView::Amend};
+ ModelPointer compModel = QmlDesigner::Model::create("QtQuick/Item", 2, 1);
+ const QString compFile = compNode.metaInfo().componentFileName();
+ const Utils::FilePath compFilePath = Utils::FilePath::fromString(compFile);
+ QByteArray src = compFilePath.fileContents().value();
+
+ compModel->setFileUrl(QUrl::fromLocalFile(compFile));
+
+ auto textDocument = std::make_unique<QTextDocument>(QString::fromUtf8(src));
+ auto modifier = std::make_unique<IndentingTextEditModifier>(
+ textDocument.get(), QTextCursor{textDocument.get()});
+
+ rewriter.setTextModifier(modifier.get());
+ compModel->setRewriterView(&rewriter);
+
+ if (!rewriter.rootModelNode().isValid() || !rewriter.errors().isEmpty())
+ return;
+
+ QString originalText = modifier->text();
+ QStringList idList;
+
+ rewriter.executeInTransaction(__FUNCTION__, [&]() {
+ QList<ModelNode> nodes = rewriter.rootModelNode().allSubModelNodes();
+ for (ModelNode &node : nodes) {
+ if (node.metaInfo().isQtQuick3DModel() || node.metaInfo().isQtQuick3DLight()) {
+ QString idStr = node.id();
+ if (idStr.isEmpty()) {
+ const QString type = node.metaInfo().isQtQuick3DModel() ? "model" : "light";
+ idStr = compModel->generateNewId(type);
+ node.setIdWithoutRefactoring(idStr);
+ }
+ idList.append(idStr);
+ }
+ }
+ });
+
+ rewriter.executeInTransaction(__FUNCTION__, [&]() {
+ for (const QString &id : std::as_const(idList)) {
+ ModelNode node = rewriter.modelNodeForId(id);
+ if (!node.isValid())
+ continue;
+ rewriter.rootModelNode().bindingProperty(id.toUtf8())
+ .setDynamicTypeNameAndExpression("alias", id);
+ }
+ });
+
+ rewriter.forceAmend();
+
+ QString newText = modifier->text();
+ if (newText != originalText) {
+ QSaveFile saveFile(compFile);
+ if (saveFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ saveFile.write(newText.toUtf8());
+ saveFile.commit();
+ } else {
+ qWarning() << __FUNCTION__ << "Failed to save changes to:" << compFile;
+ }
+ }
+
+ QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
+ QmlJS::Document::Ptr doc = rewriter.document()->ptr();
+ modelManager->updateDocument(doc);
+
+ m_view->model()->rewriterView()->forceAmend();
+
+ compModel->setRewriterView({});
+
+ // Rebake to relaunch setup dialog with updated properties
+ rebake();
+}
+
+void BakeLights::showSetupDialog()
+{
+ if (!m_dataModel)
+ m_dataModel = new BakeLightsDataModel(m_view);
+
+ m_dataModel->reset();
+
+ auto data = m_dataModel->view3dNode().auxiliaryData(bakeLightsManualProperty);
+ if (data)
+ m_manualMode = data->toBool();
+
+ if (!m_setupDialog) {
+ // Show non-modal progress dialog with cancel button
+ QString path = qmlSourcesPath() + "/BakeLightsSetupDialog.qml";
+
+ m_setupDialog = new QQuickView;
+ m_setupDialog->setTitle(tr("Lights Baking Setup"));
+ m_setupDialog->setResizeMode(QQuickView::SizeRootObjectToView);
+ m_setupDialog->setMinimumSize({550, 200});
+ m_setupDialog->setWidth(550);
+ m_setupDialog->setHeight(400);
+ m_setupDialog->setFlags(Qt::Dialog);
+ m_setupDialog->setModality(Qt::ApplicationModal);
+ m_setupDialog->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
+
+ m_setupDialog->rootContext()->setContextProperties({
+ {"rootView", QVariant::fromValue(this)},
+ {"sceneId", QVariant::fromValue(m_view3dId)},
+ {"bakeModel", QVariant::fromValue(m_dataModel.data())}
+ });
+ m_setupDialog->setSource(QUrl::fromLocalFile(path));
+ m_setupDialog->installEventFilter(this);
+ }
+ m_setupDialog->show();
+}
+
+void BakeLights::showProgressDialog()
+{
+ if (!m_progressDialog) {
+ // Show non-modal progress dialog with cancel button
+ QString path = qmlSourcesPath() + "/BakeLightsProgressDialog.qml";
+
+ m_progressDialog = new QQuickView;
+ m_progressDialog->setTitle(tr("Lights Baking Progress"));
+ m_progressDialog->setResizeMode(QQuickView::SizeRootObjectToView);
+ m_progressDialog->setMinimumSize({150, 100});
+ m_progressDialog->setWidth(800);
+ m_progressDialog->setHeight(400);
+ m_progressDialog->setFlags(Qt::Dialog);
+ m_progressDialog->setModality(Qt::NonModal);
+ m_progressDialog->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
+
+ m_progressDialog->rootContext()->setContextProperties({
+ {"rootView", QVariant::fromValue(this)},
+ {"sceneId", QVariant::fromValue(m_view3dId)}
+ });
+ m_progressDialog->setSource(QUrl::fromLocalFile(path));
+ m_progressDialog->installEventFilter(this);
+ }
+ m_progressDialog->show();
+}
+
+void BakeLights::cleanup()
+{
+ if (m_connectionManager) {
+ m_connectionManager->setProgressCallback({});
+ m_connectionManager->setFinishedCallback({});
+ m_nodeInstanceView->setCrashCallback({});
+ }
+
+ if (m_model) {
+ m_model->setNodeInstanceView({});
+ m_model->setRewriterView({});
+ m_model.reset();
+ }
+
+ delete m_setupDialog;
+ delete m_progressDialog;
+ delete m_rewriterView;
+ delete m_nodeInstanceView;
+ delete m_connectionManager;
+ delete m_dataModel;
+
+ m_manualMode = false;
+}
+
+void BakeLights::cancel()
+{
+ if (!m_setupDialog.isNull() && m_setupDialog->isVisible())
+ m_setupDialog->close();
+ if (!m_progressDialog.isNull() && m_progressDialog->isVisible())
+ m_progressDialog->close();
+
+ deleteLater();
+}
+
+bool BakeLights::eventFilter(QObject *obj, QEvent *event)
+{
+ if (obj == m_progressDialog || obj == m_setupDialog) {
+ if (event->type() == QEvent::KeyPress) {
+ QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
+ if (keyEvent->key() == Qt::Key_Escape)
+ cancel();
+ } else if (event->type() == QEvent::Close) {
+ cancel();
+ }
+ }
+
+ return QObject::eventFilter(obj, event);
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/edit3d/bakelights.h b/src/plugins/qmldesigner/components/edit3d/bakelights.h
new file mode 100644
index 00000000000..65f00acc7b0
--- /dev/null
+++ b/src/plugins/qmldesigner/components/edit3d/bakelights.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+#pragma once
+
+#include "modelnode.h"
+#include "qmldesignercorelib_global.h"
+
+#include <QObject>
+#include <QPointer>
+
+QT_BEGIN_NAMESPACE
+class QQuickView;
+QT_END_NAMESPACE
+
+namespace QmlDesigner {
+
+class AbstractView;
+class BakeLightsConnectionManager;
+class NodeInstanceView;
+class RewriterView;
+class BakeLightsDataModel;
+
+class BakeLights : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(bool manualMode READ manualMode WRITE setManualMode NOTIFY manualModeChanged)
+
+public:
+ BakeLights(AbstractView *view);
+ ~BakeLights();
+
+ Q_INVOKABLE void cancel();
+ Q_INVOKABLE void bakeLights();
+ Q_INVOKABLE void apply();
+ Q_INVOKABLE void rebake();
+ Q_INVOKABLE void exposeModelsAndLights(const QString &nodeId);
+
+ void raiseDialog();
+
+ bool manualMode() const;
+ void setManualMode(bool enabled);
+
+ static ModelNode resolveView3dNode(AbstractView *view);
+ static QString resolveView3dId(AbstractView *view);
+
+signals:
+ void finished();
+ void progress(const QString &msg);
+ void manualModeChanged();
+
+protected:
+ bool eventFilter(QObject *obj, QEvent *event) override;
+
+private:
+ void showSetupDialog();
+ void showProgressDialog();
+ void cleanup();
+
+ // Separate dialogs for setup and progress, as setup needs to be modal
+ QPointer<QQuickView> m_setupDialog;
+ QPointer<QQuickView> m_progressDialog;
+
+ QPointer<BakeLightsConnectionManager> m_connectionManager;
+ QPointer<NodeInstanceView> m_nodeInstanceView;
+ QPointer<RewriterView> m_rewriterView;
+ QPointer<AbstractView> m_view;
+ QPointer<BakeLightsDataModel> m_dataModel;
+ ModelPointer m_model;
+ QString m_view3dId;
+ bool m_manualMode = false;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/edit3d/bakelightsconnectionmanager.cpp b/src/plugins/qmldesigner/components/edit3d/bakelightsconnectionmanager.cpp
new file mode 100644
index 00000000000..d2a6f3d332d
--- /dev/null
+++ b/src/plugins/qmldesigner/components/edit3d/bakelightsconnectionmanager.cpp
@@ -0,0 +1,48 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "bakelightsconnectionmanager.h"
+
+#include <puppettocreatorcommand.h>
+
+namespace QmlDesigner {
+
+BakeLightsConnectionManager::BakeLightsConnectionManager()
+{
+ connections().emplace_back("Bake lights", "bakelightsmode");
+}
+
+void BakeLightsConnectionManager::setProgressCallback(Callback callback)
+{
+ m_progressCallback = std::move(callback);
+}
+
+void BakeLightsConnectionManager::setFinishedCallback(Callback callback)
+{
+ m_finishedCallback = std::move(callback);
+}
+
+void BakeLightsConnectionManager::dispatchCommand(const QVariant &command,
+ ConnectionManagerInterface::Connection &)
+{
+ static const int commandType = QMetaType::type("PuppetToCreatorCommand");
+
+ if (command.userType() == commandType) {
+ auto cmd = command.value<PuppetToCreatorCommand>();
+ switch (cmd.type()) {
+ case PuppetToCreatorCommand::BakeLightsProgress:
+ m_progressCallback(cmd.data().toString());
+ break;
+ case PuppetToCreatorCommand::BakeLightsAborted:
+ m_finishedCallback(tr("Baking aborted: %1").arg(cmd.data().toString()));
+ break;
+ case PuppetToCreatorCommand::BakeLightsFinished:
+ m_finishedCallback(tr("Baking finished!"));
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/edit3d/bakelightsconnectionmanager.h b/src/plugins/qmldesigner/components/edit3d/bakelightsconnectionmanager.h
new file mode 100644
index 00000000000..2af5e56c114
--- /dev/null
+++ b/src/plugins/qmldesigner/components/edit3d/bakelightsconnectionmanager.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "connectionmanager.h"
+
+namespace QmlDesigner {
+
+class BakeLightsConnectionManager : public ConnectionManager
+{
+public:
+ using Callback = std::function<void(const QString &)>;
+
+ BakeLightsConnectionManager();
+
+ void setProgressCallback(Callback callback);
+ void setFinishedCallback(Callback callback);
+
+protected:
+ void dispatchCommand(const QVariant &command, Connection &connection) override;
+
+private:
+ Callback m_progressCallback;
+ Callback m_finishedCallback;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/edit3d/bakelightsdatamodel.cpp b/src/plugins/qmldesigner/components/edit3d/bakelightsdatamodel.cpp
new file mode 100644
index 00000000000..36d192a9244
--- /dev/null
+++ b/src/plugins/qmldesigner/components/edit3d/bakelightsdatamodel.cpp
@@ -0,0 +1,387 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "bakelightsdatamodel.h"
+
+#include "abstractview.h"
+#include "bakelights.h"
+#include "bindingproperty.h"
+#include "enumeration.h"
+#include "externaldependenciesinterface.h"
+#include "model.h"
+#include "modelnode.h"
+#include "nodelistproperty.h"
+#include "nodemetainfo.h"
+#include "qmlobjectnode.h"
+#include "variantproperty.h"
+
+#include <utils/expected.h>
+#include <utils/filepath.h>
+#include <utils/qtcassert.h>
+
+#include <algorithm>
+
+namespace QmlDesigner {
+
+
+BakeLightsDataModel::BakeLightsDataModel(AbstractView *view)
+ : QAbstractListModel(view)
+ , m_view(view)
+{
+}
+
+BakeLightsDataModel::~BakeLightsDataModel()
+{
+}
+
+int BakeLightsDataModel::rowCount(const QModelIndex &) const
+{
+ return m_dataList.count();
+}
+
+QHash<int, QByteArray> BakeLightsDataModel::roleNames() const
+{
+ static const QHash<int, QByteArray> roles {
+ {Qt::UserRole + 1, "displayId"},
+ {Qt::UserRole + 2, "nodeId"},
+ {Qt::UserRole + 3, "isModel"},
+ {Qt::UserRole + 4, "isEnabled"},
+ {Qt::UserRole + 5, "inUse"},
+ {Qt::UserRole + 6, "isTitle"},
+ {Qt::UserRole + 7, "isUnexposed"},
+ {Qt::UserRole + 8, "resolution"},
+ {Qt::UserRole + 9, "bakeMode"}
+ };
+ return roles;
+}
+
+QVariant BakeLightsDataModel::data(const QModelIndex &index, int role) const
+{
+ QTC_ASSERT(index.isValid() && index.row() < m_dataList.count(), return {});
+ QTC_ASSERT(roleNames().contains(role), return {});
+
+ QByteArray roleName = roleNames().value(role);
+ const BakeData &bakeData = m_dataList[index.row()];
+
+ if (roleName == "displayId") {
+ const QString id = bakeData.id;
+ const PropertyName aliasProp = bakeData.aliasProp;
+ if (aliasProp.isEmpty())
+ return id;
+ else
+ return QVariant{id + " - " + QString::fromUtf8(aliasProp)};
+ return {};
+ }
+
+ if (roleName == "nodeId")
+ return bakeData.id;
+
+ if (roleName == "isModel")
+ return bakeData.isModel;
+
+ if (roleName == "isEnabled")
+ return bakeData.enabled;
+
+ if (roleName == "inUse")
+ return bakeData.inUse;
+
+ if (roleName == "isTitle")
+ return bakeData.isTitle;
+
+ if (roleName == "isUnexposed")
+ return bakeData.isUnexposed;
+
+ if (roleName == "resolution")
+ return bakeData.resolution;
+
+ if (roleName == "bakeMode")
+ return bakeData.bakeMode;
+
+ return {};
+}
+
+bool BakeLightsDataModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ QTC_ASSERT(index.isValid() && index.row() < m_dataList.count(), return false);
+ QTC_ASSERT(roleNames().contains(role), return false);
+
+ QByteArray roleName = roleNames().value(role);
+ BakeData &bakeData = m_dataList[index.row()];
+
+ bool changed = false;
+
+ if (roleName == "isEnabled") {
+ changed = bakeData.enabled != value.toBool();
+ bakeData.enabled = value.toBool();
+ } else if (roleName == "inUse") {
+ changed = bakeData.inUse != value.toBool();
+ bakeData.inUse = value.toBool();
+ } else if (roleName == "resolution") {
+ changed = bakeData.resolution != value.toInt();
+ bakeData.resolution = value.toInt();
+ } else if (roleName == "bakeMode") {
+ changed = bakeData.bakeMode != value.toString();
+ bakeData.bakeMode = value.toString();
+ }
+
+ if (changed)
+ emit dataChanged(index, index, {role});
+
+ return changed;
+}
+
+void BakeLightsDataModel::reset()
+{
+ if (!m_view || !m_view->model())
+ return;
+
+ beginResetModel();
+ m_dataList.clear();
+
+ m_view3dNode = BakeLights::resolveView3dNode(m_view);
+
+ // Find all models and lights in active View3D
+ QList<ModelNode> nodes = m_view3dNode.allSubModelNodes();
+
+ if (m_view3dNode.hasBindingProperty("importScene"))
+ nodes.append(m_view3dNode.bindingProperty("importScene").resolveToModelNode().allSubModelNodesAndThisNode());
+
+ QList<BakeData> modelList;
+ QList<BakeData> lightList;
+ QList<BakeData> compModelList;
+ QList<BakeData> compLightList;
+ QList<BakeData> unexposedList;
+
+ // Note: We are always loading base state values for baking. If users want to bake
+ // differently for different states, they need to setup things manually for now.
+ // Same goes if they want to use any unusual bindings in baking properties.
+ for (const auto &node : std::as_const(nodes)) {
+ if (QmlObjectNode(node).hasError())
+ continue;
+
+ BakeData data;
+ data.id = node.id();
+ if (data.id.isEmpty())
+ continue; // Skip nodes without id
+
+ if (node.metaInfo().isQtQuick3DModel()) {
+ data.isModel = true;
+ if (node.hasBindingProperty("bakedLightmap")) {
+ ModelNode blm = node.bindingProperty("bakedLightmap").resolveToModelNode();
+ if (blm.isValid()) {
+ if (blm.hasVariantProperty("enabled"))
+ data.enabled = blm.variantProperty("enabled").value().toBool();
+ else
+ data.enabled = true;
+ }
+ }
+ if (node.hasVariantProperty("lightmapBaseResolution"))
+ data.resolution = node.variantProperty("lightmapBaseResolution").value().toInt();
+ if (node.hasVariantProperty("usedInBakedLighting"))
+ data.inUse = node.variantProperty("usedInBakedLighting").value().toBool();
+ modelList.append(data);
+ } else if (node.metaInfo().isQtQuick3DLight()) {
+ if (node.hasVariantProperty("bakeMode")) {
+ data.bakeMode = node.variantProperty("bakeMode").value()
+ .value<QmlDesigner::Enumeration>().toString();
+ } else {
+ data.bakeMode = "Light.BakeModeDisabled";
+ }
+ lightList.append(data);
+ }
+
+ if (node.isComponent()) {
+ // Every component can expose multiple aliases
+ // We ignore baking properties defined inside the component (no visibility there)
+ bool hasExposedProps = false;
+ const QList<AbstractProperty> props = node.properties();
+ PropertyMetaInfos metaInfos = node.metaInfo().properties();
+ for (const PropertyMetaInfo &mi : metaInfos) {
+ if (mi.isValid() && !mi.isPrivate() && mi.isWritable()) {
+ BakeData propData;
+ propData.id = data.id;
+ propData.aliasProp = mi.name();
+ if (mi.propertyType().isQtQuick3DModel()) {
+ hasExposedProps = true;
+ propData.isModel = true;
+ PropertyName dotName = mi.name() + '.';
+ for (const AbstractProperty &prop : props) {
+ if (prop.name().startsWith(dotName)) {
+ PropertyName subName = prop.name().mid(dotName.size());
+ if (subName == "bakedLightmap") {
+ ModelNode blm = prop.toBindingProperty().resolveToModelNode();
+ if (blm.isValid()) {
+ if (blm.hasVariantProperty("enabled"))
+ propData.enabled = blm.variantProperty("enabled").value().toBool();
+ else
+ propData.enabled = true;
+ }
+ }
+ if (subName == "lightmapBaseResolution")
+ propData.resolution = prop.toVariantProperty().value().toInt();
+ if (subName == "usedInBakedLighting")
+ propData.inUse = prop.toVariantProperty().value().toBool();
+ }
+ }
+ compModelList.append(propData);
+ } else if (mi.propertyType().isQtQuick3DLight()) {
+ hasExposedProps = true;
+ PropertyName dotName = mi.name() + '.';
+ for (const AbstractProperty &prop : props) {
+ if (prop.name().startsWith(dotName)) {
+ PropertyName subName = prop.name().mid(dotName.size());
+ if (subName == "bakeMode") {
+ propData.bakeMode = prop.toVariantProperty().value()
+ .value<QmlDesigner::Enumeration>()
+ .toString();
+ }
+ }
+ }
+ if (propData.bakeMode.isEmpty())
+ propData.bakeMode = "Light.BakeModeDisabled";
+ compLightList.append(propData);
+ }
+ }
+ }
+
+ if (!hasExposedProps && node.metaInfo().isFileComponent()
+ && node.metaInfo().isQtQuick3DNode()) {
+ const QString compFile = node.metaInfo().componentFileName();
+ const QString projPath = m_view->externalDependencies().currentProjectDirPath();
+ if (compFile.startsWith(projPath)) {
+ // Quick and dirty scan of the component source to check if it potentially has
+ // models or lights.
+ QByteArray src = Utils::FilePath::fromString(compFile).fileContents().value();
+ src = src.mid(src.indexOf('{')); // Skip root element
+ if (src.contains("Model {") || src.contains("Light {")) {
+ data.isUnexposed = true;
+ unexposedList.append(data);
+ }
+ }
+ }
+ }
+ }
+
+ auto sortList = [](QList<BakeData> &list) {
+ std::sort(list.begin(), list.end(), [](const BakeData &a, const BakeData &b) {
+ return a.id.compare(b.id) < 0;
+ });
+ };
+
+ sortList(modelList);
+ sortList(lightList);
+ sortList(compModelList);
+ sortList(compLightList);
+ sortList(unexposedList);
+
+ BakeData titleData;
+ titleData.isTitle = true;
+ titleData.id = tr("Lights");
+ m_dataList.append(titleData);
+ m_dataList.append(lightList);
+ m_dataList.append(compLightList);
+ titleData.id = tr("Models");
+ m_dataList.append(titleData);
+ m_dataList.append(modelList);
+ m_dataList.append(compModelList);
+
+ if (!unexposedList.isEmpty()) {
+ titleData.id = tr("Components with unexposed models and/or lights");
+ m_dataList.append(titleData);
+ m_dataList.append(unexposedList);
+ }
+
+ endResetModel();
+}
+
+void BakeLightsDataModel::apply()
+{
+ if (!m_view || !m_view->model())
+ return;
+
+ auto setBakedLightmap = [this](const ModelNode &node, const BakeData &data) {
+ ModelNode blmNode;
+ PropertyName propName{"bakedLightmap"};
+ if (!data.aliasProp.isEmpty())
+ propName.prepend(data.aliasProp + '.');
+ if (node.hasBindingProperty(propName))
+ blmNode = node.bindingProperty(propName).resolveToModelNode();
+ if (!blmNode.isValid() && data.enabled) {
+ NodeMetaInfo metaInfo = m_view->model()->qtQuick3DBakedLightmapMetaInfo();
+ blmNode = m_view->createModelNode("QtQuick3D.BakedLightmap",
+ metaInfo.majorVersion(),
+ metaInfo.minorVersion());
+ QString idPart;
+ if (data.aliasProp.isEmpty())
+ idPart = data.id;
+ else
+ idPart = QStringLiteral("%1_%2").arg(data.id, QString::fromUtf8(data.aliasProp));
+ QString newId = m_view->model()->generateNewId(QStringLiteral("blm_%1").arg(idPart));
+ blmNode.setIdWithoutRefactoring(newId);
+ node.defaultNodeListProperty().reparentHere(blmNode);
+ node.bindingProperty(propName).setExpression(newId);
+ }
+ if (blmNode.isValid()) {
+ VariantProperty enabledProp = blmNode.variantProperty("enabled");
+ VariantProperty prefixProp = blmNode.variantProperty("loadPrefix");
+ VariantProperty keyProp = blmNode.variantProperty("key");
+ enabledProp.setValue(data.enabled);
+ prefixProp.setValue(commonPrefix());
+ keyProp.setValue(blmNode.id());
+ }
+ };
+
+ auto setVariantProp = [](const ModelNode &node,
+ const PropertyName &propName,
+ const PropertyName &aliasProp,
+ const QVariant &value,
+ const QVariant &defaultValue) {
+ PropertyName resolvedName = propName;
+ if (!aliasProp.isEmpty())
+ resolvedName.prepend(aliasProp + '.');
+ if (node.hasVariantProperty(resolvedName) || value != defaultValue)
+ node.variantProperty(resolvedName).setValue(value);
+ };
+
+ // Commits changes to scene model
+ m_view->executeInTransaction(__FUNCTION__, [&]() {
+ for (const BakeData &data : std::as_const(m_dataList)) {
+ if (data.isTitle || data.isUnexposed)
+ continue;
+ ModelNode node = m_view->modelNodeForId(data.id);
+ if (data.isModel) {
+ setBakedLightmap(node, data);
+ setVariantProp(node, "lightmapBaseResolution", data.aliasProp, data.resolution, 1024);
+ setVariantProp(node, "usedInBakedLighting", data.aliasProp, data.inUse, false);
+ } else {
+ setVariantProp(node, "bakeMode", data.aliasProp,
+ QVariant::fromValue(QmlDesigner::Enumeration(data.bakeMode)),
+ QVariant::fromValue(QmlDesigner::Enumeration("Light", "BakeModeDisabled")));
+ }
+ }
+ });
+}
+
+QString BakeLightsDataModel::commonPrefix()
+{
+ static QString prefix = "lightmaps";
+ return prefix;
+}
+
+QDebug operator<<(QDebug debug, const BakeLightsDataModel::BakeData &data)
+{
+ QDebugStateSaver saver(debug);
+ debug.space() << "("
+ << "id:" << data.id
+ << "aliasProp:" << data.aliasProp
+ << "isModel:" << data.isModel
+ << "enabled:" << data.enabled
+ << "inUse:" << data.inUse
+ << "resolution:" << data.resolution
+ << "bakeMode:" << data.bakeMode
+ << "isTitle:" << data.isTitle
+ << ")";
+ return debug;
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/edit3d/bakelightsdatamodel.h b/src/plugins/qmldesigner/components/edit3d/bakelightsdatamodel.h
new file mode 100644
index 00000000000..313c09cf459
--- /dev/null
+++ b/src/plugins/qmldesigner/components/edit3d/bakelightsdatamodel.h
@@ -0,0 +1,56 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+#pragma once
+
+#include "modelnode.h"
+#include "qmldesignercorelib_global.h"
+
+#include <QAbstractListModel>
+#include <QObject>
+#include <QPointer>
+
+namespace QmlDesigner {
+
+class AbstractView;
+
+class BakeLightsDataModel : public QAbstractListModel
+{
+ Q_OBJECT
+
+public:
+ struct BakeData {
+ QString id; // node id. Also used as BakedLightmap.key
+ PropertyName aliasProp; // property id for component exposed models/lights
+ bool isModel = false; // false means light
+ bool enabled = false;
+ bool inUse = false;
+ bool isTitle = false; // if true, indicates a title row in UI
+ bool isUnexposed = false; // if true, indicates a component with unexposed models/lights
+ int resolution = 1024;
+ QString bakeMode;
+ };
+
+ BakeLightsDataModel(AbstractView *view);
+ ~BakeLightsDataModel() override;
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+ QHash<int, QByteArray> roleNames() const override;
+ bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+
+ void reset();
+ void apply();
+
+ ModelNode view3dNode() const { return m_view3dNode; }
+
+private:
+ QString commonPrefix();
+
+ QPointer<AbstractView> m_view;
+ QList<BakeData> m_dataList;
+ ModelNode m_view3dNode;
+};
+
+QDebug operator<<(QDebug debug, const BakeLightsDataModel::BakeData &data);
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp
index 61731c578f8..12d2dd05528 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.cpp
@@ -2,18 +2,15 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "edit3dactions.h"
-#include "edit3dview.h"
-#include <viewmanager.h>
-#include <nodeinstanceview.h>
-#include <nodemetainfo.h>
-#include <qmldesignerplugin.h>
+#include "bakelights.h"
+#include "edit3dview.h"
+#include "nodemetainfo.h"
+#include "qmldesignerconstants.h"
#include "seekerslider.h"
#include <utils/algorithm.h>
-#include <QDebug>
-
namespace QmlDesigner {
Edit3DActionTemplate::Edit3DActionTemplate(const QString &description,
@@ -147,4 +144,33 @@ bool Edit3DParticleSeekerAction::isEnabled(const SelectionContext &) const
return m_seeker->isEnabled();
}
+Edit3DBakeLightsAction::Edit3DBakeLightsAction(const QIcon &icon,
+ Edit3DView *view,
+ SelectionContextOperation selectionAction)
+ : Edit3DAction(QmlDesigner::Constants::EDIT3D_BAKE_LIGHTS,
+ View3DActionType::Empty,
+ QCoreApplication::translate("BakeLights", "Bake Lights"),
+ QKeySequence(),
+ false,
+ false,
+ icon,
+ view,
+ selectionAction,
+ QCoreApplication::translate("BakeLights", "Bake lights for the current 3D scene."))
+ , m_view(view)
+{
+
+}
+
+bool Edit3DBakeLightsAction::isVisible(const SelectionContext &) const
+{
+ return m_view->isBakingLightsSupported();
+}
+
+bool Edit3DBakeLightsAction::isEnabled(const SelectionContext &) const
+{
+ return m_view->isBakingLightsSupported()
+ && !BakeLights::resolveView3dId(m_view).isEmpty();
+}
+
}
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dactions.h b/src/plugins/qmldesigner/components/edit3d/edit3dactions.h
index bad427a25be..4e8be202b9f 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dactions.h
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dactions.h
@@ -122,4 +122,19 @@ private:
SeekerSliderAction *m_seeker = nullptr;
};
+class Edit3DBakeLightsAction : public Edit3DAction
+{
+public:
+ Edit3DBakeLightsAction(const QIcon &icon,
+ Edit3DView *view,
+ SelectionContextOperation selectionAction);
+
+protected:
+ bool isVisible(const SelectionContext &) const override;
+ bool isEnabled(const SelectionContext &) const override;
+
+private:
+ Edit3DView *m_view = nullptr;
+};
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
index d92e76362b9..10d62a5dc21 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.cpp
@@ -4,6 +4,7 @@
#include "edit3dview.h"
#include "backgroundcolorselection.h"
+#include "bakelights.h"
#include "designeractionmanager.h"
#include "designericons.h"
#include "designersettings.h"
@@ -20,11 +21,18 @@
#include "qmldesignerplugin.h"
#include "qmlvisualnode.h"
#include "seekerslider.h"
+#include "theme.h"
+
+#include <model/modelutils.h>
#include <coreplugin/icore.h>
#include <coreplugin/messagebox.h>
-#include <theme.h>
+#include <projectexplorer/target.h>
+#include <projectexplorer/kit.h>
+
+#include <qtsupport/qtkitinformation.h>
+
#include <utils/algorithm.h>
#include <utils/qtcassert.h>
#include <utils/stylehelper.h>
@@ -204,6 +212,12 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState)
m_particlesPlayAction->action()->setChecked(sceneState[particlesPlayKey].toBool());
else
m_particlesPlayAction->action()->setChecked(true);
+
+ // Selection context change updates visible and enabled states
+ SelectionContext selectionContext(this);
+ selectionContext.setUpdateMode(SelectionContext::UpdateMode::Fast);
+ if (m_bakeLightsAction)
+ m_bakeLightsAction->currentContextChanged(selectionContext);
}
void Edit3DView::modelAttached(Model *model)
@@ -219,6 +233,13 @@ void Edit3DView::modelAttached(Model *model)
edit3DWidget()->canvas()->busyIndicator()->show();
+ m_isBakingLightsSupported = false;
+ ProjectExplorer::Target *target = QmlDesignerPlugin::instance()->currentDesignDocument()->currentTarget();
+ if (target && target->kit()) {
+ if (QtSupport::QtVersion *qtVer = QtSupport::QtKitAspect::qtVersion(target->kit()))
+ m_isBakingLightsSupported = qtVer->qtVersion() >= QVersionNumber(6, 5, 0);
+ }
+
connect(model->metaInfo().itemLibraryInfo(), &ItemLibraryInfo::entriesChanged, this,
&Edit3DView::onEntriesChanged, Qt::UniqueConnection);
}
@@ -279,6 +300,11 @@ void Edit3DView::handleEntriesChanged()
void Edit3DView::modelAboutToBeDetached(Model *model)
{
+ m_isBakingLightsSupported = false;
+
+ if (m_bakeLights)
+ m_bakeLights->cancel();
+
// Hide the canvas when model is detached (i.e. changing documents)
if (edit3DWidget() && edit3DWidget()->canvas()) {
m_canvasCache.insert(model, edit3DWidget()->canvas()->renderImage());
@@ -288,8 +314,8 @@ void Edit3DView::modelAboutToBeDetached(Model *model)
AbstractView::modelAboutToBeDetached(model);
}
-void Edit3DView::importsChanged([[maybe_unused]] const QList<Import> &addedImports,
- [[maybe_unused]] const QList<Import> &removedImports)
+void Edit3DView::importsChanged([[maybe_unused]] const Imports &addedImports,
+ [[maybe_unused]] const Imports &removedImports)
{
checkImports();
}
@@ -702,6 +728,17 @@ void Edit3DView::createEdit3DActions()
m_seekerAction->action()->setEnabled(!m_particlesPlayAction->action()->isChecked());
};
+ SelectionContextOperation bakeLightsTrigger = [this](const SelectionContext &) {
+ if (!m_isBakingLightsSupported)
+ return;
+
+ // BakeLights cleans itself up when its dialog is closed
+ if (!m_bakeLights)
+ m_bakeLights = new BakeLights(this);
+ else
+ m_bakeLights->raiseDialog();
+ };
+
m_particleViewModeAction = new Edit3DAction(
QmlDesigner::Constants::EDIT3D_PARTICLE_MODE,
View3DActionType::Edit3DParticleModeToggle,
@@ -804,6 +841,11 @@ void Edit3DView::createEdit3DActions()
m_seekerAction = createSeekerSliderAction();
+ m_bakeLightsAction = new Edit3DBakeLightsAction(
+ toolbarIcon(Theme::editLightOn_medium), //: TODO placeholder icon
+ this,
+ bakeLightsTrigger);
+
m_leftActions << m_selectionModeAction;
m_leftActions << nullptr; // Null indicates separator
m_leftActions << nullptr; // Second null after separator indicates an exclusive group
@@ -830,6 +872,7 @@ void Edit3DView::createEdit3DActions()
m_rightActions << nullptr;
m_rightActions << m_seekerAction;
m_rightActions << nullptr;
+ m_rightActions << m_bakeLightsAction;
m_rightActions << m_resetAction;
m_visibilityToggleActions << m_showGridAction;
@@ -870,24 +913,20 @@ Edit3DAction *Edit3DView::edit3DAction(View3DActionType type) const
return m_edit3DActions.value(type, nullptr).data();
}
+Edit3DBakeLightsAction *Edit3DView::bakeLightsAction() const
+{
+ return m_bakeLightsAction;
+}
+
void Edit3DView::addQuick3DImport()
{
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
- if (document && !document->inFileComponentModelActive() && model()) {
- const QList<Import> imports = model()->possibleImports();
- for (const auto &import : imports) {
- if (import.url() == "QtQuick3D") {
- if (!import.version().isEmpty() && import.majorVersion() >= 6) {
- // Prefer empty version number in Qt6 and beyond
- model()->changeImports({Import::createLibraryImport(
- import.url(), {}, import.alias(),
- import.importPaths())}, {});
- } else {
- model()->changeImports({import}, {});
- }
- return;
- }
- }
+ if (document && !document->inFileComponentModelActive() && model()
+ && Utils::addImportWithCheck(
+ "QtQuick3D",
+ [](const Import &import) { return !import.hasVersion() || import.majorVersion() >= 6; },
+ model())) {
+ return;
}
Core::AsynchronousMessageBox::warning(tr("Failed to Add Import"),
tr("Could not add QtQuick3D import to project."));
@@ -939,4 +978,9 @@ void Edit3DView::dropAsset(const QString &file, const QPointF &pos)
emitView3DAction(View3DActionType::GetNodeAtPos, pos);
}
+bool Edit3DView::isBakingLightsSupported() const
+{
+ return m_isBakingLightsSupported;
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dview.h b/src/plugins/qmldesigner/components/edit3d/edit3dview.h
index 2b746cf1af7..cd3e686d3bb 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dview.h
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dview.h
@@ -22,8 +22,10 @@ QT_END_NAMESPACE
namespace QmlDesigner {
+class BakeLights;
class Edit3DWidget;
class Edit3DAction;
+class Edit3DBakeLightsAction;
class Edit3DCameraAction;
class QMLDESIGNERCOMPONENTS_EXPORT Edit3DView : public AbstractView
@@ -42,7 +44,7 @@ public:
void updateActiveScene3D(const QVariantMap &sceneState) override;
void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
void nodeAtPosReady(const ModelNode &modelNode, const QVector3D &pos3d) override;
@@ -57,6 +59,7 @@ public:
QVector<Edit3DAction *> visibilityToggleActions() const;
QVector<Edit3DAction *> backgroundColorActions() const;
Edit3DAction *edit3DAction(View3DActionType type) const;
+ Edit3DBakeLightsAction *bakeLightsAction() const;
void addQuick3DImport();
void startContextMenu(const QPoint &pos);
@@ -66,6 +69,8 @@ public:
void dropComponent(const ItemLibraryEntry &entry, const QPointF &pos);
void dropAsset(const QString &file, const QPointF &pos);
+ bool isBakingLightsSupported() const;
+
private slots:
void onEntriesChanged();
@@ -122,6 +127,7 @@ private:
Edit3DAction *m_visibilityTogglesAction = nullptr;
Edit3DAction *m_backgrondColorMenuAction = nullptr;
Edit3DAction *m_seekerAction = nullptr;
+ Edit3DBakeLightsAction *m_bakeLightsAction = nullptr;
int particlemode;
ModelCache<QImage> m_canvasCache;
ModelNode m_droppedModelNode;
@@ -130,6 +136,8 @@ private:
NodeAtPosReqType m_nodeAtPosReqType;
QPoint m_contextMenuPos;
QTimer m_compressionTimer;
+ QPointer<BakeLights> m_bakeLights;
+ bool m_isBakingLightsSupported = false;
friend class Edit3DAction;
};
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
index 408584e166b..a217e396d9c 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.cpp
@@ -261,6 +261,12 @@ void Edit3DWidget::createContextMenu()
view()->emitView3DAction(View3DActionType::AlignViewToCamera, true);
});
+ m_bakeLightsAction = m_contextMenu->addAction(
+ contextIcon(DesignerIcons::LightIcon), // TODO: placeholder icon
+ tr("Bake Lights"), [&] {
+ view()->bakeLightsAction()->action()->trigger();
+ });
+
m_contextMenu->addSeparator();
m_selectParentAction = m_contextMenu->addAction(
@@ -466,6 +472,8 @@ void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode
m_alignViewAction->setEnabled(isCamera);
m_selectParentAction->setEnabled(selectionExcludingRoot);
m_toggleGroupAction->setEnabled(true);
+ m_bakeLightsAction->setVisible(view()->bakeLightsAction()->action()->isVisible());
+ m_bakeLightsAction->setEnabled(view()->bakeLightsAction()->action()->isEnabled());
m_contextMenu->popup(mapToGlobal(pos));
}
diff --git a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h
index 092abd313a5..eecd52345fa 100644
--- a/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h
+++ b/src/plugins/qmldesigner/components/edit3d/edit3dwidget.h
@@ -75,6 +75,7 @@ private:
QPointer<QMenu> m_visibilityTogglesMenu;
QPointer<QMenu> m_backgroundColorMenu;
QPointer<QMenu> m_contextMenu;
+ QPointer<QAction> m_bakeLightsAction;
QPointer<QAction> m_editComponentAction;
QPointer<QAction> m_editMaterialAction;
QPointer<QAction> m_duplicateAction;
diff --git a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
index 86951866058..9a51c9f3722 100644
--- a/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/dragtool.cpp
@@ -77,8 +77,6 @@ void DragTool::createQmlItemNode(const ItemLibraryEntry &itemLibraryEntry,
const QmlItemNode &parentNode,
const QPointF &scenePosition)
{
- MetaInfo metaInfo = MetaInfo::global();
-
FormEditorItem *parentItem = scene()->itemForQmlItemNode(parentNode);
const QPointF positonInItemSpace = parentItem->qmlItemNode().instanceSceneContentItemTransform().inverted().map(scenePosition);
QPointF itemPos = positonInItemSpace;
@@ -107,8 +105,6 @@ void DragTool::createQmlItemNodeFromImage(const QString &imagePath,
const QPointF &scenePosition)
{
if (parentNode.isValid()) {
- MetaInfo metaInfo = MetaInfo::global();
-
FormEditorItem *parentItem = scene()->itemForQmlItemNode(parentNode);
QPointF positonInItemSpace = parentItem->qmlItemNode().instanceSceneContentItemTransform().inverted().map(scenePosition);
@@ -121,8 +117,6 @@ void DragTool::createQmlItemNodeFromFont(const QString &fontPath,
const QPointF &scenePos)
{
if (parentNode.isValid()) {
- MetaInfo metaInfo = MetaInfo::global();
-
FormEditorItem *parentItem = scene()->itemForQmlItemNode(parentNode);
QPointF positonInItemSpace = parentItem->qmlItemNode().instanceSceneContentItemTransform()
.inverted().map(scenePos);
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
index 1f4d5262852..5661e4ff793 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp
@@ -253,7 +253,7 @@ void FormEditorView::modelAboutToBeDetached(Model *model)
AbstractView::modelAboutToBeDetached(model);
}
-void FormEditorView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/)
+void FormEditorView::importsChanged(const Imports &/*addedImports*/, const Imports &/*removedImports*/)
{
reset();
}
diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.h b/src/plugins/qmldesigner/components/formeditor/formeditorview.h
index fde20427628..f97959acb37 100644
--- a/src/plugins/qmldesigner/components/formeditor/formeditorview.h
+++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.h
@@ -48,7 +48,7 @@ public:
void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void nodeCreated(const ModelNode &createdNode) override;
void nodeAboutToBeRemoved(const ModelNode &removedNode) override;
diff --git a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp
index acd0b7401b0..47a9503b2d3 100644
--- a/src/plugins/qmldesigner/components/formeditor/toolbox.cpp
+++ b/src/plugins/qmldesigner/components/formeditor/toolbox.cpp
@@ -20,6 +20,8 @@ ToolBox::ToolBox(QWidget *parentWidget)
, m_rightToolBar(new QToolBar(QLatin1String("RightSidebar"), this))
{
Utils::StyleHelper::setPanelWidget(this, false);
+ Utils::StyleHelper::setPanelWidgetSingleRow(this, false);
+ setFixedHeight(Theme::toolbarSize());
m_leftToolBar->setFloatable(true);
m_leftToolBar->setMovable(true);
@@ -29,8 +31,6 @@ ToolBox::ToolBox(QWidget *parentWidget)
horizontalLayout->setContentsMargins(0, 0, 0, 0);
horizontalLayout->setSpacing(0);
- setFixedHeight(Theme::toolbarSize());
-
Utils::StyleHelper::setPanelWidget(m_leftToolBar, false);
Utils::StyleHelper::setPanelWidgetSingleRow(m_leftToolBar, false);
m_leftToolBar->setFixedHeight(Theme::toolbarSize());
diff --git a/src/plugins/qmldesigner/components/integration/designdocumentview.cpp b/src/plugins/qmldesigner/components/integration/designdocumentview.cpp
index a587580590d..4a1c92ad0aa 100644
--- a/src/plugins/qmldesigner/components/integration/designdocumentview.cpp
+++ b/src/plugins/qmldesigner/components/integration/designdocumentview.cpp
@@ -115,6 +115,7 @@ QString DesignDocumentView::toText() const
QScopedPointer<RewriterView> rewriterView(
new RewriterView(externalDependencies(), RewriterView::Amend));
rewriterView->setCheckSemanticErrors(false);
+ rewriterView->setPossibleImportsEnabled(false);
rewriterView->setTextModifier(&modifier);
outputModel->setRewriterView(rewriterView.data());
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.cpp
index 5b46c1d12ef..41a9c6b5f4a 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.cpp
@@ -56,14 +56,14 @@ QHash<int, QByteArray> ItemLibraryAddImportModel::roleNames() const
return m_roleNames;
}
-void ItemLibraryAddImportModel::update(const QList<Import> &possibleImports)
+void ItemLibraryAddImportModel::update(const Imports &possibleImports)
{
beginResetModel();
m_importList.clear();
const DesignerMcuManager &mcuManager = DesignerMcuManager::instance();
const bool isQtForMCUs = mcuManager.isMCUProject();
- QList<Import> filteredImports;
+ Imports filteredImports;
if (isQtForMCUs) {
const QStringList mcuAllowedList = mcuManager.allowedImports();
const QStringList mcuBannedList = mcuManager.bannedImports();
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.h
index 5785b67301a..2989fd51642 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryaddimportmodel.h
@@ -24,7 +24,7 @@ public:
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
- void update(const QList<Import> &possibleImports);
+ void update(const Imports &possibleImports);
void setSearchText(const QString &searchText);
Import getImportAt(int index) const;
@@ -33,7 +33,7 @@ public:
private:
QString m_searchText;
- QList<Import> m_importList;
+ Imports m_importList;
QSet<QString> m_importFilterList;
QHash<int, QByteArray> m_roleNames;
QSet<QString> m_priorityImports;
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
index 635a248152d..d141b88dc85 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.cpp
@@ -14,6 +14,8 @@
#include "rewritingexception.h"
#include "viewmanager.h"
+#include <model/modelutils.h>
+
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <utils/algorithm.h>
@@ -300,7 +302,7 @@ bool ItemLibraryAssetImporter::preParseQuick3DAsset(const QString &file, ParseDa
if (exitVal == QDialog::Accepted)
overwriteFiles = dlg.selectedFiles();
if (!overwriteFiles.isEmpty()) {
- overwriteFiles.append(Utils::toList(alwaysOverwrite));
+ overwriteFiles.append(::Utils::toList(alwaysOverwrite));
m_overwrittenImports.insert(pd.targetDirPath, overwriteFiles);
} else {
addWarning(tr("No files selected for overwrite, skipping import: \"%1\".").arg(pd.assetName));
@@ -359,9 +361,8 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd)
qmlInfo.append(".");
qmlInfo.append(pd.assetName);
qmlInfo.append('\n');
- m_requiredImports.append(Import::createLibraryImport(
- QStringLiteral("%1.%2").arg(pd.targetDir.dirName(),
- pd.assetName), version));
+ m_requiredImports.append(
+ QStringLiteral("%1.%2").arg(pd.targetDir.dirName(), pd.assetName));
while (qmlIt.hasNext()) {
qmlIt.next();
QFileInfo fi = QFileInfo(qmlIt.filePath());
@@ -417,11 +418,8 @@ void ItemLibraryAssetImporter::postParseQuick3DAsset(ParseData &pd)
}
// Add quick3D import unless it is already added
- if (impVersionMajor > 0
- && m_requiredImports.first().url() != "QtQuick3D") {
- m_requiredImports.prepend(Import::createLibraryImport(
- "QtQuick3D", impVersionStr));
- }
+ if (impVersionMajor > 0 && m_requiredImports.first() != "QtQuick3D")
+ m_requiredImports.prepend("QtQuick3D");
}
if (impVersionMajor > 0 && impVersionMajor < 6) {
pd.iconFile = iconFileName;
@@ -683,66 +681,42 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport()
QFuture<void> result;
if (modelManager) {
QmlJS::PathsAndLanguages pathToScan;
- pathToScan.maybeInsert(Utils::FilePath::fromString(m_importPath));
- result = Utils::asyncRun(&QmlJS::ModelManagerInterface::importScan,
- modelManager->workingCopy(), pathToScan,
- modelManager, true, true, true);
+ pathToScan.maybeInsert(::Utils::FilePath::fromString(m_importPath));
+ result = ::Utils::asyncRun(&QmlJS::ModelManagerInterface::importScan,
+ modelManager->workingCopy(),
+ pathToScan,
+ modelManager,
+ true,
+ true,
+ true);
}
// First we have to wait a while to ensure qmljs detects new files and updates its
- // internal model. Then we make a non-change to the document to trigger qmljs snapshot
- // update. There is an inbuilt delay before rewriter change actually updates the data
- // model, so we need to wait for another moment to allow the change to take effect.
- // Otherwise subsequent subcomponent manager update won't detect new imports properly.
+ // internal model. Then we force amend on rewriter to trigger qmljs snapshot update.
QTimer *timer = new QTimer(parent());
static int counter;
counter = 0;
timer->callOnTimeout([this, timer, progressTitle, model, result]() {
if (!isCancelled()) {
- notifyProgress(++counter, progressTitle);
- if (counter < 50) {
+ notifyProgress(++counter * 2, progressTitle);
+ if (counter < 49) {
if (result.isCanceled() || result.isFinished())
- counter = 49; // skip to next step
- } else if (counter == 50) {
+ counter = 48; // skip to next step
+ } else if (counter == 49) {
QmlDesignerPlugin::instance()->documentManager().resetPossibleImports();
- model->rewriterView()->textModifier()->replace(0, 0, {});
- } else if (counter < 100) {
+ model->rewriterView()->forceAmend();
try {
- const QList<Import> posImports = model->possibleImports();
- const QList<Import> currentImports = model->imports();
- QList<Import> newImportsToAdd;
-
- for (auto &imp : std::as_const(m_requiredImports)) {
- const bool isPos = Utils::contains(posImports, [imp](const Import &posImp) {
- return posImp.url() == imp.url();
- });
- const bool isCur = Utils::contains(currentImports, [imp](const Import &curImp) {
- return curImp.url() == imp.url();
- });
- if (!(isPos || isCur))
- return;
- // Check again with 'contains' to ensure we insert latest version
- if (!currentImports.contains(imp))
- newImportsToAdd.append(imp);
- }
- if (counter == 99)
+ RewriterTransaction transaction = model->rewriterView()->beginRewriterTransaction(
+ QByteArrayLiteral("ItemLibraryAssetImporter::finalizeQuick3DImport"));
+ bool success = Utils::addImportsWithCheck(m_requiredImports, model);
+ if (!success)
addError(tr("Failed to insert import statement into qml document."));
- else
- counter = 99;
- if (!newImportsToAdd.isEmpty()) {
- RewriterTransaction transaction
- = model->rewriterView()->beginRewriterTransaction(
- QByteArrayLiteral("ItemLibraryAssetImporter::finalizeQuick3DImport"));
-
- model->changeImports(newImportsToAdd, {});
- transaction.commit();
- }
+ transaction.commit();
} catch (const RewritingException &e) {
addError(tr("Failed to update imports: %1").arg(e.description()));
- counter = 99;
}
- } else if (counter >= 100) {
+ } else if (counter >= 50) {
if (!m_overwrittenImports.isEmpty())
model->rewriterView()->emitCustomNotification("asset_import_update");
timer->stop();
@@ -752,7 +726,7 @@ void ItemLibraryAssetImporter::finalizeQuick3DImport()
timer->stop();
}
});
- timer->start(50);
+ timer->start(100);
} else {
notifyFinished();
}
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h
index c7952e9b8f6..a53f0c9de1b 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryassetimporter.h
@@ -107,7 +107,7 @@ private:
int m_currentImportId = 0;
QHash<int, ParseData> m_parseData;
QString m_progressTitle;
- QList<Import> m_requiredImports;
+ QStringList m_requiredImports;
QList<int> m_puppetQueue;
};
} // QmlDesigner
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp
index cdaa3e28a9c..304aa5716ff 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryiconimageprovider.cpp
@@ -20,7 +20,7 @@ QQuickImageResponse *ItemLibraryIconImageProvider::requestImageResponse(const QS
Utils::StyleHelper::dpiSpecificImageFile(":/ItemLibrary/images/item-default-icon.png")});
m_cache.requestSmallImage(
- id,
+ Utils::PathString{id},
[response = QPointer<ImageCacheImageResponse>(response.get())](const QImage &image) {
QMetaObject::invokeMethod(
response,
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp
index 96b95f7949a..21f2e6aa55d 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.cpp
@@ -304,28 +304,6 @@ Import ItemLibraryModel::entryToImport(const ItemLibraryEntry &entry)
}
-// Returns true if first import version is higher or equal to second import version
-static bool compareVersions(const QString &version1, const QString &version2)
-{
- if (version2.isEmpty() || version1 == version2)
- return true;
- const QStringList version1List = version1.split(QLatin1Char('.'));
- const QStringList version2List = version2.split(QLatin1Char('.'));
- if (version1List.count() == 2 && version2List.count() == 2) {
- int major1 = version1List.constFirst().toInt();
- int major2 = version2List.constFirst().toInt();
- if (major1 > major2) {
- return true;
- } else if (major1 == major2) {
- int minor1 = version1List.constLast().toInt();
- int minor2 = version2List.constLast().toInt();
- if (minor1 >= minor2)
- return true;
- }
- }
- return false;
-}
-
void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
{
if (!model)
@@ -343,7 +321,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
materialBundlePrefix.append(".MaterialBundle");
// create import sections
- const QList<Import> usedImports = model->usedImports();
+ const Imports usedImports = model->usedImports();
QHash<QString, ItemLibraryImport *> importHash;
for (const Import &import : model->imports()) {
if (import.url() != projectName) {
@@ -363,7 +341,7 @@ void ItemLibraryModel::update(ItemLibraryInfo *itemLibraryInfo, Model *model)
addNew = false; // add only 1 Quick3DAssets import section
} else if (oldImport && oldImport->importEntry().url() == import.url()) {
// Retain the higher version if multiples exist
- if (compareVersions(oldImport->importEntry().version(), import.version()))
+ if (oldImport->importEntry().toVersion() >= import.toVersion() || import.hasVersion())
addNew = false;
else
delete oldImport;
@@ -550,7 +528,7 @@ ItemLibraryImport *ItemLibraryModel::importByUrl(const QString &importUrl) const
return nullptr;
}
-void ItemLibraryModel::updateUsedImports(const QList<Import> &usedImports)
+void ItemLibraryModel::updateUsedImports(const Imports &usedImports)
{
// imports in the excludeList are not marked used and thus can always be removed even when in use.
const QList<QString> excludeList = {"SimulinkConnector"};
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h
index 4e9c5809c12..212ddf8e040 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarymodel.h
@@ -38,7 +38,7 @@ public:
ItemLibraryImport *importByUrl(const QString &importName) const;
void update(ItemLibraryInfo *itemLibraryInfo, Model *model);
- void updateUsedImports(const QList<Import> &usedImports);
+ void updateUsedImports(const Imports &usedImports);
QMimeData *getMimeData(const ItemLibraryEntry &itemLibraryEntry);
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
index b5a0567114a..d370f6d4547 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.cpp
@@ -62,7 +62,7 @@ void ItemLibraryView::modelAttached(Model *model)
m_widget->setModel(model);
updateImports();
if (model)
- m_widget->updatePossibleImports(model->possibleImports());
+ m_widget->updatePossibleImports(difference(model->possibleImports(), model->imports()));
m_hasErrors = !rewriterView()->errors().isEmpty();
m_widget->setFlowMode(QmlItemNode(rootModelNode()).isFlowView());
}
@@ -74,13 +74,14 @@ void ItemLibraryView::modelAboutToBeDetached(Model *model)
m_widget->setModel(nullptr);
}
-void ItemLibraryView::importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports)
+void ItemLibraryView::importsChanged(const Imports &addedImports, const Imports &removedImports)
{
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
for (const auto &import : addedImports)
document->addSubcomponentManagerImport(import);
updateImports();
+ m_widget->updatePossibleImports(model()->possibleImports());
// TODO: generalize the logic below to allow adding/removing any Qml component when its import is added/removed
bool simulinkImportAdded = std::any_of(addedImports.cbegin(), addedImports.cend(), [](const Import &import) {
@@ -111,7 +112,7 @@ void ItemLibraryView::importsChanged(const QList<Import> &addedImports, const QL
}
}
-void ItemLibraryView::possibleImportsChanged(const QList<Import> &possibleImports)
+void ItemLibraryView::possibleImportsChanged(const Imports &possibleImports)
{
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
for (const auto &import : possibleImports)
@@ -120,7 +121,7 @@ void ItemLibraryView::possibleImportsChanged(const QList<Import> &possibleImport
m_widget->updatePossibleImports(possibleImports);
}
-void ItemLibraryView::usedImportsChanged(const QList<Import> &usedImports)
+void ItemLibraryView::usedImportsChanged(const Imports &usedImports)
{
m_widget->updateUsedImports(usedImports);
}
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h
index e28f39318c0..43287ae0e5a 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibraryview.h
@@ -26,9 +26,9 @@ public:
// AbstractView
void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
- void possibleImportsChanged(const QList<Import> &possibleImports) override;
- void usedImportsChanged(const QList<Import> &usedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
+ void possibleImportsChanged(const Imports &possibleImports) override;
+ void usedImportsChanged(const Imports &usedImports) override;
void documentMessagesChanged(const QList<DocumentMessage> &errors, const QList<DocumentMessage> &warnings) override;
void updateImport3DSupport(const QVariantMap &supportMap) override;
void customNotification(const AbstractView *view, const QString &identifier,
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
index 549f9e69c10..f98284f61d6 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.cpp
@@ -18,6 +18,7 @@
#include <itemlibrarymodel.h>
#include <metainfo.h>
#include <model.h>
+#include <model/modelutils.h>
#include <rewritingexception.h>
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
@@ -59,7 +60,7 @@ namespace QmlDesigner {
static QString propertyEditorResourcesPath()
{
#ifdef SHARE_QML_PATH
- if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
+ if (::Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
return QLatin1String(SHARE_QML_PATH) + "/propertyEditorQmlSources";
#endif
return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString();
@@ -80,26 +81,16 @@ bool ItemLibraryWidget::eventFilter(QObject *obj, QEvent *event)
ItemLibraryEntry entry = m_itemToDrag.value<ItemLibraryEntry>();
// For drag to be handled correctly, we must have the component properly imported
// beforehand, so we import the module immediately when the drag starts
- if (!entry.requiredImport().isEmpty()) {
- // We don't know if required import is library of file import, so try both.
- Import libImport = Import::createLibraryImport(entry.requiredImport());
- Import fileImport = Import::createFileImport(entry.requiredImport());
- if (!m_model->hasImport(libImport, true, true)
- && !m_model->hasImport(fileImport, true, true)) {
- const QList<Import> possImports = m_model->possibleImports();
- for (const auto &possImport : possImports) {
- if ((!possImport.url().isEmpty() && possImport.url() == libImport.url())
- || (!possImport.file().isEmpty() && possImport.file() == fileImport.file())) {
- m_model->changeImports({possImport}, {});
- break;
- }
- }
- }
+ if (!entry.requiredImport().isEmpty()
+ && !Utils::addImportWithCheck(entry.requiredImport(), m_model)) {
+ qWarning() << __FUNCTION__ << "Required import adding failed:"
+ << entry.requiredImport();
}
if (model) {
model->startDrag(m_itemLibraryModel->getMimeData(entry),
- Utils::StyleHelper::dpiSpecificImageFile(entry.libraryEntryIconPath()));
+ ::Utils::StyleHelper::dpiSpecificImageFile(
+ entry.libraryEntryIconPath()));
}
m_itemToDrag = {};
@@ -154,7 +145,7 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache)
updateSearch();
setStyleSheet(Theme::replaceCssColors(
- QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
+ QString::fromUtf8(::Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css"))));
m_qmlSourceUpdateShortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_F5), this);
connect(m_qmlSourceUpdateShortcut, &QShortcut::activated, this, &ItemLibraryWidget::reloadQmlSource);
@@ -176,10 +167,9 @@ ItemLibraryWidget::ItemLibraryWidget(AsynchronousImageCache &imageCache)
{"itemLibraryIconHeight", m_itemIconSize.height()},
{"rootView", QVariant::fromValue(this)},
{"widthLimit", HORIZONTAL_LAYOUT_WIDTH_LIMIT},
- {"highlightColor", Utils::StyleHelper::notTooBrightHighlightColor()},
+ {"highlightColor", ::Utils::StyleHelper::notTooBrightHighlightColor()},
{"tooltipBackend", QVariant::fromValue(m_previewTooltipBackend.get())}});
-
reloadQmlSource();
}
@@ -246,7 +236,7 @@ void ItemLibraryWidget::handleAddImport(int index)
+ importStr);
}
- QList<Import> imports;
+ Imports imports;
const QString dependency = getDependencyImport(import);
auto document = QmlDesignerPlugin::instance()->currentDesignDocument();
@@ -303,7 +293,7 @@ void ItemLibraryWidget::setModel(Model *model)
QString ItemLibraryWidget::qmlSourcesPath()
{
#ifdef SHARE_QML_PATH
- if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
+ if (::Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
return QLatin1String(SHARE_QML_PATH) + "/itemLibraryQmlSources";
#endif
return Core::ICore::resourcePath("qmldesigner/itemLibraryQmlSources").toString();
@@ -346,13 +336,13 @@ void ItemLibraryWidget::updateModel()
updateSearch();
}
-void ItemLibraryWidget::updatePossibleImports(const QList<Import> &possibleImports)
+void ItemLibraryWidget::updatePossibleImports(const Imports &possibleImports)
{
- m_addModuleModel->update(possibleImports);
+ m_addModuleModel->update(difference(possibleImports, m_model->imports()));
delayedUpdateModel();
}
-void ItemLibraryWidget::updateUsedImports(const QList<Import> &usedImports)
+void ItemLibraryWidget::updateUsedImports(const Imports &usedImports)
{
m_itemLibraryModel->updateUsedImports(usedImports);
}
@@ -368,7 +358,7 @@ void ItemLibraryWidget::handlePriorityImportsChanged()
{
if (!m_itemLibraryInfo.isNull()) {
m_addModuleModel->setPriorityImports(m_itemLibraryInfo->priorityImports());
- m_addModuleModel->update(m_model->possibleImports());
+ m_addModuleModel->update(difference(m_model->possibleImports(), m_model->imports()));
}
}
diff --git a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h
index 394b3ea6103..38cd782d097 100644
--- a/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h
+++ b/src/plugins/qmldesigner/components/itemlibrary/itemlibrarywidget.h
@@ -60,8 +60,8 @@ public:
void switchToComponentsView();
void delayedUpdateModel();
void updateModel();
- void updatePossibleImports(const QList<Import> &possibleImports);
- void updateUsedImports(const QList<Import> &usedImports);
+ void updatePossibleImports(const Imports &possibleImports);
+ void updateUsedImports(const Imports &usedImports);
void setModel(Model *model);
void setFlowMode(bool b);
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp
index 10b6660db57..4ed241abf98 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.cpp
@@ -51,6 +51,10 @@ QVariant MaterialBrowserTexturesModel::data(const QModelIndex &index, int role)
if (role == RoleTexInternalId)
return m_textureList.at(index.row()).internalId();
+ if (role == RoleTexId) {
+ return m_textureList.at(index.row()).id();
+ }
+
if (role == RoleTexToolTip) {
QString source = data(index, RoleTexSource).toString(); // absolute path
if (source.isEmpty())
@@ -88,6 +92,7 @@ QHash<int, QByteArray> MaterialBrowserTexturesModel::roleNames() const
static const QHash<int, QByteArray> roles {
{RoleTexHasDynamicProps, "hasDynamicProperties"},
{RoleTexInternalId, "textureInternalId"},
+ {RoleTexId, "textureId"},
{RoleTexSource, "textureSource"},
{RoleTexToolTip, "textureToolTip"},
{RoleTexVisible, "textureVisible"}
@@ -294,6 +299,21 @@ void MaterialBrowserTexturesModel::deleteTexture(int idx)
}
}
+void MaterialBrowserTexturesModel::setTextureId(int idx, const QString &newId)
+{
+ if (!isValidIndex(idx))
+ return;
+
+ ModelNode node = m_textureList[idx];
+ if (!node.isValid())
+ return;
+
+ if (node.id() != newId) {
+ node.setIdWithRefactoring(newId);
+ emit dataChanged(index(idx, 0), index(idx, 0), {RoleTexId});
+ }
+}
+
void MaterialBrowserTexturesModel::applyToSelectedMaterial(qint64 internalId)
{
int idx = m_textureIndexHash.value(internalId);
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h
index 6d66ad13ec5..9cb7c5ac18f 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowsertexturesmodel.h
@@ -55,6 +55,7 @@ public:
Q_INVOKABLE void addNewTexture();
Q_INVOKABLE void duplicateTexture(int idx);
Q_INVOKABLE void deleteTexture(int idx);
+ Q_INVOKABLE void setTextureId(int idx, const QString &newId);
Q_INVOKABLE void applyToSelectedMaterial(qint64 internalId);
Q_INVOKABLE void applyToSelectedModel(qint64 internalId);
Q_INVOKABLE void openTextureEditor();
@@ -91,6 +92,7 @@ private:
enum {
RoleTexHasDynamicProps = Qt::UserRole + 1,
RoleTexInternalId,
+ RoleTexId,
RoleTexSource,
RoleTexToolTip,
RoleTexVisible
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
index 5265c70683d..5349fc26ce7 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.cpp
@@ -264,12 +264,17 @@ void MaterialBrowserView::refreshModel(bool updateImages)
m_widget->materialBrowserTexturesModel()->setTextures(textures);
m_widget->materialBrowserModel()->setHasMaterialLibrary(matLib.isValid());
- if (updateImages) {
- for (const ModelNode &node : std::as_const(materials))
- m_previewRequests.insert(node);
- if (!m_previewRequests.isEmpty())
- m_previewTimer.start(0);
- }
+ if (updateImages)
+ updateMaterialsPreview();
+}
+
+void MaterialBrowserView::updateMaterialsPreview()
+{
+ const QList<ModelNode> materials = m_widget->materialBrowserModel()->materials();
+ for (const ModelNode &node : materials)
+ m_previewRequests.insert(node);
+ if (!m_previewRequests.isEmpty())
+ m_previewTimer.start(0);
}
bool MaterialBrowserView::isMaterial(const ModelNode &node) const
@@ -469,8 +474,8 @@ ModelNode MaterialBrowserView::getMaterialOfModel(const ModelNode &model, int id
return mat;
}
-void MaterialBrowserView::importsChanged([[maybe_unused]] const QList<Import> &addedImports,
- [[maybe_unused]] const QList<Import> &removedImports)
+void MaterialBrowserView::importsChanged([[maybe_unused]] const Imports &addedImports,
+ [[maybe_unused]] const Imports &removedImports)
{
bool hasQuick3DImport = model()->hasImport("QtQuick3D");
@@ -541,6 +546,7 @@ void MaterialBrowserView::active3DSceneChanged(qint32 sceneId)
void MaterialBrowserView::currentStateChanged([[maybe_unused]] const ModelNode &node)
{
m_widget->materialBrowserTexturesModel()->updateAllTexturesSources();
+ updateMaterialsPreview();
}
void MaterialBrowserView::instancesCompleted(const QVector<ModelNode> &completedNodeList)
diff --git a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h
index 811d6679b63..297487ae66f 100644
--- a/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h
+++ b/src/plugins/qmldesigner/components/materialbrowser/materialbrowserview.h
@@ -44,7 +44,7 @@ public:
void nodeAboutToBeRemoved(const ModelNode &removedNode) override;
void nodeRemoved(const ModelNode &removedNode, const NodeAbstractProperty &parentProperty,
PropertyChangeFlags propertyChange) override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
void instancesCompleted(const QVector<ModelNode> &completedNodeList) override;
@@ -66,6 +66,7 @@ protected:
private:
void refreshModel(bool updateImages);
+ void updateMaterialsPreview();
bool isMaterial(const ModelNode &node) const;
bool isTexture(const ModelNode &node) const;
void loadPropertyGroups();
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
index 47d47985ebd..96e01072904 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.cpp
@@ -38,6 +38,20 @@
#include <QShortcut>
#include <QColorDialog>
+namespace {
+QSize maxSize(const std::initializer_list<QSize> &sizeList)
+{
+ QSize result;
+ for (const QSize &size : sizeList) {
+ if (size.width() > result.width())
+ result.setWidth(size.width());
+ if (size.height() > result.height())
+ result.setHeight(size.height());
+ }
+ return result;
+}
+}
+
namespace QmlDesigner {
MaterialEditorView::MaterialEditorView(ExternalDependenciesInterface &externalDependencies)
@@ -64,7 +78,6 @@ MaterialEditorView::MaterialEditorView(ExternalDependenciesInterface &externalDe
m_typeUpdateTimer.setInterval(500);
connect(&m_typeUpdateTimer, &QTimer::timeout, this, &MaterialEditorView::updatePossibleTypes);
- m_stackedWidget->setMinimumWidth(250);
QmlDesignerPlugin::trackWidgetFocusTime(m_stackedWidget, Constants::EVENT_MATERIALEDITOR_TIME);
MaterialEditorDynamicPropertiesProxyModel::registerDeclarativeType();
@@ -594,6 +607,14 @@ void MaterialEditorView::setupQmlBackend()
initPreviewData();
m_stackedWidget->setCurrentWidget(m_qmlBackEnd->widget());
+ if (m_qmlBackEnd->widget()) {
+ m_stackedWidget->setMinimumSize(maxSize({m_qmlBackEnd->widget()->sizeHint(),
+ m_qmlBackEnd->widget()->initialSize(),
+ m_qmlBackEnd->widget()->minimumSizeHint(),
+ m_qmlBackEnd->widget()->minimumSize()}));
+ } else {
+ m_stackedWidget->setMinimumSize({400, 300});
+ }
}
void MaterialEditorView::commitVariantValueToModel(const PropertyName &propertyName, const QVariant &value)
@@ -974,8 +995,8 @@ void MaterialEditorView::modelNodePreviewPixmapChanged(const ModelNode &node, co
m_qmlBackEnd->updateMaterialPreview(pixmap);
}
-void MaterialEditorView::importsChanged([[maybe_unused]] const QList<Import> &addedImports,
- [[maybe_unused]] const QList<Import> &removedImports)
+void MaterialEditorView::importsChanged([[maybe_unused]] const Imports &addedImports,
+ [[maybe_unused]] const Imports &removedImports)
{
m_hasQuick3DImport = model()->hasImport("QtQuick3D");
m_qmlBackEnd->contextObject()->setHasQuick3DImport(m_hasQuick3DImport);
diff --git a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
index d47d030e57b..c201742bd51 100644
--- a/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
+++ b/src/plugins/qmldesigner/components/materialeditor/materialeditorview.h
@@ -55,7 +55,7 @@ public:
void nodeTypeChanged(const ModelNode& node, const TypeName &type, int majorVersion, int minorVersion) override;
void rootNodeTypeChanged(const QString &type, int majorVersion, int minorVersion) override;
void modelNodePreviewPixmapChanged(const ModelNode &node, const QPixmap &pixmap) override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent,
diff --git a/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp b/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp
index 35078859de0..91c300e87a2 100644
--- a/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp
+++ b/src/plugins/qmldesigner/components/navigator/choosefrompropertylistdialog.cpp
@@ -90,7 +90,7 @@ ChooseFromPropertyListFilter::ChooseFromPropertyListFilter(const NodeMetaInfo &i
} else if (insertInfo.isQtQuick3DParticles3DParticle3D()) {
if (parentInfo.isQtQuick3DParticles3DParticleEmitter3D())
propertyList.append("particle");
- } else if (insertInfo.isQuick3DParticleAbstractShape()) {
+ } else if (insertInfo.isQtQuick3DParticleAbstractShape()) {
if (parentInfo.isQtQuick3DParticles3DParticleEmitter3D()
|| parentInfo.isQtQuick3DParticles3DAttractor3D())
propertyList.append("shape");
diff --git a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
index 62868290285..16dd2242863 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatortreemodel.cpp
@@ -9,23 +9,24 @@
#include "qmldesignerplugin.h"
#include "assetslibrarywidget.h"
+#include <abstractview.h>
#include <bindingproperty.h>
+#include <coreplugin/icore.h>
+#include <designeractionmanager.h>
#include <designersettings.h>
+#include <import.h>
+#include <invalididexception.h>
+#include <materialutils.h>
+#include <metainfo.h>
+#include <model/modelutils.h>
#include <nodeabstractproperty.h>
#include <nodehints.h>
#include <nodelistproperty.h>
#include <nodeproperty.h>
-#include <variantproperty.h>
-#include <metainfo.h>
-#include <materialutils.h>
-#include <abstractview.h>
-#include <invalididexception.h>
#include <rewritingexception.h>
+#include <variantproperty.h>
#include <qmldesignerconstants.h>
#include <qmlitemnode.h>
-#include <designeractionmanager.h>
-#include <import.h>
-#include <coreplugin/icore.h>
#include <qmlprojectmanager/qmlproject.h>
@@ -210,7 +211,7 @@ QVariant NavigatorTreeModel::data(const QModelIndex &index, int role) const
return modelNode.displayName();
} else if (role == Qt::DecorationRole) {
if (currentQmlObjectNode.hasError())
- return Utils::Icons::WARNING.icon();
+ return ::Utils::Icons::WARNING.icon();
return modelNode.typeIcon();
@@ -314,14 +315,14 @@ QList<ModelNode> NavigatorTreeModel::filteredList(const NodeListProperty &proper
if (m_nameFilter.isEmpty()) {
nameFilteredList = propertyNodes;
} else {
- nameFilteredList.append(Utils::filtered(propertyNodes, [&] (const ModelNode &arg){
+ nameFilteredList.append(::Utils::filtered(propertyNodes, [&](const ModelNode &arg) {
const bool value = m_nameFilteredList.contains(arg);
return value;
}));
}
if (filter) {
- list.append(Utils::filtered(nameFilteredList, [] (const ModelNode &arg) {
+ list.append(::Utils::filtered(nameFilteredList, [](const ModelNode &arg) {
const bool value = (QmlItemNode::isValidQmlItemNode(arg) || NodeHints::fromModelNode(arg).visibleInNavigator())
&& arg.id() != Constants::MATERIAL_LIB_ID;
return value;
@@ -899,17 +900,8 @@ ModelNode NavigatorTreeModel::handleItemLibraryFontDrop(const QString &fontFamil
void NavigatorTreeModel::addImport(const QString &importName)
{
- Import import = Import::createLibraryImport(importName);
- if (!m_view->model()->hasImport(import, true, true)) {
- const QList<Import> possImports = m_view->model()->possibleImports();
- for (const auto &possImport : possImports) {
- if (possImport.url() == import.url()) {
- import = possImport;
- m_view->model()->changeImports({import}, {});
- break;
- }
- }
- }
+ if (!Utils::addImportWithCheck(importName, m_view->model()))
+ qWarning() << __FUNCTION__ << "Adding import failed:" << importName;
}
bool QmlDesigner::NavigatorTreeModel::moveNodeToParent(const NodeAbstractProperty &targetProperty,
@@ -1268,12 +1260,12 @@ static QList<ModelNode> collectParents(const QList<ModelNode> &modelNodes)
}
}
- return Utils::toList(parents);
+ return ::Utils::toList(parents);
}
QList<QPersistentModelIndex> NavigatorTreeModel::nodesToPersistentIndex(const QList<ModelNode> &modelNodes)
{
- return Utils::transform(modelNodes, [this](const ModelNode &modelNode) {
+ return ::Utils::transform(modelNodes, [this](const ModelNode &modelNode) {
return QPersistentModelIndex(indexForModelNode(modelNode));
});
}
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
index 38e6b9ada75..f1a00a36c7c 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
+++ b/src/plugins/qmldesigner/components/navigator/navigatorview.cpp
@@ -228,7 +228,7 @@ void NavigatorView::modelAboutToBeDetached(Model *model)
AbstractView::modelAboutToBeDetached(model);
}
-void NavigatorView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/)
+void NavigatorView::importsChanged(const Imports &/*addedImports*/, const Imports &/*removedImports*/)
{
treeWidget()->update();
}
diff --git a/src/plugins/qmldesigner/components/navigator/navigatorview.h b/src/plugins/qmldesigner/components/navigator/navigatorview.h
index f5fa81591d9..662b749ecec 100644
--- a/src/plugins/qmldesigner/components/navigator/navigatorview.h
+++ b/src/plugins/qmldesigner/components/navigator/navigatorview.h
@@ -50,7 +50,7 @@ public:
void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void nodeAboutToBeRemoved(const ModelNode &removedNode) override;
void nodeRemoved(const ModelNode &removedNode, const NodeAbstractProperty &parentProperty, PropertyChangeFlags propertyChange) override;
diff --git a/src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp b/src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp
index 550ff8fcaf9..16328ae532f 100644
--- a/src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp
+++ b/src/plugins/qmldesigner/components/previewtooltip/previewtooltipbackend.cpp
@@ -32,8 +32,9 @@ void PreviewTooltipBackend::showTooltip()
m_tooltip->setInfo(m_info);
m_cache.requestImage(
- m_path,
- [tooltip = QPointer<PreviewImageTooltip>(m_tooltip.get()), scaleImage = m_scaleImage](const QImage &image) {
+ Utils::PathString{m_path},
+ [tooltip = QPointer<PreviewImageTooltip>(m_tooltip.get()),
+ scaleImage = m_scaleImage](const QImage &image) {
QMetaObject::invokeMethod(tooltip, [tooltip, image, scaleImage] {
if (tooltip) {
tooltip->setImage(image, scaleImage);
@@ -42,7 +43,7 @@ void PreviewTooltipBackend::showTooltip()
});
},
[](auto) {},
- m_extraId,
+ Utils::PathString{m_extraId},
m_auxiliaryData);
reposition();
diff --git a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp
index 75b9f34cefd..a81560f5662 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/gradientmodel.cpp
@@ -29,14 +29,13 @@ GradientModel::GradientModel(QObject *parent) :
int GradientModel::rowCount(const QModelIndex & /*parent*/) const
{
- if (m_itemNode.isValid()) {
- if (m_itemNode.modelNode().hasNodeProperty(gradientPropertyName().toUtf8())) {
- QmlDesigner::ModelNode gradientNode =
- m_itemNode.modelNode().nodeProperty(gradientPropertyName().toUtf8()).modelNode();
+ if (m_itemNode.modelNode().hasNodeProperty(gradientPropertyName().toUtf8())) {
+ QmlDesigner::ModelNode gradientNode = m_itemNode.modelNode()
+ .nodeProperty(gradientPropertyName().toUtf8())
+ .modelNode();
- if (gradientNode.hasNodeListProperty("stops"))
- return gradientNode.nodeListProperty("stops").toModelNodeList().count();
- }
+ if (gradientNode.hasNodeListProperty("stops"))
+ return gradientNode.nodeListProperty("stops").count();
}
return 0;
diff --git a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp
index d52e47c3678..c5d9a23d7ea 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp
+++ b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.cpp
@@ -7,7 +7,7 @@
#include <model.h>
#include <nodemetainfo.h>
#include <qmlmodelnodeproxy.h>
-#include "variantproperty.h"
+#include <variantproperty.h>
#include <QFileDialog>
#include <QDirIterator>
@@ -15,24 +15,14 @@
using namespace QmlDesigner;
-QHash<int, QByteArray> ItemFilterModel::m_roles;
-
ItemFilterModel::ItemFilterModel(QObject *parent)
: QAbstractListModel(parent)
, m_typeFilter("QtQuick.Item")
, m_selectionOnly(false)
-{
- if (m_roles.empty()) {
- m_roles = QAbstractListModel::roleNames();
- QMetaEnum roleEnum = QMetaEnum::fromType<Roles>();
- for (int i = 0; i < roleEnum.keyCount(); i++)
- m_roles.insert(roleEnum.value(i), roleEnum.key(i));
- }
-}
+{}
void ItemFilterModel::setModelNodeBackend(const QVariant &modelNodeBackend)
{
-
auto modelNodeBackendObject = modelNodeBackend.value<QObject*>();
const auto backendObjectCasted =
@@ -47,18 +37,28 @@ void ItemFilterModel::setModelNodeBackend(const QVariant &modelNodeBackend)
void ItemFilterModel::setTypeFilter(const QString &filter)
{
- if (m_typeFilter != filter) {
- m_typeFilter = filter;
- setupModel();
- }
+ if (m_typeFilter == filter)
+ return;
+
+ m_typeFilter = filter;
+ setupModel();
+ emit typeFilterChanged();
}
void ItemFilterModel::setSelectionOnly(bool value)
{
- if (m_selectionOnly != value) {
- m_selectionOnly = value;
- setupModel();
- }
+ if (m_selectionOnly == value)
+ return;
+
+ m_selectionOnly = value;
+ setupModel();
+ emit selectionOnlyChanged();
+}
+
+void ItemFilterModel::setSelectedItems(const QStringList &selectedItems)
+{
+ m_selectedItems = selectedItems;
+ emit selectedItemsChanged();
}
QString ItemFilterModel::typeFilter() const
@@ -71,14 +71,14 @@ bool ItemFilterModel::selectionOnly() const
return m_selectionOnly;
}
-void ItemFilterModel::registerDeclarativeType()
+QStringList ItemFilterModel::selectedItems() const
{
- qmlRegisterType<ItemFilterModel>("HelperWidgets",2,0,"ItemFilterModel");
+ return m_selectedItems;
}
-QModelIndex ItemFilterModel::index(int row, int column, const QModelIndex &parent) const
+void ItemFilterModel::registerDeclarativeType()
{
- return QAbstractListModel::index(row, column, parent);
+ qmlRegisterType<ItemFilterModel>("HelperWidgets", 2, 0, "ItemFilterModel");
}
int ItemFilterModel::rowCount(const QModelIndex &) const
@@ -88,41 +88,34 @@ int ItemFilterModel::rowCount(const QModelIndex &) const
QVariant ItemFilterModel::data(const QModelIndex &index, int role) const
{
- if (!index.isValid())
+ if (!index.isValid() || index.row() >= rowCount())
return {};
- ModelNode node = modelNodeForRow(index.row());
+ const ModelNode node = modelNodeForRow(index.row());
- QVariant value;
switch (role) {
case IdRole:
- value = node.id();
- break;
+ return node.id();
case NameRole:
- value = node.variantProperty("objectName").value();
- break;
+ return node.variantProperty("objectName").value();
case IdAndNameRole:
- value = QString("%1 [%2]").arg(
- node.variantProperty("objectName").value().toString()
- ,node.id());
- break;
+ return QString("%1 [%2]").arg(node.variantProperty("objectName").value().toString(),
+ node.id());
+ case EnabledRole:
+ return !m_selectedItems.contains(node.id());
default:
- value = node.id();
- break;
+ return {};
}
-
- return value;
-}
-
-// TODO: Handle model data manipulation here.
-bool ItemFilterModel::setData(const QModelIndex &index, const QVariant &value, int role)
-{
- return QAbstractListModel::setData(index, value, role);
}
QHash<int, QByteArray> ItemFilterModel::roleNames() const
{
- return m_roles;
+ static QHash<int, QByteArray> roleNames{{IdRole, "id"},
+ {NameRole, "name"},
+ {IdAndNameRole, "idAndName"},
+ {EnabledRole, "enabled"}};
+
+ return roleNames;
}
QVariant ItemFilterModel::modelNodeBackend() const
diff --git a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h
index 6876f1edffd..cb7ae131778 100644
--- a/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h
+++ b/src/plugins/qmldesigner/components/propertyeditor/itemfiltermodel.h
@@ -16,43 +16,43 @@ class ItemFilterModel : public QAbstractListModel
{
Q_OBJECT
- Q_PROPERTY(QString typeFilter READ typeFilter WRITE setTypeFilter)
- Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend NOTIFY modelNodeBackendChanged)
+ Q_PROPERTY(QString typeFilter READ typeFilter WRITE setTypeFilter NOTIFY typeFilterChanged)
+ Q_PROPERTY(QVariant modelNodeBackendProperty READ modelNodeBackend WRITE setModelNodeBackend
+ NOTIFY modelNodeBackendChanged)
Q_PROPERTY(QStringList itemModel READ itemModel NOTIFY itemModelChanged)
- Q_PROPERTY(bool selectionOnly READ selectionOnly WRITE setSelectionOnly NOTIFY selectionOnlyChanged)
+ Q_PROPERTY(
+ bool selectionOnly READ selectionOnly WRITE setSelectionOnly NOTIFY selectionOnlyChanged)
+ Q_PROPERTY(QStringList selectedItems READ selectedItems WRITE setSelectedItems NOTIFY
+ selectedItemsChanged)
public:
- enum Roles {
- IdRole = Qt::UserRole + 1,
- NameRole,
- IdAndNameRole
- };
- Q_ENUM(Roles)
+ enum { IdRole = Qt::DisplayRole, NameRole = Qt::UserRole, IdAndNameRole, EnabledRole };
explicit ItemFilterModel(QObject *parent = nullptr);
void setModelNodeBackend(const QVariant &modelNodeBackend);
void setTypeFilter(const QString &typeFilter);
void setSelectionOnly(bool value);
+ void setSelectedItems(const QStringList &selectedItems);
QString typeFilter() const;
bool selectionOnly() const;
+ QStringList selectedItems() const;
void setupModel();
QStringList itemModel() const;
static void registerDeclarativeType();
- // Make index accessible for Qml side since it's not accessible by default in QAbstractListModel
- Q_INVOKABLE QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
- Q_INVOKABLE virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
- Q_INVOKABLE virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
- Q_INVOKABLE virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
- virtual QHash<int,QByteArray> roleNames() const override;
+ virtual QHash<int, QByteArray> roleNames() const override;
signals:
+ void typeFilterChanged();
void modelNodeBackendChanged();
void itemModelChanged();
void selectionOnlyChanged();
+ void selectedItemsChanged();
private:
QVariant modelNodeBackend() const;
@@ -63,7 +63,7 @@ private:
QList<qint32> m_modelInternalIds;
QmlDesigner::ModelNode m_modelNode;
bool m_selectionOnly;
- static QHash<int, QByteArray> m_roles;
+ QStringList m_selectedItems;
};
QML_DECLARE_TYPE(ItemFilterModel)
diff --git a/src/plugins/qmldesigner/components/resources/dockwidgets.css b/src/plugins/qmldesigner/components/resources/dockwidgets.css
index 3404065521e..4ff1b46f52d 100644
--- a/src/plugins/qmldesigner/components/resources/dockwidgets.css
+++ b/src/plugins/qmldesigner/components/resources/dockwidgets.css
@@ -113,40 +113,6 @@ QScrollArea#dockWidgetScrollArea {
background: creatorTheme.DStabInactiveButtonPress;
}
-QScrollBar {
- background: creatorTheme.DSscrollBarTrack;
-}
-
-QScrollBar:vertical {
- width: 10px;
-}
-
-QScrollBar:horizontal {
- height: 10px;
-}
-
-QScrollBar::handle {
- background: creatorTheme.DSscrollBarHandle;
-}
-
-QScrollBar::handle:vertical {
- min-height: 30px;
-}
-
-QScrollBar::handle:horizontal {
- min-width: 30px;
-}
-
-QScrollBar::add-line,
-QScrollBar::sub-line,
-QScrollBar::left-arrow,
-QScrollBar::right-arrow,
-QScrollBar::add-page,
-QScrollBar::sub-page {
- height: 0px;
- width: 0px;
-}
-
/* Focus related styling */
ADS--DockWidgetTab[focused="true"] {
background: creatorTheme.DStabFocusBackground;
diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp
index a7ada80ed73..6c6102036ac 100644
--- a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp
+++ b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp
@@ -27,10 +27,11 @@
#include <texteditor/texteditorconstants.h>
#include <qmljseditor/qmljseditordocument.h>
-#include <qmljs/qmljsmodelmanagerinterface.h>
-#include <qmljs/qmljsreformatter.h>
#include <utils/changeset.h>
#include <utils/qtcassert.h>
+#include <utils/uniqueobjectptr.h>
+#include <qmljs/qmljsmodelmanagerinterface.h>
+#include <qmljs/qmljsreformatter.h>
#include <QDebug>
#include <QPair>
@@ -78,15 +79,15 @@ void TextEditorView::modelAttached(Model *model)
AbstractView::modelAttached(model);
- auto textEditor = qobject_cast<TextEditor::BaseTextEditor *>(
- QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor()->duplicate());
+ auto textEditor = Utils::UniqueObjectLatePtr<TextEditor::BaseTextEditor>(
+ QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor()->duplicate());
// Set the context of the text editor, but we add another special context to override shortcuts.
Core::Context context = textEditor->context();
context.prepend(TEXTEDITOR_CONTEXT_ID);
m_textEditorContext->setContext(context);
- m_widget->setTextEditor(textEditor);
+ m_widget->setTextEditor(std::move(textEditor));
}
void TextEditorView::modelAboutToBeDetached(Model *model)
@@ -102,7 +103,7 @@ void TextEditorView::modelAboutToBeDetached(Model *model)
}
}
-void TextEditorView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/)
+void TextEditorView::importsChanged(const Imports &/*addedImports*/, const Imports &/*removedImports*/)
{
}
diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorview.h b/src/plugins/qmldesigner/components/texteditor/texteditorview.h
index b1865e78f9f..e50372279d9 100644
--- a/src/plugins/qmldesigner/components/texteditor/texteditorview.h
+++ b/src/plugins/qmldesigner/components/texteditor/texteditorview.h
@@ -34,7 +34,7 @@ public:
void modelAttached(Model *model) override;
void modelAboutToBeDetached(Model *model) override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void nodeAboutToBeRemoved(const ModelNode &removedNode) override;
void nodeReparented(const ModelNode &node, const NodeAbstractProperty &newPropertyParent, const NodeAbstractProperty &oldPropertyParent, AbstractView::PropertyChangeFlags propertyChange) override;
diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
index 1529c0a87c1..9f4bb59231e 100644
--- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
+++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include "texteditorwidget.h"
+#include "utils/uniqueobjectptr.h"
#include <texteditorstatusbar.h>
#include <texteditorview.h>
@@ -51,34 +52,30 @@ TextEditorWidget::TextEditorWidget(TextEditorView *textEditorView)
QmlDesignerPlugin::trackWidgetFocusTime(this, Constants::EVENT_TEXTEDITOR_TIME);
}
-void TextEditorWidget::setTextEditor(TextEditor::BaseTextEditor *textEditor)
+void TextEditorWidget::setTextEditor(Utils::UniqueObjectLatePtr<TextEditor::BaseTextEditor> textEditor)
{
- TextEditor::BaseTextEditor *oldEditor = m_textEditor.release();
- m_textEditor.reset(textEditor);
+ std::swap(m_textEditor, textEditor);
- if (textEditor) {
- m_layout->insertWidget(0, textEditor->editorWidget());
+ if (m_textEditor) {
+ m_layout->insertWidget(0, m_textEditor->editorWidget());
- setFocusProxy(textEditor->editorWidget());
+ setFocusProxy(m_textEditor->editorWidget());
- QmlDesignerPlugin::instance()->emitCurrentTextEditorChanged(textEditor);
+ QmlDesignerPlugin::instance()->emitCurrentTextEditorChanged(m_textEditor.get());
- connect(textEditor->editorWidget(), &QPlainTextEdit::cursorPositionChanged, this, [this] {
+ connect(m_textEditor->editorWidget(), &QPlainTextEdit::cursorPositionChanged, this, [this] {
// Cursor position is changed by rewriter
if (!m_blockCursorSelectionSynchronisation)
m_updateSelectionTimer.start();
});
- textEditor->editorWidget()->installEventFilter(this);
+ m_textEditor->editorWidget()->installEventFilter(this);
static QString styleSheet = Theme::replaceCssColors(
QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css")));
- textEditor->editorWidget()->verticalScrollBar()->setStyleSheet(styleSheet);
- textEditor->editorWidget()->horizontalScrollBar()->setStyleSheet(styleSheet);
+ m_textEditor->editorWidget()->verticalScrollBar()->setStyleSheet(styleSheet);
+ m_textEditor->editorWidget()->horizontalScrollBar()->setStyleSheet(styleSheet);
}
-
- if (oldEditor)
- oldEditor->deleteLater();
}
void TextEditorWidget::contextHelp(const Core::IContext::HelpCallback &callback) const
diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h
index c5e5c4f5bc9..947826ab598 100644
--- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h
+++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h
@@ -3,6 +3,7 @@
#pragma once
#include <texteditor/texteditor.h>
+#include <utils/uniqueobjectptr.h>
#include <QTimer>
#include <QVBoxLayout>
@@ -25,7 +26,7 @@ class TextEditorWidget : public QWidget {
public:
TextEditorWidget(TextEditorView *textEditorView);
- void setTextEditor(TextEditor::BaseTextEditor *textEditor);
+ void setTextEditor(Utils::UniqueObjectLatePtr<TextEditor::BaseTextEditor> textEditor);
TextEditor::BaseTextEditor *textEditor() const
{
@@ -51,7 +52,7 @@ protected:
private:
void updateSelectionByCursorPosition();
- std::unique_ptr<TextEditor::BaseTextEditor> m_textEditor;
+ Utils::UniqueObjectLatePtr<TextEditor::BaseTextEditor> m_textEditor;
QPointer<TextEditorView> m_textEditorView;
QTimer m_updateSelectionTimer;
TextEditorStatusBar *m_statusBar = nullptr;
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp
index 38664c146e4..a4132d0eb7a 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.cpp
@@ -720,8 +720,8 @@ void TextureEditorView::instancePropertyChanged(const QList<QPair<ModelNode, Pro
m_locked = false;
}
-void TextureEditorView::importsChanged([[maybe_unused]] const QList<Import> &addedImports,
- [[maybe_unused]] const QList<Import> &removedImports)
+void TextureEditorView::importsChanged([[maybe_unused]] const Imports &addedImports,
+ [[maybe_unused]] const Imports &removedImports)
{
m_hasQuick3DImport = model()->hasImport("QtQuick3D");
m_qmlBackEnd->contextObject()->setHasQuick3DImport(m_hasQuick3DImport);
diff --git a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h
index b299a1e99ae..7baa07e9d30 100644
--- a/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h
+++ b/src/plugins/qmldesigner/components/textureeditor/textureeditorview.h
@@ -58,7 +58,7 @@ public:
void currentStateChanged(const ModelNode &node) override;
void instancePropertyChanged(const QList<QPair<ModelNode, PropertyName> > &propertyList) override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void customNotification(const AbstractView *view, const QString &identifier,
const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
diff --git a/src/plugins/qmldesigner/components/toolbar/toolbar.cpp b/src/plugins/qmldesigner/components/toolbar/toolbar.cpp
index 3326c889ad5..e4f523c55cc 100644
--- a/src/plugins/qmldesigner/components/toolbar/toolbar.cpp
+++ b/src/plugins/qmldesigner/components/toolbar/toolbar.cpp
@@ -47,10 +47,10 @@ Utils::FilePath qmlSourcesPath()
return Core::ICore::resourcePath("qmldesigner/toolbar");
}
-void ToolBar::create()
+Utils::UniqueObjectPtr<QToolBar> ToolBar::create()
{
if (!isVisible())
- return;
+ return nullptr;
ToolBarBackend::registerDeclarativeType();
@@ -58,7 +58,7 @@ void ToolBar::create()
//Core::ICore::statusBar()->hide();
- auto toolBar = new QToolBar;
+ auto toolBar = Utils::makeUniqueObjectPtr<QToolBar>();
toolBar->setObjectName("QDS-TOOLBAR");
toolBar->setContextMenuPolicy(Qt::PreventContextMenu);
@@ -66,7 +66,7 @@ void ToolBar::create()
toolBar->setFloatable(false);
toolBar->setMovable(false);
- auto quickWidget = new StudioQuickWidget;
+ auto quickWidget = std::make_unique<StudioQuickWidget>();
quickWidget->setFixedHeight(48);
quickWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
@@ -78,24 +78,26 @@ void ToolBar::create()
quickWidget->engine()->addImportPath(propertyEditorResourcesPath().toString() + "/imports");
Utils::FilePath qmlFilePath = qmlSourcesPath() / "Main.qml";
- QTC_ASSERT(qmlFilePath.exists(), return);
+ QTC_ASSERT(qmlFilePath.exists(), return nullptr);
Theme::setupTheme(quickWidget->engine());
quickWidget->setSource(QUrl::fromLocalFile(qmlFilePath.toFSPathString()));
- toolBar->addWidget(quickWidget);
- window->addToolBar(toolBar);
+ toolBar->addWidget(quickWidget.release());
+ window->addToolBar(toolBar.get());
+
+ return toolBar;
}
-void ToolBar::createStatusBar()
+Utils::UniqueObjectPtr<QWidget> ToolBar::createStatusBar()
{
if (!isVisible())
- return;
+ return nullptr;
ToolBarBackend::registerDeclarativeType();
- auto quickWidget = new StudioQuickWidget;
+ auto quickWidget = Utils::makeUniqueObjectPtr<StudioQuickWidget>();
quickWidget->setFixedHeight(Theme::toolbarSize());
quickWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
@@ -107,7 +109,7 @@ void ToolBar::createStatusBar()
quickWidget->engine()->addImportPath(propertyEditorResourcesPath().toString() + "/imports");
Utils::FilePath qmlFilePath = qmlSourcesStatusBarPath().pathAppended("/Main.qml");
- QTC_ASSERT(qmlFilePath.exists(), return);
+ QTC_ASSERT(qmlFilePath.exists(), return nullptr);
Theme::setupTheme(quickWidget->engine());
@@ -117,8 +119,10 @@ void ToolBar::createStatusBar()
w->hide();
}
- Core::ICore::statusBar()->addWidget(quickWidget);
+ Core::ICore::statusBar()->addPermanentWidget(quickWidget.get(), 100);
Core::ICore::statusBar()->setFixedHeight(Theme::toolbarSize());
+
+ return quickWidget;
}
bool ToolBar::isVisible()
diff --git a/src/plugins/qmldesigner/components/toolbar/toolbar.h b/src/plugins/qmldesigner/components/toolbar/toolbar.h
index 8537757cdf4..d086fdf3ed2 100644
--- a/src/plugins/qmldesigner/components/toolbar/toolbar.h
+++ b/src/plugins/qmldesigner/components/toolbar/toolbar.h
@@ -3,14 +3,18 @@
#pragma once
+#include <QToolBar>
+
+#include <utils/uniqueobjectptr.h>
+
namespace QmlDesigner {
class ToolBar
{
public:
- static void create();
- static void createStatusBar();
+ static Utils::UniqueObjectPtr<QToolBar> create();
+ static Utils::UniqueObjectPtr<QWidget> createStatusBar();
static bool isVisible();
};
diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp
index ce7d783a4ed..1b9f1e3271f 100644
--- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp
+++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.cpp
@@ -79,10 +79,288 @@ static void openUiFile()
Core::EditorManager::openEditor(mainUiFile, Utils::Id());
}
+CrumbleBarModel::CrumbleBarModel(QObject *)
+{
+ connect(crumbleBar(), &CrumbleBar::pathChanged, this, &CrumbleBarModel::handleCrumblePathChanged);
+}
+
+int CrumbleBarModel::rowCount(const QModelIndex &) const
+{
+ return crumbleBar()->path().count();
+}
+
+QHash<int, QByteArray> CrumbleBarModel::roleNames() const
+{
+ static QHash<int, QByteArray> roleNames{{Qt::UserRole + 1, "fileName"},
+ {Qt::UserRole + 2, "fileAddress"}};
+
+ return roleNames;
+}
+
+QVariant CrumbleBarModel::data(const QModelIndex &index, int role) const
+{
+ if (index.isValid() && index.row() < rowCount()) {
+ auto info = crumbleBar()->infos().at(index.row());
+
+ if (role == Qt::UserRole + 1) {
+ return info.displayName;
+ } else if (role == Qt::UserRole + 2) {
+ return info.fileName.displayName();
+ } else {
+ qWarning() << Q_FUNC_INFO << "invalid role";
+ }
+ } else {
+ qWarning() << Q_FUNC_INFO << "invalid index";
+ }
+
+ return QVariant();
+}
+
+void CrumbleBarModel::handleCrumblePathChanged()
+{
+ beginResetModel();
+ endResetModel();
+}
+
+void CrumbleBarModel::onCrumblePathElementClicked(int i)
+{
+ if (i < rowCount()) {
+ auto info = crumbleBar()->infos().at(i);
+ crumbleBar()->onCrumblePathElementClicked(QVariant::fromValue(info));
+ }
+}
+
+WorkspaceModel::WorkspaceModel(QObject *)
+{
+ connect(designModeWidget(), &Internal::DesignModeWidget::initialized, this, [this]() {
+ const auto dockManager = designModeWidget()->dockManager();
+
+ connect(dockManager, &ADS::DockManager::workspaceListChanged, this, [this]() {
+ beginResetModel();
+ endResetModel();
+ });
+
+ beginResetModel();
+ endResetModel();
+ });
+}
+
+int WorkspaceModel::rowCount(const QModelIndex &) const
+{
+ if (designModeWidget() && designModeWidget()->dockManager())
+ return designModeWidget()->dockManager()->workspaces().count();
+
+ return 0;
+}
+
+QHash<int, QByteArray> WorkspaceModel::roleNames() const
+{
+ static QHash<int, QByteArray> roleNames{{DisplayNameRole, "displayName"},
+ {FileNameRole, "fileName"}};
+
+ return roleNames;
+}
+
+QVariant WorkspaceModel::data(const QModelIndex &index, int role) const
+{
+ if (index.isValid() && index.row() < rowCount()) {
+ auto workspace = designModeWidget()->dockManager()->workspaces().at(index.row());
+
+ if (role == DisplayNameRole) {
+ return workspace.name();
+ } else if (role == FileNameRole) {
+ return workspace.fileName();
+ } else {
+ qWarning() << Q_FUNC_INFO << "invalid role";
+ }
+ } else {
+ qWarning() << Q_FUNC_INFO << "invalid index";
+ }
+
+ return QVariant();
+}
+
+ActionSubscriber::ActionSubscriber(QObject *parent)
+ : QObject(parent)
+{
+ ActionAddedInterface callback = [this](ActionInterface *interface) {
+ if (interface->menuId() == m_actionId.toLatin1()) {
+ m_interface = interface;
+ setupNotifier();
+ }
+ };
+
+ QmlDesignerPlugin::instance()->viewManager().designerActionManager().addAddActionCallback(callback);
+}
+
+void ActionSubscriber::trigger()
+{
+ if (m_interface)
+ m_interface->action()->trigger();
+}
+
+bool ActionSubscriber::available() const
+{
+ if (m_interface)
+ return m_interface->action()->isEnabled();
+ return false;
+}
+
+bool ActionSubscriber::checked() const
+{
+ if (m_interface)
+ return m_interface->action()->isChecked();
+
+ return false;
+}
+
+QString ActionSubscriber::actionId() const
+{
+ return m_actionId;
+}
+
+void ActionSubscriber::setActionId(const QString &id)
+{
+ if (id == m_actionId)
+ return;
+
+ m_actionId = id;
+ emit actionIdChanged();
+ emit tooltipChanged();
+}
+
+QString ActionSubscriber::tooltip() const
+{
+ if (m_interface)
+ return m_interface->action()->text();
+ return {};
+}
+
+void ActionSubscriber::setupNotifier()
+{
+ if (!m_interface)
+ return;
+
+ connect(m_interface->action(), &QAction::enabledChanged, this, &ActionSubscriber::availableChanged);
+
+ emit tooltipChanged();
+}
+
+ToolBarBackend::ToolBarBackend(QObject *parent)
+ : QObject(parent)
+{
+ ActionAddedInterface callback = [this](ActionInterface *interface) {
+ if (interface->menuId() == "PreviewZoom")
+ m_zoomAction = interface;
+ };
+
+ QmlDesignerPlugin::instance()->viewManager().designerActionManager().addAddActionCallback(callback);
+
+ connect(designModeWidget(),
+ &Internal::DesignModeWidget::navigationHistoryChanged,
+ this,
+ &ToolBarBackend::navigationHistoryChanged);
+
+ connect(Core::DocumentModel::model(),
+ &QAbstractItemModel::rowsInserted,
+ this,
+ &ToolBarBackend::updateDocumentModel);
+ connect(Core::DocumentModel::model(),
+ &QAbstractItemModel::rowsRemoved,
+ this,
+ &ToolBarBackend::updateDocumentModel);
+ connect(Core::DocumentModel::model(),
+ &QAbstractItemModel::dataChanged,
+ this,
+ &ToolBarBackend::updateDocumentModel);
+ connect(Core::DocumentModel::model(),
+ &QAbstractItemModel::modelReset,
+ this,
+ &ToolBarBackend::updateDocumentModel);
+
+ connect(Core::EditorManager::instance(),
+ &Core::EditorManager::currentEditorChanged,
+ this,
+ &ToolBarBackend::documentIndexChanged);
+
+ connect(Core::EditorManager::instance(),
+ &Core::EditorManager::currentEditorChanged,
+ this,
+ &ToolBarBackend::currentStyleChanged);
+
+ connect(designModeWidget(), &Internal::DesignModeWidget::initialized, this, [this]() {
+ const auto dockManager = designModeWidget()->dockManager();
+
+ connect(dockManager, &ADS::DockManager::workspaceLoaded, this, [this](const QString &) {
+ emit currentWorkspaceChanged();
+ });
+
+ connect(dockManager, &ADS::DockManager::workspaceListChanged, this, [this]() {
+ emit currentWorkspaceChanged();
+ });
+
+ emit currentWorkspaceChanged();
+ });
+
+ auto editorManager = Core::EditorManager::instance();
+
+ connect(editorManager, &Core::EditorManager::documentClosed, this, [this]() {
+ if (isInDesignMode() && Core::DocumentModel::entryCount() == 0) {
+ QTimer::singleShot(0,
+ Core::ModeManager::instance(),
+ []() { /* The mode change has to happen from event loop.
+ Otherwise we and up in an invalid state */
+ Core::ModeManager::activateMode(Core::Constants::MODE_WELCOME);
+ });
+ }
+ });
+
+ connect(Core::ICore::instance(), &Core::ICore::coreAboutToOpen, this, [this] {
+ connect(Core::DesignMode::instance(), &Core::DesignMode::enabledStateChanged, this, [this] {
+ emit isDesignModeEnabledChanged();
+ });
+ });
+
+ connect(Core::ModeManager::instance(), &Core::ModeManager::currentModeChanged, this, [this]() {
+ emit isInDesignModeChanged();
+ emit isInEditModeChanged();
+ emit isDesignModeEnabledChanged();
+ });
+
+ connect(ProjectExplorer::ProjectManager::instance(),
+ &ProjectExplorer::ProjectManager::startupProjectChanged,
+ this,
+ [this](ProjectExplorer::Project *project) {
+ disconnect(m_kitConnection);
+ emit isQt6Changed();
+ emit projectOpenedChanged();
+ if (project) {
+ m_kitConnection = connect(project,
+ &ProjectExplorer::Project::activeTargetChanged,
+ this,
+ &ToolBarBackend::currentKitChanged);
+ emit currentKitChanged();
+ }
+ });
+
+ connect(ProjectExplorer::KitManager::instance(),
+ &ProjectExplorer::KitManager::kitsChanged,
+ this,
+ &ToolBarBackend::kitsChanged);
+}
+
+void ToolBarBackend::registerDeclarativeType()
+{
+ qmlRegisterType<ToolBarBackend>("ToolBar", 1, 0, "ToolBarBackend");
+ qmlRegisterType<ActionSubscriber>("ToolBar", 1, 0, "ActionSubscriber");
+ qmlRegisterType<CrumbleBarModel>("ToolBar", 1, 0, "CrumbleBarModel");
+ qmlRegisterType<WorkspaceModel>("ToolBar", 1, 0, "WorkspaceModel");
+}
+
void ToolBarBackend::triggerModeChange()
{
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_MODE_CHANGE);
- QTimer::singleShot(0, [this]() { //Do not trigger mode change directly from QML
+ QTimer::singleShot(0, this, [this]() { //Do not trigger mode change directly from QML
bool qmlFileOpen = false;
if (!projectOpened()) {
@@ -109,7 +387,7 @@ void ToolBarBackend::triggerModeChange()
void ToolBarBackend::triggerProjectSettings()
{
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_PROJECT_SETTINGS);
- QTimer::singleShot(0, []() { //Do not trigger mode change directly from QML
+ QTimer::singleShot(0, Core::ModeManager::instance(), []() { // Do not trigger mode change directly from QML
Core::ModeManager::activateMode(ProjectExplorer::Constants::MODE_SESSION);
});
}
@@ -230,7 +508,8 @@ void ToolBarBackend::setCurrentKit(int index)
if (!newTarget)
newTarget = project->addTargetForKit(kit);
- project->setActiveTarget(newTarget, ProjectExplorer::SetActive::Cascade);
+ project->setActiveTarget(newTarget,
+ ProjectExplorer::SetActive::Cascade);
emit currentKitChanged();
}
@@ -247,113 +526,6 @@ bool ToolBarBackend::canGoForward() const
return designModeWidget()->canGoForward();
}
-ToolBarBackend::ToolBarBackend(QObject *parent)
- : QObject(parent)
-{
- ActionAddedInterface callback = [this](ActionInterface *interface) {
- if (interface->menuId() == "PreviewZoom")
- m_zoomAction = interface;
- };
-
- QmlDesignerPlugin::instance()->viewManager().designerActionManager().addAddActionCallback(callback);
-
- connect(designModeWidget(),
- &Internal::DesignModeWidget::navigationHistoryChanged,
- this,
- &ToolBarBackend::navigationHistoryChanged);
-
- connect(Core::DocumentModel::model(),
- &QAbstractItemModel::rowsInserted,
- this,
- &ToolBarBackend::updateDocumentModel);
- connect(Core::DocumentModel::model(),
- &QAbstractItemModel::rowsRemoved,
- this,
- &ToolBarBackend::updateDocumentModel);
- connect(Core::DocumentModel::model(),
- &QAbstractItemModel::dataChanged,
- this,
- &ToolBarBackend::updateDocumentModel);
- connect(Core::DocumentModel::model(),
- &QAbstractItemModel::modelReset,
- this,
- &ToolBarBackend::updateDocumentModel);
-
- connect(Core::EditorManager::instance(),
- &Core::EditorManager::currentEditorChanged,
- this,
- &ToolBarBackend::documentIndexChanged);
-
- connect(Core::EditorManager::instance(),
- &Core::EditorManager::currentEditorChanged,
- this,
- &ToolBarBackend::currentStyleChanged);
-
- connect(designModeWidget(), &Internal::DesignModeWidget::initialized, this, [this]() {
- const auto dockManager = designModeWidget()->dockManager();
-
- connect(dockManager,
- &ADS::DockManager::workspaceListChanged,
- this,
- &ToolBarBackend::setupWorkspaces);
- connect(dockManager, &ADS::DockManager::workspaceLoaded, this, [this](const QString &) {
- emit currentWorkspaceChanged();
- });
-
- setupWorkspaces();
- });
-
- auto editorManager = Core::EditorManager::instance();
-
- connect(editorManager, &Core::EditorManager::documentClosed, this, [this]() {
- if (isInDesignMode() && Core::DocumentModel::entryCount() == 0) {
- QTimer::singleShot(0, []() { /* The mode change has to happen from event loop.
- Otherwise we and up in an invalid state */
- Core::ModeManager::activateMode(Core::Constants::MODE_WELCOME);
- });
- }
- });
-
- connect(Core::ICore::instance(), &Core::ICore::coreAboutToOpen, this, [this] {
- connect(Core::DesignMode::instance(), &Core::DesignMode::enabledStateChanged, this, [this] {
- emit isDesignModeEnabledChanged();
- });
- });
-
- connect(Core::ModeManager::instance(), &Core::ModeManager::currentModeChanged, this, [this]() {
- emit isInDesignModeChanged();
- emit isInEditModeChanged();
- emit isDesignModeEnabledChanged();
- });
-
- connect(ProjectExplorer::ProjectManager::instance(),
- &ProjectExplorer::ProjectManager::startupProjectChanged,
- [this](ProjectExplorer::Project *project) {
- disconnect(m_kitConnection);
- emit isQt6Changed();
- emit projectOpenedChanged();
- if (project) {
- m_kitConnection = connect(project,
- &ProjectExplorer::Project::activeTargetChanged,
- this,
- &ToolBarBackend::currentKitChanged);
- emit currentKitChanged();
- }
- });
-
- connect(ProjectExplorer::KitManager::instance(),
- &ProjectExplorer::KitManager::kitsChanged,
- this,
- &ToolBarBackend::kitsChanged);
-}
-
-void ToolBarBackend::registerDeclarativeType()
-{
- qmlRegisterType<ToolBarBackend>("ToolBar", 1, 0, "ToolBarBackend");
- qmlRegisterType<ActionSubscriber>("ToolBar", 1, 0, "ActionSubscriber");
- qmlRegisterType<CrumbleBarModel>("ToolBar", 1, 0, "CrumbleBarModel");
-}
-
QStringList ToolBarBackend::documentModel() const
{
return m_openDocuments;
@@ -382,13 +554,9 @@ int ToolBarBackend::documentIndex() const
QString ToolBarBackend::currentWorkspace() const
{
if (designModeWidget() && designModeWidget()->dockManager())
- return designModeWidget()->dockManager()->activeWorkspace();
- return {};
-}
+ return designModeWidget()->dockManager()->activeWorkspace()->fileName();
-QStringList ToolBarBackend::workspaces() const
-{
- return m_workspaces;
+ return {};
}
QStringList ToolBarBackend::styles() const
@@ -417,17 +585,6 @@ bool ToolBarBackend::isInEditMode() const
return Core::ModeManager::currentModeId() == Core::Constants::MODE_EDIT;
}
-void ToolBarBackend::launchGlobalAnnotations()
-{
- QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_EDIT_GLOBAL_ANNOTATION);
- ModelNode node = currentDesignDocument()->rewriterView()->rootModelNode();
-
- if (node.isValid()) {
- designModeWidget()->globalAnnotationEditor().setModelNode(node);
- designModeWidget()->globalAnnotationEditor().showWidget();
- }
-}
-
bool ToolBarBackend::isDesignModeEnabled() const
{
if (Core::DesignMode::instance())
@@ -445,9 +602,7 @@ int ToolBarBackend::currentStyle() const
const QString qmlFile = view->model()->fileUrl().toLocalFile();
- const int index = ChangeStyleWidgetAction::getCurrentStyle(qmlFile);
-
- return index;
+ return ChangeStyleWidgetAction::getCurrentStyle(qmlFile);
}
QStringList ToolBarBackend::kits() const
@@ -485,129 +640,16 @@ bool ToolBarBackend::projectOpened() const
return ProjectExplorer::ProjectManager::instance()->startupProject();
}
-void ToolBarBackend::setupWorkspaces()
-{
- m_workspaces.clear();
- m_workspaces = designModeWidget()->dockManager()->workspaces();
- Utils::sort(m_workspaces);
- emit workspacesChanged();
- emit currentWorkspaceChanged();
-}
-
-ActionSubscriber::ActionSubscriber(QObject *parent)
- : QObject(parent)
-{
- ActionAddedInterface callback = [this](ActionInterface *interface) {
- if (interface->menuId() == m_actionId.toLatin1()) {
- m_interface = interface;
- setupNotifier();
- }
- };
-
- QmlDesignerPlugin::instance()->viewManager().designerActionManager().addAddActionCallback(callback);
-}
-
-void ActionSubscriber::trigger()
-{
- if (m_interface)
- m_interface->action()->trigger();
-}
-
-bool ActionSubscriber::available() const
-{
- if (m_interface)
- return m_interface->action()->isEnabled();
- return false;
-}
-
-bool ActionSubscriber::checked() const
-{
- if (m_interface)
- return m_interface->action()->isChecked();
-
- return false;
-}
-
-QString ActionSubscriber::actionId() const
-{
- return m_actionId;
-}
-
-void ActionSubscriber::setActionId(const QString &id)
-{
- if (id == m_actionId)
- return;
-
- m_actionId = id;
- emit actionIdChanged();
- emit tooltipChanged();
-}
-
-QString ActionSubscriber::tooltip() const
-{
- if (m_interface)
- return m_interface->action()->text();
- return {};
-}
-
-void ActionSubscriber::setupNotifier()
-{
- if (!m_interface)
- return;
-
- connect(m_interface->action(), &QAction::enabledChanged, this, &ActionSubscriber::availableChanged);
-
- emit tooltipChanged();
-}
-
-CrumbleBarModel::CrumbleBarModel(QObject *)
-{
- connect(crumbleBar(), &CrumbleBar::pathChanged, this, &CrumbleBarModel::handleCrumblePathChanged);
-}
-
-int CrumbleBarModel::rowCount(const QModelIndex &) const
-{
- return crumbleBar()->path().count();
-}
-
-QHash<int, QByteArray> CrumbleBarModel::roleNames() const
-{
- static QHash<int, QByteArray> roleNames{{Qt::UserRole + 1, "fileName"},
- {Qt::UserRole + 2, "fileAddress"}};
-
- return roleNames;
-}
-
-QVariant CrumbleBarModel::data(const QModelIndex &index, int role) const
+void ToolBarBackend::launchGlobalAnnotations()
{
- if (index.isValid() && index.row() < rowCount()) {
- auto info = crumbleBar()->infos().at(index.row());
-
- if (role == Qt::UserRole + 1) {
- return info.displayName;
- } else if (role == Qt::UserRole + 2) {
- return info.fileName.displayName();
- } else {
- qWarning() << Q_FUNC_INFO << "invalid role";
- }
- } else {
- qWarning() << Q_FUNC_INFO << "invalid index";
- }
-
- return QVariant();
-}
+ QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TOOLBAR_EDIT_GLOBAL_ANNOTATION);
-void CrumbleBarModel::handleCrumblePathChanged()
-{
- beginResetModel();
- endResetModel();
-}
+ QTC_ASSERT(currentDesignDocument(), return);
+ ModelNode node = currentDesignDocument()->rewriterView()->rootModelNode();
-void CrumbleBarModel::onCrumblePathElementClicked(int i)
-{
- if (i < rowCount()) {
- auto info = crumbleBar()->infos().at(i);
- crumbleBar()->onCrumblePathElementClicked(QVariant::fromValue(info));
+ if (node.isValid()) {
+ designModeWidget()->globalAnnotationEditor().setModelNode(node);
+ designModeWidget()->globalAnnotationEditor().showWidget();
}
}
diff --git a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h
index 1aed5aeeaf4..0091ab8a7f1 100644
--- a/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h
+++ b/src/plugins/qmldesigner/components/toolbar/toolbarbackend.h
@@ -18,15 +18,25 @@ public:
explicit CrumbleBarModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
-
QHash<int, QByteArray> roleNames() const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void handleCrumblePathChanged();
Q_INVOKABLE void onCrumblePathElementClicked(int i);
+};
-private:
+class WorkspaceModel : public QAbstractListModel
+{
+ Q_OBJECT
+ enum { DisplayNameRole = Qt::DisplayRole, FileNameRole = Qt::UserRole };
+
+public:
+ explicit WorkspaceModel(QObject *parent = nullptr);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QHash<int, QByteArray> roleNames() const override;
+ QVariant data(const QModelIndex &index, int role = DisplayNameRole) const override;
};
class ActionSubscriber : public QObject
@@ -73,7 +83,6 @@ class ToolBarBackend : public QObject
Q_PROPERTY(QStringList documentModel READ documentModel NOTIFY openDocumentsChanged)
Q_PROPERTY(int documentIndex READ documentIndex NOTIFY documentIndexChanged)
Q_PROPERTY(QString currentWorkspace READ currentWorkspace NOTIFY currentWorkspaceChanged)
- Q_PROPERTY(QStringList workspaces READ workspaces NOTIFY workspacesChanged)
Q_PROPERTY(QStringList styles READ styles CONSTANT)
Q_PROPERTY(bool isInDesignMode READ isInDesignMode NOTIFY isInDesignModeChanged)
Q_PROPERTY(bool isInEditMode READ isInEditMode NOTIFY isInEditModeChanged)
@@ -111,11 +120,11 @@ public:
int documentIndex() const;
QString currentWorkspace() const;
- QStringList workspaces() const;
QStringList styles() const;
bool isInDesignMode() const;
+ bool isInEditMode() const;
bool isDesignModeEnabled() const;
int currentStyle() const;
@@ -127,8 +136,6 @@ public:
bool projectOpened() const;
- bool isInEditMode() const;
-
static void launchGlobalAnnotations();
signals:
@@ -136,7 +143,6 @@ signals:
void openDocumentsChanged();
void documentIndexChanged();
void currentWorkspaceChanged();
- void workspacesChanged();
void isInDesignModeChanged();
void isInEditModeChanged();
void isDesignModeEnabledChanged();
@@ -152,7 +158,6 @@ private:
ActionInterface *m_zoomAction;
QStringList m_openDocuments;
- QStringList m_workspaces;
QMetaObject::Connection m_kitConnection;
};
diff --git a/src/plugins/qmldesigner/designercore/imagecache/asynchronousexplicitimagecache.cpp b/src/plugins/qmldesigner/designercore/imagecache/asynchronousexplicitimagecache.cpp
index ed168b8a09b..1c46722d4c4 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/asynchronousexplicitimagecache.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/asynchronousexplicitimagecache.cpp
@@ -78,42 +78,30 @@ void AsynchronousExplicitImageCache::wait()
m_backgroundThread.join();
}
-void AsynchronousExplicitImageCache::requestImage(Utils::PathString name,
+void AsynchronousExplicitImageCache::requestImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId)
+ Utils::SmallStringView extraId)
{
- addEntry(std::move(name),
- std::move(extraId),
- std::move(captureCallback),
- std::move(abortCallback),
- RequestType::Image);
+ addEntry(name, extraId, std::move(captureCallback), std::move(abortCallback), RequestType::Image);
m_condition.notify_all();
}
-void AsynchronousExplicitImageCache::requestMidSizeImage(Utils::PathString name,
+void AsynchronousExplicitImageCache::requestMidSizeImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId)
+ Utils::SmallStringView extraId)
{
- addEntry(std::move(name),
- std::move(extraId),
- std::move(captureCallback),
- std::move(abortCallback),
- RequestType::MidSizeImage);
+ addEntry(name, extraId, std::move(captureCallback), std::move(abortCallback), RequestType::MidSizeImage);
m_condition.notify_all();
}
-void AsynchronousExplicitImageCache::requestSmallImage(Utils::PathString name,
+void AsynchronousExplicitImageCache::requestSmallImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId)
+ Utils::SmallStringView extraId)
{
- addEntry(std::move(name),
- std::move(extraId),
- std::move(captureCallback),
- std::move(abortCallback),
- RequestType::SmallImage);
+ addEntry(name, extraId, std::move(captureCallback), std::move(abortCallback), RequestType::SmallImage);
m_condition.notify_all();
}
diff --git a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp
index dec46f87252..00b3ab722ef 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagecache.cpp
@@ -118,10 +118,10 @@ void AsynchronousImageCache::wait()
m_backgroundThread.join();
}
-void AsynchronousImageCache::requestImage(Utils::PathString name,
+void AsynchronousImageCache::requestImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId,
+ Utils::SmallStringView extraId,
ImageCache::AuxiliaryData auxiliaryData)
{
addEntry(std::move(name),
@@ -133,10 +133,10 @@ void AsynchronousImageCache::requestImage(Utils::PathString name,
m_condition.notify_all();
}
-void AsynchronousImageCache::requestMidSizeImage(Utils::PathString name,
+void AsynchronousImageCache::requestMidSizeImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId,
+ Utils::SmallStringView extraId,
ImageCache::AuxiliaryData auxiliaryData)
{
addEntry(std::move(name),
@@ -148,10 +148,10 @@ void AsynchronousImageCache::requestMidSizeImage(Utils::PathString name,
m_condition.notify_all();
}
-void AsynchronousImageCache::requestSmallImage(Utils::PathString name,
+void AsynchronousImageCache::requestSmallImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId,
+ Utils::SmallStringView extraId,
ImageCache::AuxiliaryData auxiliaryData)
{
addEntry(std::move(name),
diff --git a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.cpp b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.cpp
index 500359182ae..5d6ced30601 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.cpp
@@ -39,16 +39,16 @@ AsynchronousImageFactory::~AsynchronousImageFactory()
wait();
}
-void AsynchronousImageFactory::generate(Utils::PathString name,
- Utils::SmallString extraId,
+void AsynchronousImageFactory::generate(Utils::SmallStringView name,
+ Utils::SmallStringView extraId,
ImageCache::AuxiliaryData auxiliaryData)
{
- addEntry(std::move(name), std::move(extraId), std::move(auxiliaryData));
+ addEntry(name, extraId, std::move(auxiliaryData));
m_condition.notify_all();
}
-void AsynchronousImageFactory::addEntry(Utils::PathString &&name,
- Utils::SmallString &&extraId,
+void AsynchronousImageFactory::addEntry(Utils::SmallStringView name,
+ Utils::SmallStringView extraId,
ImageCache::AuxiliaryData &&auxiliaryData)
{
std::unique_lock lock{m_mutex};
diff --git a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.h b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.h
index 4aa24d0a769..415646c73cd 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/asynchronousimagefactory.h
@@ -28,8 +28,8 @@ public:
~AsynchronousImageFactory();
- void generate(Utils::PathString name,
- Utils::SmallString extraId = {},
+ void generate(Utils::SmallStringView name,
+ Utils::SmallStringView extraId = {},
ImageCache::AuxiliaryData auxiliaryData = {});
void clean();
@@ -50,8 +50,8 @@ private:
ImageCache::AuxiliaryData auxiliaryData;
};
- void addEntry(Utils::PathString &&name,
- Utils::SmallString &&extraId,
+ void addEntry(Utils::SmallStringView name,
+ Utils::SmallStringView extraId,
ImageCache::AuxiliaryData &&auxiliaryData);
bool isRunning();
void waitForEntries();
diff --git a/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp
index 1f28d4eca69..509abb5c70f 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/explicitimagecacheimageprovider.cpp
@@ -17,7 +17,7 @@ QQuickImageResponse *ExplicitImageCacheImageProvider::requestImageResponse(const
auto response = std::make_unique<ImageCacheImageResponse>(m_defaultImage);
m_cache.requestImage(
- id,
+ Utils::PathString{id},
[response = QPointer<ImageCacheImageResponse>(response.get())](const QImage &image) {
QMetaObject::invokeMethod(
response,
diff --git a/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h b/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h
index 6b0df6f1c1e..37131012d69 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h
+++ b/src/plugins/qmldesigner/designercore/imagecache/imagecachestorage.h
@@ -35,12 +35,8 @@ public:
ImageEntry fetchImage(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
{
try {
- Sqlite::DeferredTransaction transaction{database};
-
- auto optionalBlob = selectImageStatement.template optionalValue<Sqlite::ByteArrayBlob>(
- name, minimumTimeStamp.value);
-
- transaction.commit();
+ auto optionalBlob = selectImageStatement.template optionalValueWithTransaction<
+ Sqlite::ByteArrayBlob>(name, minimumTimeStamp.value);
if (optionalBlob)
return {readImage(optionalBlob->byteArray)};
@@ -55,12 +51,8 @@ public:
Sqlite::TimeStamp minimumTimeStamp) const override
{
try {
- Sqlite::DeferredTransaction transaction{database};
-
- auto optionalBlob = selectMidSizeImageStatement.template optionalValue<Sqlite::ByteArrayBlob>(
- name, minimumTimeStamp.value);
-
- transaction.commit();
+ auto optionalBlob = selectMidSizeImageStatement.template optionalValueWithTransaction<
+ Sqlite::ByteArrayBlob>(name, minimumTimeStamp.value);
if (optionalBlob)
return {readImage(optionalBlob->byteArray)};
@@ -75,12 +67,8 @@ public:
Sqlite::TimeStamp minimumTimeStamp) const override
{
try {
- Sqlite::DeferredTransaction transaction{database};
-
- auto optionalBlob = selectSmallImageStatement.template optionalValue<Sqlite::ByteArrayBlob>(
- name, minimumTimeStamp.value);
-
- transaction.commit();
+ auto optionalBlob = selectSmallImageStatement.template optionalValueWithTransaction<
+ Sqlite::ByteArrayBlob>(name, minimumTimeStamp.value);
if (optionalBlob)
return ImageEntry{readImage(optionalBlob->byteArray)};
@@ -95,12 +83,8 @@ public:
IconEntry fetchIcon(Utils::SmallStringView name, Sqlite::TimeStamp minimumTimeStamp) const override
{
try {
- Sqlite::DeferredTransaction transaction{database};
-
- auto optionalBlob = selectIconStatement.template optionalValue<Sqlite::ByteArrayBlob>(
- name, minimumTimeStamp.value);
-
- transaction.commit();
+ auto optionalBlob = selectIconStatement.template optionalValueWithTransaction<
+ Sqlite::ByteArrayBlob>(name, minimumTimeStamp.value);
if (optionalBlob)
return {readIcon(optionalBlob->byteArray)};
@@ -119,19 +103,16 @@ public:
const QImage &smallImage) override
{
try {
- Sqlite::ImmediateTransaction transaction{database};
-
auto imageBuffer = createBuffer(image);
auto midSizeImageBuffer = createBuffer(midSizeImage);
auto smallImageBuffer = createBuffer(smallImage);
- upsertImageStatement.write(name,
- newTimeStamp.value,
- createBlobView(imageBuffer.get()),
- createBlobView(midSizeImageBuffer.get()),
- createBlobView(smallImageBuffer.get()));
-
- transaction.commit();
-
+ Sqlite::withImmediateTransaction(database, [&] {
+ upsertImageStatement.write(name,
+ newTimeStamp.value,
+ createBlobView(imageBuffer.get()),
+ createBlobView(midSizeImageBuffer.get()),
+ createBlobView(smallImageBuffer.get()));
+ });
} catch (const Sqlite::StatementIsBusy &) {
return storeImage(name, newTimeStamp, image, midSizeImage, smallImage);
}
@@ -140,12 +121,10 @@ public:
void storeIcon(Utils::SmallStringView name, Sqlite::TimeStamp newTimeStamp, const QIcon &icon) override
{
try {
- Sqlite::ImmediateTransaction transaction{database};
-
auto iconBuffer = createBuffer(icon);
- upsertIconStatement.write(name, newTimeStamp.value, createBlobView(iconBuffer.get()));
-
- transaction.commit();
+ Sqlite::withImmediateTransaction(database, [&] {
+ upsertIconStatement.write(name, newTimeStamp.value, createBlobView(iconBuffer.get()));
+ });
} catch (const Sqlite::StatementIsBusy &) {
return storeIcon(name, newTimeStamp, icon);
diff --git a/src/plugins/qmldesigner/designercore/imagecache/midsizeimagecacheprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/midsizeimagecacheprovider.cpp
index fd37f02f044..9b62ffe1bfa 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/midsizeimagecacheprovider.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/midsizeimagecacheprovider.cpp
@@ -15,7 +15,7 @@ QQuickImageResponse *MidSizeImageCacheProvider::requestImageResponse(const QStri
auto response = std::make_unique<ImageCacheImageResponse>(m_defaultImage);
m_cache.requestMidSizeImage(
- id,
+ Utils::PathString{id},
[response = QPointer<ImageCacheImageResponse>(response.get())](const QImage &image) {
QMetaObject::invokeMethod(
response,
diff --git a/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp
index 3fae3bb1754..722498dd98a 100644
--- a/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp
+++ b/src/plugins/qmldesigner/designercore/imagecache/smallimagecacheprovider.cpp
@@ -16,7 +16,7 @@ QQuickImageResponse *SmallImageCacheProvider::requestImageResponse(const QString
auto response = std::make_unique<ImageCacheImageResponse>(m_defaultImage);
m_cache.requestSmallImage(
- id,
+ Utils::PathString{id},
[response = QPointer<ImageCacheImageResponse>(response.get())](const QImage &image) {
QMetaObject::invokeMethod(
response,
diff --git a/src/plugins/qmldesigner/designercore/include/abstractproperty.h b/src/plugins/qmldesigner/designercore/include/abstractproperty.h
index 7b5c6ccf68d..c22402202d8 100644
--- a/src/plugins/qmldesigner/designercore/include/abstractproperty.h
+++ b/src/plugins/qmldesigner/designercore/include/abstractproperty.h
@@ -50,6 +50,10 @@ class QMLDESIGNERCORE_EXPORT AbstractProperty
public:
AbstractProperty() = default;
+ AbstractProperty(const AbstractProperty &) = default;
+ AbstractProperty &operator=(const AbstractProperty &) = default;
+ AbstractProperty(AbstractProperty &&) = default;
+ AbstractProperty &operator=(AbstractProperty &&) noexcept = default;
~AbstractProperty();
AbstractProperty(const AbstractProperty &property, AbstractView *view);
diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h
index 2d886d959be..0c3df94030c 100644
--- a/src/plugins/qmldesigner/designercore/include/abstractview.h
+++ b/src/plugins/qmldesigner/designercore/include/abstractview.h
@@ -195,9 +195,9 @@ public:
const ModelNode &movedNode,
int oldIndex);
- virtual void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports);
- virtual void possibleImportsChanged(const QList<Import> &possibleImports);
- virtual void usedImportsChanged(const QList<Import> &usedImports);
+ virtual void importsChanged(const Imports &addedImports, const Imports &removedImports);
+ virtual void possibleImportsChanged(const Imports &possibleImports);
+ virtual void usedImportsChanged(const Imports &usedImports);
virtual void auxiliaryDataChanged(const ModelNode &node,
AuxiliaryDataKeyView type,
diff --git a/src/plugins/qmldesigner/designercore/include/asynchronousexplicitimagecache.h b/src/plugins/qmldesigner/designercore/include/asynchronousexplicitimagecache.h
index 7cddfd29d9f..f9a053a9413 100644
--- a/src/plugins/qmldesigner/designercore/include/asynchronousexplicitimagecache.h
+++ b/src/plugins/qmldesigner/designercore/include/asynchronousexplicitimagecache.h
@@ -23,18 +23,18 @@ public:
AsynchronousExplicitImageCache(ImageCacheStorageInterface &storage);
- void requestImage(Utils::PathString name,
+ void requestImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId = {});
- void requestMidSizeImage(Utils::PathString name,
+ Utils::SmallStringView extraId = {});
+ void requestMidSizeImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId = {});
- void requestSmallImage(Utils::PathString name,
+ Utils::SmallStringView extraId = {});
+ void requestSmallImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId = {});
+ Utils::SmallStringView extraId = {});
void clean();
diff --git a/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h b/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h
index 04882d61eb7..3257f9d75c1 100644
--- a/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h
+++ b/src/plugins/qmldesigner/designercore/include/asynchronousimagecache.h
@@ -28,20 +28,20 @@ public:
ImageCacheGeneratorInterface &generator,
TimeStampProviderInterface &timeStampProvider);
- void requestImage(Utils::PathString name,
+ void requestImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId = {},
+ Utils::SmallStringView extraId = {},
ImageCache::AuxiliaryData auxiliaryData = {}) override;
- void requestMidSizeImage(Utils::PathString name,
+ void requestMidSizeImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId = {},
+ Utils::SmallStringView extraId = {},
ImageCache::AuxiliaryData auxiliaryData = {}) override;
- void requestSmallImage(Utils::PathString name,
+ void requestSmallImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId = {},
+ Utils::SmallStringView extraId = {},
ImageCache::AuxiliaryData auxiliaryData = {}) override;
void clean();
diff --git a/src/plugins/qmldesigner/designercore/include/asynchronousimagecacheinterface.h b/src/plugins/qmldesigner/designercore/include/asynchronousimagecacheinterface.h
index da8bda079e2..43c8e5b6726 100644
--- a/src/plugins/qmldesigner/designercore/include/asynchronousimagecacheinterface.h
+++ b/src/plugins/qmldesigner/designercore/include/asynchronousimagecacheinterface.h
@@ -14,22 +14,22 @@ namespace QmlDesigner {
class AsynchronousImageCacheInterface
{
public:
- virtual void requestImage(Utils::PathString name,
+ virtual void requestImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId = {},
+ Utils::SmallStringView extraId = {},
ImageCache::AuxiliaryData auxiliaryData = {})
= 0;
- virtual void requestMidSizeImage(Utils::PathString name,
+ virtual void requestMidSizeImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId = {},
+ Utils::SmallStringView extraId = {},
ImageCache::AuxiliaryData auxiliaryData = {})
= 0;
- virtual void requestSmallImage(Utils::PathString name,
+ virtual void requestSmallImage(Utils::SmallStringView name,
ImageCache::CaptureImageCallback captureCallback,
ImageCache::AbortCallback abortCallback,
- Utils::SmallString extraId = {},
+ Utils::SmallStringView extraId = {},
ImageCache::AuxiliaryData auxiliaryData = {})
= 0;
diff --git a/src/plugins/qmldesigner/designercore/include/auxiliarydataproperties.h b/src/plugins/qmldesigner/designercore/include/auxiliarydataproperties.h
index 1a1884ce645..4c12af14fef 100644
--- a/src/plugins/qmldesigner/designercore/include/auxiliarydataproperties.h
+++ b/src/plugins/qmldesigner/designercore/include/auxiliarydataproperties.h
@@ -106,6 +106,8 @@ inline constexpr AuxiliaryDataKeyView globalAnnotationStatus{AuxiliaryDataType::
inline constexpr AuxiliaryDataKeyView rotBlockProperty{AuxiliaryDataType::NodeInstanceAuxiliary,
"rotBlock"};
inline constexpr AuxiliaryDataKeyView languageProperty{AuxiliaryDataType::Temporary, "language"};
+inline constexpr AuxiliaryDataKeyView bakeLightsManualProperty{AuxiliaryDataType::Document,
+ "bakeLightsManual"};
// Most material preview aux properties are duplicated as document and instance types, as they
// are both required to be persistent and used at runtime to control material preview rendering
diff --git a/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h b/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h
index 7b2b8a2c55f..d4a087f4c7b 100644
--- a/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h
+++ b/src/plugins/qmldesigner/designercore/include/externaldependenciesinterface.h
@@ -6,6 +6,9 @@
#include <instances/puppetstartdata.h>
#include <utils/filepath.h>
+#include <QColor>
+#include <QUrl>
+
namespace QmlDesigner {
class DesignerSettings;
@@ -40,6 +43,11 @@ public:
virtual PuppetStartData puppetStartData(const class Model &model) const = 0;
virtual bool instantQmlTextUpdate() const = 0;
virtual Utils::FilePath qmlPuppetPath() const = 0;
+ virtual QStringList modulePaths() const = 0;
+ virtual QStringList projectModulePaths() const = 0;
+ virtual bool isQt6Project() const = 0;
+ virtual QString qtQuickVersion() const = 0;
+ virtual Utils::FilePath resourcePath(const QString &relativePath) const = 0;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/include/forwardview.h b/src/plugins/qmldesigner/designercore/include/forwardview.h
index 7041e851096..386ac83141c 100644
--- a/src/plugins/qmldesigner/designercore/include/forwardview.h
+++ b/src/plugins/qmldesigner/designercore/include/forwardview.h
@@ -44,7 +44,7 @@ public:
void fileUrlChanged(const QUrl &oldUrl, const QUrl &newUrl) override;
void nodeOrderChanged(const NodeListProperty &listProperty) override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void auxiliaryDataChanged(const ModelNode &node, const PropertyName &name, const QVariant &data) override;
@@ -197,7 +197,7 @@ void ForwardView<ViewType>::nodeOrderChanged(const NodeListProperty &listPropert
}
template <class ViewType>
-void ForwardView<ViewType>::importChanged(const QList<Import> &addedImports, const QList<Import> &removedImports)
+void ForwardView<ViewType>::importChanged(const Imports &addedImports, const Imports &removedImports)
{
for (const ViewTypePointer &view : std::as_const(m_targetViewList))
view->importChanged(addedImport, removedImport);
diff --git a/src/plugins/qmldesigner/designercore/include/import.h b/src/plugins/qmldesigner/designercore/include/import.h
index b221b861732..f0a5b8e7700 100644
--- a/src/plugins/qmldesigner/designercore/include/import.h
+++ b/src/plugins/qmldesigner/designercore/include/import.h
@@ -3,18 +3,49 @@
#pragma once
+#include <utils/set_algorithm.h>
+
#include <QString>
#include <QStringList>
#include <QMetaType>
#include "qmldesignercorelib_global.h"
+#include <limits>
+
namespace QmlDesigner {
+class Version
+{
+public:
+ friend bool operator==(Version first, Version second)
+ {
+ return first.major == second.major && first.minor == second.minor;
+ }
+
+ friend bool operator<(Version first, Version second)
+ {
+ return std::tie(first.major, first.minor) < std::tie(second.major, second.minor);
+ }
+
+ friend bool operator>(Version first, Version second) { return second < first; }
+ friend bool operator<=(Version first, Version second) { return !(second < first); }
+ friend bool operator>=(Version first, Version second) { return !(first < second); }
+
+ bool isEmpty() const
+ {
+ return major == std::numeric_limits<int>::max() || minor == std::numeric_limits<int>::max();
+ }
+
+public:
+ int major = std::numeric_limits<int>::max();
+ int minor = std::numeric_limits<int>::max();
+};
+
class QMLDESIGNERCORE_EXPORT Import
{
public:
- Import();
+ Import() = default;
static Import createLibraryImport(const QString &url, const QString &version = QString(), const QString &alias = QString(), const QStringList &importPaths = QStringList());
static Import createFileImport(const QString &file, const QString &version = QString(), const QString &alias = QString(), const QStringList &importPaths = QStringList());
@@ -26,23 +57,35 @@ public:
bool hasVersion() const { return !m_version.isEmpty(); }
bool hasAlias() const { return !m_alias.isEmpty(); }
- QString url() const { return m_url; }
- QString file() const { return m_file; }
- QString version() const { return m_version; }
- QString alias() const { return m_alias; }
- QStringList importPaths() const { return m_importPathList; }
+ const QString &url() const { return m_url; }
+ const QString &file() const { return m_file; }
+ const QString &version() const { return m_version; }
+ const QString &alias() const { return m_alias; }
+ const QStringList &importPaths() const { return m_importPathList; }
QString toString(bool skipAlias = false, bool skipVersion = false) const;
QString toImportString() const;
- bool operator==(const Import &other) const;
bool isSameModule(const Import &other) const;
int majorVersion() const;
int minorVersion() const;
+ Version toVersion() const;
static int majorFromVersion(const QString &version);
static int minorFromVersion(const QString &version);
+ friend bool operator==(const Import &first, const Import &second)
+ {
+ return first.m_url == second.m_url && first.m_file == second.m_file
+ && (first.m_version == second.m_version || first.m_version.isEmpty()
+ || second.m_version.isEmpty());
+ }
+
+ friend bool operator<(const Import &first, const Import &second)
+ {
+ return std::tie(first.m_url, first.m_file) < std::tie(second.m_url, second.m_file);
+ }
+
private:
Import(const QString &url, const QString &file, const QString &version, const QString &alias, const QStringList &importPaths);
@@ -56,6 +99,23 @@ private:
QMLDESIGNERCORE_EXPORT size_t qHash(const Import &import);
+using Imports = QList<Import>;
+
+QMLDESIGNERCORE_EXPORT Imports difference(const Imports &first, const Imports &second);
+
+template<typename Callable>
+void differenceCall(const Imports &first, const Imports &second, Callable callable)
+{
+ Imports difference;
+ difference.reserve(first.size());
+
+ std::set_difference(first.begin(),
+ first.end(),
+ second.begin(),
+ second.end(),
+ ::Utils::make_iterator(callable));
+}
+
} // namespace QmlDesigner
Q_DECLARE_METATYPE(QmlDesigner::Import)
diff --git a/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h b/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h
index 0571e64a8ce..034af72410f 100644
--- a/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h
+++ b/src/plugins/qmldesigner/designercore/include/itemlibraryinfo.h
@@ -6,9 +6,10 @@
#include "qmldesignercorelib_global.h"
#include "propertycontainer.h"
+#include <memory>
+#include <QIcon>
#include <QPointer>
#include <QSet>
-#include <memory>
namespace QmlDesigner {
diff --git a/src/plugins/qmldesigner/designercore/include/metainfo.h b/src/plugins/qmldesigner/designercore/include/metainfo.h
index b5ec3c0aa95..914be96db7b 100644
--- a/src/plugins/qmldesigner/designercore/include/metainfo.h
+++ b/src/plugins/qmldesigner/designercore/include/metainfo.h
@@ -16,6 +16,7 @@ namespace QmlDesigner {
class ModelNode;
class AbstractProperty;
class ItemLibraryInfo;
+class ExternalDependenciesInterface;
namespace Internal {
class MetaInfoPrivate;
@@ -44,15 +45,14 @@ public:
ItemLibraryInfo *itemLibraryInfo() const;
public:
- static MetaInfo global();
- static void clearGlobal();
-
- static void setPluginPaths(const QStringList &paths);
+ static void initializeGlobal(const QStringList &pluginPaths,
+ const ExternalDependenciesInterface &externalDependencies);
static void disableParseItemLibraryDescriptionsUgly(); // ugly hack around broken tests
private:
bool isGlobal() const;
+ static MetaInfo global();
private:
MetaInfo();
diff --git a/src/plugins/qmldesigner/designercore/include/model.h b/src/plugins/qmldesigner/designercore/include/model.h
index 9e6c7ca36ad..c2cd807a8a2 100644
--- a/src/plugins/qmldesigner/designercore/include/model.h
+++ b/src/plugins/qmldesigner/designercore/include/model.h
@@ -6,6 +6,7 @@
#include <qmldesignercorelib_global.h>
#include <documentmessage.h>
+#include <model/modelresourcemanagementinterface.h>
#include <projectstorage/projectstoragefwd.h>
#include <QMimeData>
@@ -40,7 +41,7 @@ class RewriterView;
class NodeInstanceView;
class TextModifier;
-using PropertyListType = QList<QPair<PropertyName, QVariant> >;
+using PropertyListType = QList<QPair<PropertyName, QVariant>>;
class QMLDESIGNERCORE_EXPORT Model : public QObject
{
@@ -57,21 +58,38 @@ class QMLDESIGNERCORE_EXPORT Model : public QObject
public:
enum ViewNotification { NotifyView, DoNotNotifyView };
- Model(ProjectStorage<Sqlite::Database> &projectStorage,
+ Model(ProjectStorageType &projectStorage,
const TypeName &type,
int major = 1,
int minor = 1,
- Model *metaInfoProxyModel = nullptr);
- Model(const TypeName &typeName, int major = 1, int minor = 1, Model *metaInfoProxyModel = nullptr);
+ Model *metaInfoProxyModel = nullptr,
+ std::unique_ptr<ModelResourceManagementInterface> resourceManagement = {});
+ Model(const TypeName &typeName,
+ int major = 1,
+ int minor = 1,
+ Model *metaInfoProxyModel = nullptr,
+ std::unique_ptr<ModelResourceManagementInterface> resourceManagement = {});
~Model();
static ModelPointer create(const TypeName &typeName,
int major = 1,
int minor = 1,
- Model *metaInfoProxyModel = nullptr)
+ Model *metaInfoProxyModel = nullptr,
+ std::unique_ptr<ModelResourceManagementInterface> resourceManagement = {})
+ {
+ return ModelPointer(
+ new Model(typeName, major, minor, metaInfoProxyModel, std::move(resourceManagement)));
+ }
+
+ static ModelPointer create(ProjectStorageType &projectStorage,
+ const TypeName &typeName,
+ int major = 1,
+ int minor = 1,
+ std::unique_ptr<ModelResourceManagementInterface> resourceManagement = {})
{
- return ModelPointer(new Model(typeName, major, minor, metaInfoProxyModel));
+ return ModelPointer(
+ new Model(projectStorage, typeName, major, minor, nullptr, std::move(resourceManagement)));
}
QUrl fileUrl() const;
@@ -87,6 +105,7 @@ public:
NodeMetaInfo flowViewFlowTransitionMetaInfo() const;
NodeMetaInfo flowViewFlowWildcardMetaInfo() const;
NodeMetaInfo fontMetaInfo() const;
+ NodeMetaInfo qtQuick3DBakedLightmapMetaInfo() const;
NodeMetaInfo qtQuick3DDefaultMaterialMetaInfo() const;
NodeMetaInfo qtQuick3DMaterialMetaInfo() const;
NodeMetaInfo qtQuick3DModelMetaInfo() const;
@@ -111,15 +130,17 @@ public:
void attachView(AbstractView *view);
void detachView(AbstractView *view, ViewNotification emitDetachNotify = NotifyView);
+ QList<ModelNode> allModelNodes() const;
+
// Editing sub-components:
// Imports:
- const QList<Import> &imports() const;
- const QList<Import> &possibleImports() const;
- const QList<Import> &usedImports() const;
- void changeImports(const QList<Import> &importsToBeAdded, const QList<Import> &importsToBeRemoved);
- void setPossibleImports(const QList<Import> &possibleImports);
- void setUsedImports(const QList<Import> &usedImports);
+ const Imports &imports() const;
+ const Imports &possibleImports() const;
+ const Imports &usedImports() const;
+ void changeImports(const Imports &importsToBeAdded, const Imports &importsToBeRemoved);
+ void setPossibleImports(Imports possibleImports);
+ void setUsedImports(Imports usedImports);
bool hasImport(const Import &import, bool ignoreAlias = true, bool allowHigherVersion = false) const;
bool isImportPossible(const Import &import, bool ignoreAlias = true, bool allowHigherVersion = false) const;
QString pathForImport(const Import &import);
@@ -157,7 +178,7 @@ public:
void startDrag(QMimeData *mimeData, const QPixmap &icon);
void endDrag();
- NotNullPointer<const ProjectStorage<Sqlite::Database>> projectStorage() const;
+ NotNullPointer<const ProjectStorageType> projectStorage() const;
private:
template<const auto &moduleName, const auto &typeName>
@@ -168,4 +189,4 @@ private:
std::unique_ptr<Internal::ModelPrivate> d;
};
-}
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/include/modelfwd.h b/src/plugins/qmldesigner/designercore/include/modelfwd.h
new file mode 100644
index 00000000000..66712499958
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/include/modelfwd.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "../projectstorage/projectstoragefwd.h"
+#include "qmldesignercorelib_exports.h"
+
+#include <utils/smallstringview.h>
+
+namespace QmlDesigner {
+using PropertyName = QByteArray;
+using PropertyNameList = QList<PropertyName>;
+using TypeName = QByteArray;
+using PropertyTypeList = QList<PropertyName>;
+using IdName = QByteArray;
+class Model;
+class ModelNode;
+
+struct ModelDeleter
+{
+ QMLDESIGNERCORE_EXPORT void operator()(class Model *model);
+};
+
+using ModelPointer = std::unique_ptr<class Model, ModelDeleter>;
+
+constexpr bool useProjectStorage()
+{
+#ifdef QDS_USE_PROJECTSTORAGE
+ return true;
+#else
+ return false;
+#endif
+}
+
+#ifdef QDS_MODEL_USE_PROJECTSTORAGEINTERFACE
+using ProjectStorageType = ProjectStorageInterface;
+#else
+using ProjectStorageType = ProjectStorage<Sqlite::Database>;
+#endif
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/include/modelnode.h b/src/plugins/qmldesigner/designercore/include/modelnode.h
index a48713ee864..e9891da620c 100644
--- a/src/plugins/qmldesigner/designercore/include/modelnode.h
+++ b/src/plugins/qmldesigner/designercore/include/modelnode.h
@@ -80,6 +80,10 @@ public:
ModelNode();
ModelNode(const Internal::InternalNodePointer &internalNode, Model *model, const AbstractView *view);
ModelNode(const ModelNode &modelNode, AbstractView *view);
+ ModelNode(const ModelNode &) = default;
+ ModelNode &operator=(const ModelNode &) = default;
+ ModelNode(ModelNode &&) = default;
+ ModelNode &operator=(ModelNode &&) noexcept = default;
~ModelNode();
TypeName type() const;
@@ -266,6 +270,8 @@ QMLDESIGNERCORE_EXPORT bool operator !=(const ModelNode &firstNode, const ModelN
QMLDESIGNERCORE_EXPORT bool operator <(const ModelNode &firstNode, const ModelNode &secondNode);
QMLDESIGNERCORE_EXPORT QDebug operator<<(QDebug debug, const ModelNode &modelNode);
QMLDESIGNERCORE_EXPORT QTextStream& operator<<(QTextStream &stream, const ModelNode &modelNode);
+
+using ModelNodes = QList<ModelNode>;
}
Q_DECLARE_METATYPE(QmlDesigner::ModelNode)
diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h
index 632dbfce077..93b4e82a2a2 100644
--- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h
+++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h
@@ -85,7 +85,7 @@ public:
void fileUrlChanged(const QUrl &oldUrl, const QUrl &newUrl) override;
void nodeIdChanged(const ModelNode& node, const QString& newId, const QString& oldId) override;
void nodeOrderChanged(const NodeListProperty &listProperty) override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
void auxiliaryDataChanged(const ModelNode &node,
AuxiliaryDataKeyView key,
const QVariant &data) override;
@@ -122,6 +122,7 @@ public:
QImage statePreviewImage(const ModelNode &stateNode) const;
void setTarget(ProjectExplorer::Target *newTarget);
+ ProjectExplorer::Target *target() const;
void sendToken(const QString &token, int number, const QVector<ModelNode> &nodeVector);
diff --git a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h
index 69ac5f2a977..d7bc414e77e 100644
--- a/src/plugins/qmldesigner/designercore/include/nodemetainfo.h
+++ b/src/plugins/qmldesigner/designercore/include/nodemetainfo.h
@@ -6,7 +6,7 @@
#include "propertymetainfo.h"
#include "qmldesignercorelib_global.h"
-#include <projectstorage/projectstoragefwd.h>
+#include <projectstorage/projectstorageinterface.h>
#include <projectstorage/projectstoragetypes.h>
#include <projectstorageids.h>
@@ -32,11 +32,11 @@ class QMLDESIGNERCORE_EXPORT NodeMetaInfo
public:
NodeMetaInfo() = default;
NodeMetaInfo(Model *model, const TypeName &typeName, int majorVersion, int minorVersion);
- NodeMetaInfo(TypeId typeId, NotNullPointer<const ProjectStorage<Sqlite::Database>> projectStorage)
+ NodeMetaInfo(TypeId typeId, NotNullPointer<const ProjectStorageType> projectStorage)
: m_typeId{typeId}
, m_projectStorage{projectStorage}
{}
- NodeMetaInfo(NotNullPointer<const ProjectStorage<Sqlite::Database>> projectStorage)
+ NodeMetaInfo(NotNullPointer<const ProjectStorageType> projectStorage)
: m_projectStorage{projectStorage}
{}
~NodeMetaInfo();
@@ -44,7 +44,7 @@ public:
bool isValid() const;
explicit operator bool() const { return isValid(); }
bool isFileComponent() const;
- bool hasProperty(Utils::SmallStringView propertyName) const;
+ bool hasProperty(::Utils::SmallStringView propertyName) const;
PropertyMetaInfos properties() const;
PropertyMetaInfos localProperties() const;
PropertyMetaInfo property(const PropertyName &propertyName) const;
@@ -67,8 +67,6 @@ public:
QString componentFileName() const;
- bool availableInVersion(int majorVersion, int minorVersion) const;
-
bool isBasedOn(const NodeMetaInfo &metaInfo) const;
bool isBasedOn(const NodeMetaInfo &metaInfo1, const NodeMetaInfo &metaInfo2) const;
bool isBasedOn(const NodeMetaInfo &metaInfo1,
@@ -126,9 +124,11 @@ public:
bool isQtQuick3DEffect() const;
bool isQtQuick3DInstanceList() const;
bool isQtQuick3DInstanceListEntry() const;
+ bool isQtQuick3DLight() const;
bool isQtQuick3DMaterial() const;
bool isQtQuick3DModel() const;
bool isQtQuick3DNode() const;
+ bool isQtQuick3DParticleAbstractShape() const;
bool isQtQuick3DParticles3DAffector3D() const;
bool isQtQuick3DParticles3DAttractor3D() const;
bool isQtQuick3DParticles3DParticle3D() const;
@@ -171,8 +171,6 @@ public:
bool isQtQuickWindowWindow() const;
bool isQtSafeRendererSafePicture() const;
bool isQtSafeRendererSafeRendererPicture() const;
- bool isQuick3DParticleAbstractShape() const;
- bool isQuickStateOperation() const;
bool isString() const;
bool isSuitableForMouseAreaFill() const;
bool isUrl() const;
@@ -199,7 +197,7 @@ private:
private:
TypeId m_typeId;
- NotNullPointer<const ProjectStorage<Sqlite::Database>> m_projectStorage = {};
+ NotNullPointer<const ProjectStorageType> m_projectStorage = {};
mutable std::optional<Storage::Info::Type> m_typeData;
QSharedPointer<class NodeMetaInfoPrivate> m_privateData;
};
diff --git a/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h b/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h
index 814137d8a77..4172e8921ee 100644
--- a/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h
+++ b/src/plugins/qmldesigner/designercore/include/plaintexteditmodifier.h
@@ -91,8 +91,17 @@ public:
TextEditor::TabSettings tabSettings() const override
{ return m_tabSettings; }
-private:
+protected:
TextEditor::TabSettings m_tabSettings;
};
+class QMLDESIGNERCORE_EXPORT IndentingTextEditModifier : public NotIndentingTextEditModifier
+{
+public:
+ IndentingTextEditModifier(QTextDocument *document, const QTextCursor &textCursor);
+
+ void indent(int offset, int length) override;
+ void indentLines(int startLine, int endLine) override;
+};
+
}
diff --git a/src/plugins/qmldesigner/designercore/include/propertymetainfo.h b/src/plugins/qmldesigner/designercore/include/propertymetainfo.h
index 6cda405f615..a3c928bc36f 100644
--- a/src/plugins/qmldesigner/designercore/include/propertymetainfo.h
+++ b/src/plugins/qmldesigner/designercore/include/propertymetainfo.h
@@ -25,10 +25,12 @@ public:
PropertyMetaInfo() = default;
PropertyMetaInfo(QSharedPointer<class NodeMetaInfoPrivate> nodeMetaInfoPrivateData,
const PropertyName &propertyName);
- PropertyMetaInfo(PropertyDeclarationId id,
- NotNullPointer<const ProjectStorage<Sqlite::Database>> projectStorage)
- : m_id{id}
- , m_projectStorage{projectStorage}
+ PropertyMetaInfo([[maybe_unused]] PropertyDeclarationId id,
+ [[maybe_unused]] NotNullPointer<const ProjectStorageType> projectStorage)
+#ifdef QDS_USE_PROJECTSTORAGE
+ : m_projectStorage{projectStorage}
+ , m_id{id}
+#endif
{}
~PropertyMetaInfo();
@@ -36,11 +38,11 @@ public:
bool isValid() const
{
- if (useProjectStorage()) {
- return bool(m_id);
- } else {
- return bool(m_nodeMetaInfoPrivateData);
- }
+#ifdef QDS_USE_PROJECTSTORAGE
+ return bool(m_id);
+#else
+ return bool(m_nodeMetaInfoPrivateData);
+#endif
}
PropertyName name() const;
NodeMetaInfo propertyType() const;
@@ -53,20 +55,28 @@ public:
friend bool operator==(const PropertyMetaInfo &first, const PropertyMetaInfo &second)
{
+#ifdef QDS_USE_PROJECTSTORAGE
+ return first.m_id == second.m_id;
+#else
return first.m_nodeMetaInfoPrivateData == second.m_nodeMetaInfoPrivateData
&& first.name() == second.name();
+#endif
}
private:
const Storage::Info::PropertyDeclaration &propertyData() const;
TypeName propertyTypeName() const;
+ const NodeMetaInfoPrivate *nodeMetaInfoPrivateData() const;
+ const PropertyName &propertyName() const;
private:
+ NotNullPointer<const ProjectStorageType> m_projectStorage;
+ mutable std::optional<Storage::Info::PropertyDeclaration> m_propertyData;
+ PropertyDeclarationId m_id;
+#ifndef QDS_USE_PROJECTSTORAGE
QSharedPointer<class NodeMetaInfoPrivate> m_nodeMetaInfoPrivateData;
PropertyName m_propertyName;
- PropertyDeclarationId m_id;
- NotNullPointer<const ProjectStorage<Sqlite::Database>> m_projectStorage;
- mutable std::optional<Storage::Info::PropertyDeclaration> m_propertyData;
+#endif
};
using PropertyMetaInfos = std::vector<PropertyMetaInfo>;
diff --git a/src/plugins/qmldesigner/designercore/include/qmldesignercorelib_exports.h b/src/plugins/qmldesigner/designercore/include/qmldesignercorelib_exports.h
new file mode 100644
index 00000000000..f5e1dbf4788
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/include/qmldesignercorelib_exports.h
@@ -0,0 +1,12 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#if defined(QMLDESIGNERCORE_LIBRARY)
+#define QMLDESIGNERCORE_EXPORT Q_DECL_EXPORT
+#elif defined(QMLDESIGNERCORE_STATIC_LIBRARY)
+#define QMLDESIGNERCORE_EXPORT
+#else
+#define QMLDESIGNERCORE_EXPORT Q_DECL_IMPORT
+#endif
diff --git a/src/plugins/qmldesigner/designercore/include/qmldesignercorelib_global.h b/src/plugins/qmldesigner/designercore/include/qmldesignercorelib_global.h
index 05a1c2e20f6..7871b5df3a6 100644
--- a/src/plugins/qmldesigner/designercore/include/qmldesignercorelib_global.h
+++ b/src/plugins/qmldesigner/designercore/include/qmldesignercorelib_global.h
@@ -3,29 +3,16 @@
#pragma once
+#include "modelfwd.h"
+#include "qmldesignercorelib_exports.h"
+
#include <QtGlobal>
#include <QList>
-#include <utils/smallstringview.h>
-
#include <nodeinstanceglobal.h>
-
-// Unnecessary since core isn't a dll any more.
-
-#if defined(QMLDESIGNERCORE_LIBRARY)
-#define QMLDESIGNERCORE_EXPORT Q_DECL_EXPORT
-#elif defined(QMLDESIGNERCORE_STATIC_LIBRARY)
-#define QMLDESIGNERCORE_EXPORT
-#else
-#define QMLDESIGNERCORE_EXPORT Q_DECL_IMPORT
-#endif
+#include <projectstorage/projectstoragefwd.h>
namespace QmlDesigner {
-using PropertyName = QByteArray;
-using PropertyNameList = QList<PropertyName>;
-using TypeName = QByteArray;
-using PropertyTypeList = QList<PropertyName>;
-using IdName = QByteArray;
enum AnchorLineType {
AnchorLineInvalid = 0x0,
@@ -38,26 +25,12 @@ enum AnchorLineType {
AnchorLineVerticalCenter = 0x20,
AnchorLineBaseline = 0x40,
- AnchorLineFill = AnchorLineLeft | AnchorLineRight | AnchorLineTop | AnchorLineBottom,
+ AnchorLineFill = AnchorLineLeft | AnchorLineRight | AnchorLineTop | AnchorLineBottom,
AnchorLineCenter = AnchorLineVerticalCenter | AnchorLineHorizontalCenter,
AnchorLineHorizontalMask = AnchorLineLeft | AnchorLineRight | AnchorLineHorizontalCenter,
- AnchorLineVerticalMask = AnchorLineTop | AnchorLineBottom | AnchorLineVerticalCenter | AnchorLineBaseline,
+ AnchorLineVerticalMask = AnchorLineTop | AnchorLineBottom | AnchorLineVerticalCenter
+ | AnchorLineBaseline,
AnchorLineAllMask = AnchorLineVerticalMask | AnchorLineHorizontalMask
};
-struct ModelDeleter
-{
- QMLDESIGNERCORE_EXPORT void operator()(class Model *model);
-};
-
-using ModelPointer = std::unique_ptr<class Model, ModelDeleter>;
-
-constexpr bool useProjectStorage()
-{
-#ifdef QDS_USE_PROJECTSTORAGE
- return true;
-#else
- return false;
-#endif
-}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/include/qmlmodelnodefacade.h b/src/plugins/qmldesigner/designercore/include/qmlmodelnodefacade.h
index 9c63fd040a2..27c4c86cc0b 100644
--- a/src/plugins/qmldesigner/designercore/include/qmlmodelnodefacade.h
+++ b/src/plugins/qmldesigner/designercore/include/qmlmodelnodefacade.h
@@ -14,13 +14,17 @@ class NodeInstanceView;
class QMLDESIGNERCORE_EXPORT QmlModelNodeFacade
{
public:
+ QmlModelNodeFacade(const QmlModelNodeFacade &) = default;
+ QmlModelNodeFacade &operator=(const QmlModelNodeFacade &) = default;
+ QmlModelNodeFacade(QmlModelNodeFacade &&) noexcept = default;
+ QmlModelNodeFacade &operator=(QmlModelNodeFacade &&) noexcept = default;
+ virtual ~QmlModelNodeFacade() = default;
operator ModelNode() const { return m_modelNode; }
ModelNode modelNode() const { return m_modelNode; }
bool hasModelNode() const;
static bool isValidQmlModelNodeFacade(const ModelNode &modelNode);
virtual bool isValid() const;
explicit operator bool() const { return isValid(); }
- virtual ~QmlModelNodeFacade();
QmlModelNodeFacade() = default;
AbstractView *view() const;
diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h
index 9387fdb345e..95e2e51d8a1 100644
--- a/src/plugins/qmldesigner/designercore/include/rewriterview.h
+++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h
@@ -84,7 +84,7 @@ public:
void rewriterBeginTransaction() override;
void rewriterEndTransaction() override;
- void importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports) override;
+ void importsChanged(const Imports &addedImports, const Imports &removedImports) override;
TextModifier *textModifier() const;
void setTextModifier(TextModifier *textModifier);
diff --git a/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h b/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h
index 207f1b7104b..dbc89c1cccd 100644
--- a/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h
+++ b/src/plugins/qmldesigner/designercore/include/subcomponentmanager.h
@@ -27,7 +27,7 @@ public:
explicit SubComponentManager(Model *model,
class ExternalDependenciesInterface &externalDependencies);
- void update(const QUrl &fileUrl, const QList<Import> &imports);
+ void update(const QUrl &fileUrl, const Imports &imports);
void addAndParseImport(const Import &import);
QStringList qmlFiles() const;
@@ -53,7 +53,7 @@ private: // functions
private: // variables
QFileSystemWatcher m_watcher;
- QList<Import> m_imports;
+ Imports m_imports;
// key: canonical directory path
QMultiHash<QString,QString> m_dirToQualifier;
QUrl m_filePath;
diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
index 8ebfaf52044..3befd6ec52c 100644
--- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
+++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp
@@ -625,7 +625,7 @@ void NodeInstanceView::nodeOrderChanged(const NodeListProperty &listProperty)
m_nodeInstanceServer->reparentInstances(ReparentInstancesCommand(containerList));
}
-void NodeInstanceView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/)
+void NodeInstanceView::importsChanged(const Imports &/*addedImports*/, const Imports &/*removedImports*/)
{
restartProcess();
}
@@ -1572,6 +1572,11 @@ void NodeInstanceView::setTarget(ProjectExplorer::Target *newTarget)
}
}
+ProjectExplorer::Target *NodeInstanceView::target() const
+{
+ return m_currentTarget;
+}
+
void NodeInstanceView::statePreviewImagesChanged(const StatePreviewImageChangedCommand &command)
{
if (!model())
diff --git a/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp
index b1473d6a4c0..cbde96e9926 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/itemlibraryinfo.cpp
@@ -1,11 +1,12 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-#include "itemlibraryinfo.h"
+#include "../include/itemlibraryinfo.h"
#include "nodemetainfo.h"
#include "qregularexpression.h"
#include <invalidmetainfoexception.h>
+#include <propertycontainer.h>
#include <QSharedData>
diff --git a/src/plugins/qmldesigner/designercore/metainfo/metainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/metainfo.cpp
index 354ccd63c3f..144df144483 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/metainfo.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/metainfo.cpp
@@ -7,6 +7,7 @@
#include "metainforeader.h"
#include "iwidgetplugin.h"
+#include <externaldependenciesinterface.h>
#include <invalidmetainfoexception.h>
#include <coreplugin/messagebox.h>
@@ -30,24 +31,26 @@ enum {
namespace QmlDesigner {
namespace Internal {
-
-static QString globalMetaInfoPath()
+static QString globalMetaInfoPath(const ExternalDependenciesInterface &externalDependecies)
{
#ifdef SHARE_QML_PATH
if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
return QLatin1String(SHARE_QML_PATH) + "/globalMetaInfo";
#endif
- return Core::ICore::resourcePath("qmldesigner/globalMetaInfo").toString();
+ return externalDependecies.resourcePath("qmldesigner/globalMetaInfo").toString();
}
-Utils::FilePaths allGlobalMetaInfoFiles()
+Utils::FilePaths allGlobalMetaInfoFiles(const ExternalDependenciesInterface &externalDependecies)
{
static Utils::FilePaths paths;
if (!paths.isEmpty())
return paths;
- QDirIterator it(globalMetaInfoPath(), { "*.metainfo" }, QDir::Files, QDirIterator::Subdirectories);
+ QDirIterator it(globalMetaInfoPath(externalDependecies),
+ {"*.metainfo"},
+ QDir::Files,
+ QDirIterator::Subdirectories);
while (it.hasNext())
paths.append(Utils::FilePath::fromString(it.next()));
@@ -61,9 +64,9 @@ public:
MetaInfoPrivate(MetaInfo *q);
void clear();
- void initialize();
+ void initialize(const ExternalDependenciesInterface &externalDependencies);
- void parseItemLibraryDescriptions();
+ void parseItemLibraryDescriptions(const ExternalDependenciesInterface &externalDependencies);
QScopedPointer<ItemLibraryInfo> m_itemLibraryInfo;
@@ -90,14 +93,14 @@ namespace {
bool enableParseItemLibraryDescriptions = true;
}
-void MetaInfoPrivate::initialize()
+void MetaInfoPrivate::initialize(const ExternalDependenciesInterface &externalDependencies)
{
if (enableParseItemLibraryDescriptions)
- parseItemLibraryDescriptions();
+ parseItemLibraryDescriptions(externalDependencies);
m_isInitialized = true;
}
-void MetaInfoPrivate::parseItemLibraryDescriptions()
+void MetaInfoPrivate::parseItemLibraryDescriptions(const ExternalDependenciesInterface &externalDependencies)
{
Internal::WidgetPluginManager pluginManager;
for (const QString &pluginDir : std::as_const(m_q->s_pluginDirs))
@@ -107,7 +110,8 @@ void MetaInfoPrivate::parseItemLibraryDescriptions()
Internal::MetaInfoReader reader(*m_q);
try {
reader.readMetaInfoFile(plugin->metaInfo());
- } catch (const InvalidMetaInfoException &e) {
+ } catch ([[maybe_unused]] const InvalidMetaInfoException &e) {
+#ifndef UNIT_TESTS
qWarning() << e.description();
const QString errorMessage = plugin->metaInfo() + QLatin1Char('\n') + QLatin1Char('\n')
+ reader.errors().join(QLatin1Char('\n'));
@@ -115,15 +119,18 @@ void MetaInfoPrivate::parseItemLibraryDescriptions()
QCoreApplication::translate("QmlDesigner::Internal::MetaInfoPrivate",
"Invalid meta info"),
errorMessage);
+#endif
}
}
- const Utils::FilePaths allMetaInfoFiles = allGlobalMetaInfoFiles();
+ const Utils::FilePaths allMetaInfoFiles = allGlobalMetaInfoFiles(externalDependencies);
for (const Utils::FilePath &path : allMetaInfoFiles) {
Internal::MetaInfoReader reader(*m_q);
try {
reader.readMetaInfoFile(path.toString());
} catch (const InvalidMetaInfoException &e) {
+ Q_UNUSED(e);
+#ifndef UNIT_TESTS
qWarning() << e.description();
const QString errorMessage = path.toString() + QLatin1Char('\n') + QLatin1Char('\n')
+ reader.errors().join(QLatin1Char('\n'));
@@ -131,6 +138,7 @@ void MetaInfoPrivate::parseItemLibraryDescriptions()
QCoreApplication::translate("QmlDesigner::Internal::MetaInfoPrivate",
"Invalid meta info"),
errorMessage);
+#endif
}
}
}
@@ -186,45 +194,26 @@ ItemLibraryInfo *MetaInfo::itemLibraryInfo() const
return m_p->m_itemLibraryInfo.data();
}
-/*!
- Accesses the global meta information object.
- You almost always want to use Model::metaInfo() instead.
-
- Internally, all meta information objects share this \e global object
- where static QML type information is stored.
- */
-MetaInfo MetaInfo::global()
+void MetaInfo::initializeGlobal(const QStringList &pluginPaths,
+ const ExternalDependenciesInterface &externalDependencies)
{
QMutexLocker locker(&s_lock);
if (!s_global.m_p->m_isInitialized) {
+ s_pluginDirs = pluginPaths,
s_global.m_p = QSharedPointer<MetaInfoPrivate>(new MetaInfoPrivate(&s_global));
- s_global.m_p->initialize();
+ s_global.m_p->initialize(externalDependencies);
}
- return s_global;
-}
-
-/*!
- Clears the global meta information object.
-
- This function should be called once on application shutdown to free static data structures.
- */
-void MetaInfo::clearGlobal()
-{
- if (s_global.m_p->m_isInitialized)
- s_global.m_p->clear();
}
-void MetaInfo::setPluginPaths(const QStringList &paths)
+bool MetaInfo::isGlobal() const
{
- s_pluginDirs = paths;
- global();
- clearGlobal();
+ return (this->m_p == s_global.m_p);
}
-bool MetaInfo::isGlobal() const
+MetaInfo MetaInfo::global()
{
- return (this->m_p == s_global.m_p);
+ return s_global;
}
bool operator==(const MetaInfo &first, const MetaInfo &second)
diff --git a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp
index f4b505c4e70..bdb7b63392e 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/nodemetainfo.cpp
@@ -768,7 +768,7 @@ NodeMetaInfoPrivate::NodeMetaInfoPrivate(Model *model, TypeName type, int maj, i
}
} else {
m_isFileComponent = true;
- const Imports *imports = context()->imports(document());
+ const auto *imports = context()->imports(document());
const ImportInfo importInfo = imports->info(lookupNameComponent().constLast(),
context().data());
@@ -791,7 +791,7 @@ NodeMetaInfoPrivate::NodeMetaInfoPrivate(Model *model, TypeName type, int maj, i
} else {
// Special case for aliased types for the rewriter
- const Imports *imports = context()->imports(document());
+ const auto *imports = context()->imports(document());
const ImportInfo importInfo = imports->info(QString::fromUtf8(m_qualfiedTypeName),
context().data());
if (importInfo.isValid()) {
@@ -1198,7 +1198,7 @@ QString NodeMetaInfoPrivate::importDirectoryPath() const
ModelManagerInterface *modelManager = ModelManagerInterface::instance();
if (isValid()) {
- const Imports *imports = context()->imports(document());
+ const auto *imports = context()->imports(document());
ImportInfo importInfo = imports->info(lookupNameComponent().constLast(), context().data());
if (importInfo.type() == ImportType::Directory) {
@@ -1333,7 +1333,7 @@ void NodeMetaInfoPrivate::setupPrototypes()
m_prototypes.append(description);
} else {
if (context()->lookupType(document(), {ov->className()})) {
- const Imports *allImports = context()->imports(document());
+ const auto *allImports = context()->imports(document());
ImportInfo importInfo = allImports->info(description.className, context().data());
if (importInfo.isValid()) {
@@ -1619,16 +1619,20 @@ TypeName NodeMetaInfo::simplifiedTypeName() const
int NodeMetaInfo::majorVersion() const
{
- if (isValid())
- return m_privateData->majorVersion();
+ if constexpr (!useProjectStorage()) {
+ if (isValid())
+ return m_privateData->majorVersion();
+ }
return -1;
}
int NodeMetaInfo::minorVersion() const
{
- if (isValid())
- return m_privateData->minorVersion();
+ if constexpr (!useProjectStorage()) {
+ if (isValid())
+ return m_privateData->minorVersion();
+ }
return -1;
}
@@ -1649,7 +1653,6 @@ QString NodeMetaInfo::importDirectoryPath() const
return {};
}
-#ifdef QDS_USE_PROJECTSTORAGE
const Storage::Info::Type &NodeMetaInfo::typeData() const
{
if (!m_typeData)
@@ -1657,20 +1660,6 @@ const Storage::Info::Type &NodeMetaInfo::typeData() const
return *m_typeData;
}
-#endif
-
-bool NodeMetaInfo::availableInVersion(int majorVersion, int minorVersion) const
-{
- if (!isValid())
- return false;
-
- if (majorVersion == -1 && minorVersion == -1)
- return true;
-
- return (m_privateData->majorVersion() >= majorVersion)
- || (majorVersion == m_privateData->majorVersion()
- && m_privateData->minorVersion() >= minorVersion);
-}
bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int minorVersion) const
{
@@ -1682,7 +1671,7 @@ bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int mino
if (typeName().isEmpty())
return false;
- if (typeName() == type && availableInVersion(majorVersion, minorVersion))
+ if (typeName() == type)
return true;
if (m_privateData->prototypeCachePositives().contains(
@@ -1695,8 +1684,7 @@ bool NodeMetaInfo::isSubclassOf(const TypeName &type, int majorVersion, int mino
const NodeMetaInfos superClassList = superClasses();
for (const NodeMetaInfo &superClass : superClassList) {
- if (superClass.m_privateData->cleverCheckType(type)
- && superClass.availableInVersion(majorVersion, minorVersion)) {
+ if (superClass.m_privateData->cleverCheckType(type)) {
m_privateData->prototypeCachePositives().insert(
stringIdentifier(type, majorVersion, minorVersion));
return true;
@@ -1900,8 +1888,7 @@ bool NodeMetaInfo::isBasedOn(const NodeMetaInfo &metaInfo1,
namespace {
template<const char *moduleName, const char *typeName>
-bool isBasedOnCommonType(NotNullPointer<const ProjectStorage<Sqlite::Database>> projectStorage,
- TypeId typeId)
+bool isBasedOnCommonType(NotNullPointer<const ProjectStorageType> projectStorage, TypeId typeId)
{
auto base = projectStorage->commonTypeId<moduleName, typeName>();
@@ -2047,16 +2034,6 @@ bool NodeMetaInfo::isQtQuickPropertyChanges() const
}
}
-bool NodeMetaInfo::isQuickStateOperation() const
-{
- if constexpr (useProjectStorage()) {
- using namespace Storage::Info;
- return isBasedOnCommonType<QtQuick_cppnative, QuickStateOperation>(m_projectStorage, m_typeId);
- } else {
- return isValid() && isSubclassOf("<cpp>.QQuickStateOperation");
- }
-}
-
bool NodeMetaInfo::isQtSafeRendererSafeRendererPicture() const
{
if constexpr (useProjectStorage()) {
@@ -2279,6 +2256,16 @@ bool NodeMetaInfo::isQtQuick3DInstanceListEntry() const
}
}
+bool NodeMetaInfo::isQtQuick3DLight() const
+{
+ if constexpr (useProjectStorage()) {
+ using namespace Storage::Info;
+ return isBasedOnCommonType<QtQuick3D, Light>(m_projectStorage, m_typeId);
+ } else {
+ return isValid() && isSubclassOf("QtQuick3D.Light");
+ }
+}
+
bool NodeMetaInfo::isQtQuick3DInstanceList() const
{
if constexpr (useProjectStorage()) {
@@ -2320,7 +2307,7 @@ bool NodeMetaInfo::isQtQuick3DParticles3DAttractor3D() const
}
}
-bool NodeMetaInfo::isQuick3DParticleAbstractShape() const
+bool NodeMetaInfo::isQtQuick3DParticleAbstractShape() const
{
if constexpr (useProjectStorage()) {
using namespace Storage::Info;
@@ -2405,7 +2392,8 @@ bool NodeMetaInfo::isQtQuickStateOperation() const
{
if constexpr (useProjectStorage()) {
using namespace Storage::Info;
- return isBasedOnCommonType<QtQuick, QQuickStateOperation>(m_projectStorage, m_typeId);
+ return isBasedOnCommonType<QtQuick_cppnative, QQuickStateOperation>(m_projectStorage,
+ m_typeId);
} else {
return isValid() && isSubclassOf("<cpp>.QQuickStateOperation");
}
@@ -2834,12 +2822,13 @@ bool NodeMetaInfo::isEnumeration() const
return false;
}
-PropertyMetaInfo::PropertyMetaInfo(QSharedPointer<NodeMetaInfoPrivate> nodeMetaInfoPrivateData,
- const PropertyName &propertyName)
+PropertyMetaInfo::PropertyMetaInfo(
+ [[maybe_unused]] QSharedPointer<NodeMetaInfoPrivate> nodeMetaInfoPrivateData,
+ [[maybe_unused]] const PropertyName &propertyName)
+#ifndef QDS_USE_PROJECTSTORAGE
: m_nodeMetaInfoPrivateData{nodeMetaInfoPrivateData}
, m_propertyName{propertyName}
- , m_projectStorage{nullptr}
-
+#endif
{}
PropertyMetaInfo::~PropertyMetaInfo() = default;
@@ -2850,8 +2839,8 @@ NodeMetaInfo PropertyMetaInfo::propertyType() const
return {propertyData().typeId, m_projectStorage};
} else {
if (isValid())
- return NodeMetaInfo{m_nodeMetaInfoPrivateData->model(),
- m_nodeMetaInfoPrivateData->propertyType(m_propertyName),
+ return NodeMetaInfo{nodeMetaInfoPrivateData()->model(),
+ nodeMetaInfoPrivateData()->propertyType(propertyName()),
-1,
-1};
}
@@ -2864,7 +2853,7 @@ PropertyName PropertyMetaInfo::name() const
if constexpr (useProjectStorage())
return PropertyName(Utils::SmallStringView(propertyData().name));
else
- return m_propertyName;
+ return propertyName();
}
bool PropertyMetaInfo::isWritable() const
@@ -2872,7 +2861,7 @@ bool PropertyMetaInfo::isWritable() const
if constexpr (useProjectStorage())
return !(propertyData().traits & Storage::PropertyDeclarationTraits::IsReadOnly);
else
- return isValid() && m_nodeMetaInfoPrivateData->isPropertyWritable(m_propertyName);
+ return isValid() && nodeMetaInfoPrivateData()->isPropertyWritable(propertyName());
}
bool PropertyMetaInfo::isListProperty() const
@@ -2880,7 +2869,7 @@ bool PropertyMetaInfo::isListProperty() const
if constexpr (useProjectStorage())
return propertyData().traits & Storage::PropertyDeclarationTraits::IsList;
else
- return isValid() && m_nodeMetaInfoPrivateData->isPropertyList(m_propertyName);
+ return isValid() && nodeMetaInfoPrivateData()->isPropertyList(propertyName());
}
bool PropertyMetaInfo::isEnumType() const
@@ -2888,7 +2877,7 @@ bool PropertyMetaInfo::isEnumType() const
if constexpr (useProjectStorage())
return propertyType().isEnumeration();
else
- return isValid() && m_nodeMetaInfoPrivateData->isPropertyEnum(m_propertyName);
+ return isValid() && nodeMetaInfoPrivateData()->isPropertyEnum(propertyName());
}
bool PropertyMetaInfo::isPrivate() const
@@ -2896,7 +2885,7 @@ bool PropertyMetaInfo::isPrivate() const
if constexpr (useProjectStorage())
return propertyData().name.startsWith("__");
else
- return isValid() && m_propertyName.startsWith("__");
+ return isValid() && propertyName().startsWith("__");
}
bool PropertyMetaInfo::isPointer() const
@@ -2904,7 +2893,7 @@ bool PropertyMetaInfo::isPointer() const
if constexpr (useProjectStorage())
return propertyData().traits & Storage::PropertyDeclarationTraits::IsPointer;
else
- return isValid() && m_nodeMetaInfoPrivateData->isPropertyPointer(m_propertyName);
+ return isValid() && nodeMetaInfoPrivateData()->isPropertyPointer(propertyName());
}
QVariant PropertyMetaInfo::castedValue(const QVariant &value) const
@@ -2920,7 +2909,7 @@ QVariant PropertyMetaInfo::castedValue(const QVariant &value) const
const TypeName &typeName = propertyTypeName();
- QVariant::Type typeId = m_nodeMetaInfoPrivateData->variantTypeId(m_propertyName);
+ QVariant::Type typeId = nodeMetaInfoPrivateData()->variantTypeId(propertyName());
if (variant.type() == QVariant::UserType
&& variant.userType() == ModelNode::variantUserType()) {
@@ -3012,6 +3001,25 @@ TypeName PropertyMetaInfo::propertyTypeName() const
return propertyType().typeName();
}
+const NodeMetaInfoPrivate *PropertyMetaInfo::nodeMetaInfoPrivateData() const
+{
+#ifndef QDS_USE_PROJECTSTORAGE
+ return m_nodeMetaInfoPrivateData.data();
+#else
+ return nullptr;
+#endif
+}
+
+const PropertyName &PropertyMetaInfo::propertyName() const
+{
+#ifndef QDS_USE_PROJECTSTORAGE
+ return m_propertyName;
+#else
+ static PropertyName dummy;
+ return dummy;
+#endif
+}
+
NodeMetaInfo NodeMetaInfo::commonBase(const NodeMetaInfo &metaInfo) const
{
for (const NodeMetaInfo &info : metaInfo.superClasses()) {
diff --git a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
index e7feb0d4454..0afd0d735c7 100644
--- a/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
+++ b/src/plugins/qmldesigner/designercore/metainfo/subcomponentmanager.cpp
@@ -491,7 +491,7 @@ QStringList SubComponentManager::qmlFiles() const
return m_watcher.files();
}
-void SubComponentManager::update(const QUrl &filePath, const QList<Import> &imports)
+void SubComponentManager::update(const QUrl &filePath, const Imports &imports)
{
if (debug)
qDebug() << Q_FUNC_INFO << filePath << imports.size();
diff --git a/src/plugins/qmldesigner/designercore/model/abstractproperty.cpp b/src/plugins/qmldesigner/designercore/model/abstractproperty.cpp
index 3bccf54660c..00541e12e2f 100644
--- a/src/plugins/qmldesigner/designercore/model/abstractproperty.cpp
+++ b/src/plugins/qmldesigner/designercore/model/abstractproperty.cpp
@@ -39,7 +39,6 @@ AbstractProperty::AbstractProperty(const Internal::InternalPropertyPointer &prop
m_model(model),
m_view(view)
{
- Q_ASSERT(!m_model || m_view);
}
AbstractProperty::AbstractProperty(const AbstractProperty &property, AbstractView *view)
diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
index b9f0315c196..9967d49ee7b 100644
--- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp
@@ -64,8 +64,12 @@ RewriterTransaction AbstractView::beginRewriterTransaction(const QByteArray &ide
ModelNode AbstractView::createModelNode(const TypeName &typeName)
{
- const NodeMetaInfo metaInfo = model()->metaInfo(typeName);
- return createModelNode(typeName, metaInfo.majorVersion(), metaInfo.minorVersion());
+ if constexpr (useProjectStorage()) {
+ return createModelNode(typeName, -1, -1);
+ } else {
+ const NodeMetaInfo metaInfo = model()->metaInfo(typeName);
+ return createModelNode(typeName, metaInfo.majorVersion(), metaInfo.minorVersion());
+ }
}
ModelNode AbstractView::createModelNode(const TypeName &typeName,
@@ -143,9 +147,6 @@ The default implementation is setting the reference of the model to the view.
void AbstractView::modelAttached(Model *model)
{
setModel(model);
-
- if (model)
- model->d->updateEnabledViews();
}
/*!
@@ -315,15 +316,15 @@ void AbstractView::nodeTypeChanged(const ModelNode & /*node*/, const TypeName &
}
-void AbstractView::importsChanged(const QList<Import> &/*addedImports*/, const QList<Import> &/*removedImports*/)
+void AbstractView::importsChanged(const Imports &/*addedImports*/, const Imports &/*removedImports*/)
{
}
-void AbstractView::possibleImportsChanged(const QList<Import> &/*possibleImports*/)
+void AbstractView::possibleImportsChanged(const Imports &/*possibleImports*/)
{
}
-void AbstractView::usedImportsChanged(const QList<Import> &/*usedImports*/)
+void AbstractView::usedImportsChanged(const Imports &/*usedImports*/)
{
}
@@ -617,9 +618,6 @@ bool AbstractView::isEnabled() const
void AbstractView::setEnabled(bool b)
{
m_enabled = b;
-
- if (model())
- model()->d->updateEnabledViews();
}
QList<ModelNode> AbstractView::allModelNodes() const
@@ -893,32 +891,28 @@ QmlTimeline AbstractView::currentTimeline() const
static int getMinorVersionFromImport(const Model *model)
{
- const QList<Import> imports = model->imports();
- for (const Import &import : imports) {
- if (import.isLibraryImport() && import.url() == "QtQuick") {
- const QString versionString = import.version();
- if (versionString.contains(".")) {
- const QString minorVersionString = versionString.split(".").constLast();
- return minorVersionString.toInt();
- }
- }
- }
+ const Imports &imports = model->imports();
+
+ auto found = std::find_if(imports.begin(), imports.end(), [](const auto &import) {
+ return import.url() == "QtQuick";
+ });
+
+ if (found != imports.end())
+ return found->minorVersion();
return -1;
}
static int getMajorVersionFromImport(const Model *model)
{
- const QList<Import> imports = model->imports();
- for (const Import &import : imports) {
- if (import.isLibraryImport() && import.url() == QStringLiteral("QtQuick")) {
- const QString versionString = import.version();
- if (versionString.contains(QStringLiteral("."))) {
- const QString majorVersionString = versionString.split(QStringLiteral(".")).constFirst();
- return majorVersionString.toInt();
- }
- }
- }
+ const Imports &imports = model->imports();
+
+ auto found = std::find_if(imports.begin(), imports.end(), [](const auto &import) {
+ return import.url() == "QtQuick";
+ });
+
+ if (found != imports.end())
+ return found->majorVersion();
return -1;
}
diff --git a/src/plugins/qmldesigner/designercore/model/bindingproperty.cpp b/src/plugins/qmldesigner/designercore/model/bindingproperty.cpp
index 77dbec5e25a..45d4e4cf20e 100644
--- a/src/plugins/qmldesigner/designercore/model/bindingproperty.cpp
+++ b/src/plugins/qmldesigner/designercore/model/bindingproperty.cpp
@@ -56,7 +56,7 @@ void BindingProperty::setExpression(const QString &expression)
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isBindingProperty())
- privateModel()->removeProperty(internalNode()->property(name()));
+ privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->setBindingProperty(internalNode(), name(), expression);
}
@@ -341,7 +341,7 @@ void BindingProperty::setDynamicTypeNameAndExpression(const TypeName &typeName,
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isBindingProperty())
- privateModel()->removeProperty(internalNode()->property(name()));
+ privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->setDynamicBindingProperty(internalNode(), name(), typeName, expression);
}
diff --git a/src/plugins/qmldesigner/designercore/model/import.cpp b/src/plugins/qmldesigner/designercore/model/import.cpp
index 3a6914d3258..54b18810437 100644
--- a/src/plugins/qmldesigner/designercore/model/import.cpp
+++ b/src/plugins/qmldesigner/designercore/model/import.cpp
@@ -5,9 +5,9 @@
#include <QHash>
-namespace QmlDesigner {
+#include <QStringView>
-Import::Import() = default;
+namespace QmlDesigner {
Import Import::createLibraryImport(const QString &url, const QString &version, const QString &alias, const QStringList &importPaths)
{
@@ -62,11 +62,6 @@ QString Import::toString(bool skipAlias, bool skipVersion) const
return result;
}
-bool Import::operator==(const Import &other) const
-{
- return url() == other.url() && file() == other.file() && (version() == other.version() || version().isEmpty() || other.version().isEmpty());
-}
-
bool Import::isSameModule(const Import &other) const
{
if (isLibraryImport())
@@ -85,21 +80,56 @@ int Import::minorVersion() const
return minorFromVersion(m_version);
}
+Version Import::toVersion() const
+{
+ auto found = std::find(m_version.begin(), m_version.end(), u'.');
+ if (found == m_version.end())
+ return {};
+
+ QStringView majorVersionToken{m_version.begin(), found};
+ bool canConvertMajor = false;
+ int majorVersion = majorVersionToken.toInt(&canConvertMajor);
+
+ QStringView minorVersionToken{std::next(found), m_version.end()};
+ bool canConvertMinor = false;
+ int minorVersion = minorVersionToken.toInt(&canConvertMinor);
+
+ if (canConvertMajor && canConvertMinor)
+ return {majorVersion, minorVersion};
+
+ return {};
+}
+
int Import::majorFromVersion(const QString &version)
{
- if (version.isEmpty())
+ auto found = std::find(version.begin(), version.end(), u'.');
+ if (found == version.end())
return -1;
- return version.split('.').first().toInt();
+
+ QStringView majorVersionToken{version.begin(), found};
+ bool canConvert = false;
+ int majorVersion = majorVersionToken.toInt(&canConvert);
+
+ if (canConvert)
+ return majorVersion;
+
+ return -1;
}
int Import::minorFromVersion(const QString &version)
{
- if (version.isEmpty())
+ auto found = std::find(version.begin(), version.end(), u'.');
+ if (found == version.end())
return -1;
- const QStringList parts = version.split('.');
- if (parts.size() < 2)
- return -1;
- return parts[1].toInt();
+
+ QStringView minorVersionToken{std::next(found), version.end()};
+ bool canConvert = false;
+ int minorVersion = minorVersionToken.toInt(&canConvert);
+
+ if (canConvert)
+ return minorVersion;
+
+ return -1;
}
size_t qHash(const Import &import)
@@ -107,4 +137,17 @@ size_t qHash(const Import &import)
return ::qHash(import.url()) ^ ::qHash(import.file()) ^ ::qHash(import.version()) ^ ::qHash(import.alias());
}
+Imports difference(const Imports &first, const Imports &second)
+{
+ Imports difference;
+ difference.reserve(first.size());
+
+ std::set_difference(first.begin(),
+ first.end(),
+ second.begin(),
+ second.end(),
+ std::back_inserter(difference));
+
+ return difference;
+}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp
index a234c11e1fe..844454ae55e 100644
--- a/src/plugins/qmldesigner/designercore/model/model.cpp
+++ b/src/plugins/qmldesigner/designercore/model/model.cpp
@@ -37,6 +37,7 @@
#include <QHashIterator>
#include <QPointer>
#include <QRegularExpression>
+#include <qcompilerdetection.h>
/*!
\defgroup CoreModel
@@ -57,13 +58,15 @@ namespace QmlDesigner {
namespace Internal {
ModelPrivate::ModelPrivate(Model *model,
- ProjectStorage<Sqlite::Database> &projectStorage,
+ ProjectStorageType &projectStorage,
const TypeName &typeName,
int major,
int minor,
- Model *metaInfoProxyModel)
+ Model *metaInfoProxyModel,
+ std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
: projectStorage{&projectStorage}
, m_model{model}
+ , m_resourceManagement{std::move(resourceManagement)}
{
m_metaInfoProxyModel = metaInfoProxyModel;
@@ -74,9 +77,14 @@ ModelPrivate::ModelPrivate(Model *model,
m_currentTimelineNode = m_rootInternalNode;
}
-ModelPrivate::ModelPrivate(
- Model *model, const TypeName &typeName, int major, int minor, Model *metaInfoProxyModel)
+ModelPrivate::ModelPrivate(Model *model,
+ const TypeName &typeName,
+ int major,
+ int minor,
+ Model *metaInfoProxyModel,
+ std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
: m_model(model)
+ , m_resourceManagement{std::move(resourceManagement)}
{
m_metaInfoProxyModel = metaInfoProxyModel;
@@ -95,7 +103,6 @@ void ModelPrivate::detachAllViews()
detachView(view.data(), true);
m_viewList.clear();
- updateEnabledViews();
if (m_nodeInstanceView) {
m_nodeInstanceView->modelAboutToBeDetached(m_model);
@@ -108,10 +115,10 @@ void ModelPrivate::detachAllViews()
}
}
-void ModelPrivate::changeImports(const QList<Import> &toBeAddedImportList,
- const QList<Import> &toBeRemovedImportList)
+void ModelPrivate::changeImports(const Imports &toBeAddedImportList,
+ const Imports &toBeRemovedImportList)
{
- QList<Import> removedImportList;
+ Imports removedImportList;
for (const Import &import : toBeRemovedImportList) {
if (m_imports.contains(import)) {
removedImportList.append(import);
@@ -119,7 +126,7 @@ void ModelPrivate::changeImports(const QList<Import> &toBeAddedImportList,
}
}
- QList<Import> addedImportList;
+ Imports addedImportList;
for (const Import &import : toBeAddedImportList) {
if (!m_imports.contains(import)) {
addedImportList.append(import);
@@ -127,12 +134,13 @@ void ModelPrivate::changeImports(const QList<Import> &toBeAddedImportList,
}
}
+ std::sort(m_imports.begin(), m_imports.end());
+
if (!removedImportList.isEmpty() || !addedImportList.isEmpty())
notifyImportsChanged(addedImportList, removedImportList);
}
-void ModelPrivate::notifyImportsChanged(const QList<Import> &addedImports,
- const QList<Import> &removedImports)
+void ModelPrivate::notifyImportsChanged(const Imports &addedImports, const Imports &removedImports)
{
bool resetModel = false;
QString description;
@@ -157,7 +165,7 @@ void ModelPrivate::notifyImportsChanged(const QList<Import> &addedImports,
resetModelByRewriter(description);
}
-void ModelPrivate::notifyPossibleImportsChanged(const QList<Import> &possibleImports)
+void ModelPrivate::notifyPossibleImportsChanged(const Imports &possibleImports)
{
for (const QPointer<AbstractView> &view : enabledViews()) {
Q_ASSERT(view != nullptr);
@@ -165,7 +173,7 @@ void ModelPrivate::notifyPossibleImportsChanged(const QList<Import> &possibleImp
}
}
-void ModelPrivate::notifyUsedImportsChanged(const QList<Import> &usedImports)
+void ModelPrivate::notifyUsedImportsChanged(const Imports &usedImports)
{
for (const QPointer<AbstractView> &view : enabledViews()) {
Q_ASSERT(view != nullptr);
@@ -210,6 +218,23 @@ void ModelPrivate::changeNodeType(const InternalNodePointer &node, const TypeNam
}
}
+namespace {
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_CLANG("-Wunneeded-internal-declaration")
+
+std::pair<Utils::SmallStringView, Utils::SmallStringView> decomposeTypePath(Utils::SmallStringView typeName)
+{
+ auto found = std::find(typeName.rbegin(), typeName.rend(), '.');
+
+ if (found == typeName.rend())
+ return {};
+
+ return {{typeName.begin(), std::prev(found.base())}, {found.base(), typeName.end()}};
+}
+
+QT_WARNING_POP
+} // namespace
+
InternalNodePointer ModelPrivate::createNode(const TypeName &typeName,
int majorVersion,
int minorVersion,
@@ -229,6 +254,15 @@ InternalNodePointer ModelPrivate::createNode(const TypeName &typeName,
internalId = m_internalIdCounter++;
auto newNode = std::make_shared<InternalNode>(typeName, majorVersion, minorVersion, internalId);
+
+ if constexpr (useProjectStorage()) {
+ auto [moduleName, shortTypeName] = decomposeTypePath(typeName);
+ ModuleId moduleId = projectStorage->moduleId(moduleName);
+ newNode->typeId = projectStorage->typeId(moduleId,
+ shortTypeName,
+ Storage::Version{majorVersion, minorVersion});
+ }
+
newNode->nodeSourceType = nodeSourceType;
newNode->behaviorPropertyName = behaviorPropertyName;
@@ -252,7 +286,9 @@ InternalNodePointer ModelPrivate::createNode(const TypeName &typeName,
notifyNodeCreated(newNode);
if (!newNode->propertyNameList().isEmpty())
- notifyVariantPropertiesChanged(newNode, newNode->propertyNameList(), AbstractView::PropertiesAdded);
+ notifyVariantPropertiesChanged(newNode,
+ newNode->propertyNameList(),
+ AbstractView::PropertiesAdded);
return newNode;
}
@@ -271,9 +307,27 @@ void ModelPrivate::removeNodeFromModel(const InternalNodePointer &node)
m_internalIdNodeHash.remove(node->internalId);
}
-const QList<QPointer<AbstractView>> ModelPrivate::enabledViews() const
+EnabledViewRange ModelPrivate::enabledViews() const
{
- return m_enabledViewList;
+ return EnabledViewRange{m_viewList};
+}
+
+void ModelPrivate::handleResourceSet(const ModelResourceSet &resourceSet)
+{
+ for (const ModelNode &node : resourceSet.removeModelNodes) {
+ if (node)
+ removeNode(node.m_internalNode);
+ }
+
+ for (const AbstractProperty &property : resourceSet.removeProperties) {
+ if (property)
+ removeProperty(property.m_internalNode->property(property.m_propertyName));
+ }
+
+ for (const auto &[property, expression] : resourceSet.setExpressions) {
+ if (property)
+ setBindingProperty(property.m_internalNode, property.m_propertyName, expression);
+ }
}
void ModelPrivate::removeAllSubNodes(const InternalNodePointer &node)
@@ -282,10 +336,16 @@ void ModelPrivate::removeAllSubNodes(const InternalNodePointer &node)
removeNodeFromModel(subNode);
}
-void ModelPrivate::removeNode(const InternalNodePointer &node)
+void ModelPrivate::removeNodeAndRelatedResources(const InternalNodePointer &node)
{
- Q_ASSERT(node);
+ if (m_resourceManagement)
+ handleResourceSet(m_resourceManagement->removeNode(ModelNode{node, m_model, nullptr}));
+ else
+ removeNode(node);
+}
+void ModelPrivate::removeNode(const InternalNodePointer &node)
+{
AbstractView::PropertyChangeFlags propertyChangeFlags = AbstractView::NoAdditionalChanges;
notifyNodeAboutToBeRemoved(node);
@@ -726,7 +786,6 @@ void ModelPrivate::detachView(AbstractView *view, bool notifyView)
if (notifyView)
view->modelAboutToBeDetached(m_model);
m_viewList.removeOne(view);
- updateEnabledViews();
}
void ModelPrivate::notifyNodeCreated(const InternalNodePointer &newInternalNodePointer)
@@ -1062,6 +1121,15 @@ static QList<PropertyPair> toPropertyPairList(const QList<InternalPropertyPointe
return propertyPairList;
}
+void ModelPrivate::removePropertyAndRelatedResources(const InternalPropertyPointer &property)
+{
+ if (m_resourceManagement)
+ handleResourceSet(
+ m_resourceManagement->removeProperty(AbstractProperty{property, m_model, nullptr}));
+ else
+ removeProperty(property);
+}
+
void ModelPrivate::removeProperty(const InternalPropertyPointer &property)
{
notifyPropertiesAboutToBeRemoved({property});
@@ -1289,13 +1357,6 @@ InternalNodePointer ModelPrivate::currentTimelineNode() const
return m_currentTimelineNode;
}
-void ModelPrivate::updateEnabledViews()
-{
- m_enabledViewList = Utils::filtered(m_viewList, [](QPointer<AbstractView> view) {
- return view->isEnabled();
- });
-}
-
InternalNodePointer ModelPrivate::nodeForId(const QString &id) const
{
return m_idNodeHash.value(id);
@@ -1385,89 +1446,80 @@ void WriteLocker::lock(Model *model)
} // namespace Internal
-Model::Model(ProjectStorage<Sqlite::Database> &projectStorage,
+Model::Model(ProjectStorageType &projectStorage,
const TypeName &typeName,
int major,
int minor,
- Model *metaInfoProxyModel)
+ Model *metaInfoProxyModel,
+ std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
: d(std::make_unique<Internal::ModelPrivate>(
- this, projectStorage, typeName, major, minor, metaInfoProxyModel))
+ this, projectStorage, typeName, major, minor, metaInfoProxyModel, std::move(resourceManagement)))
{}
-Model::Model(const TypeName &typeName, int major, int minor, Model *metaInfoProxyModel)
- : d(std::make_unique<Internal::ModelPrivate>(this, typeName, major, minor, metaInfoProxyModel))
+Model::Model(const TypeName &typeName,
+ int major,
+ int minor,
+ Model *metaInfoProxyModel,
+ std::unique_ptr<ModelResourceManagementInterface> resourceManagement)
+ : d(std::make_unique<Internal::ModelPrivate>(
+ this, typeName, major, minor, metaInfoProxyModel, std::move(resourceManagement)))
{}
Model::~Model() = default;
-const QList<Import> &Model::imports() const
+const Imports &Model::imports() const
{
return d->imports();
}
-const QList<Import> &Model::possibleImports() const
+const Imports &Model::possibleImports() const
{
return d->m_possibleImportList;
}
-const QList<Import> &Model::usedImports() const
+const Imports &Model::usedImports() const
{
return d->m_usedImportList;
}
-void Model::changeImports(const QList<Import> &importsToBeAdded,
- const QList<Import> &importsToBeRemoved)
+void Model::changeImports(const Imports &importsToBeAdded, const Imports &importsToBeRemoved)
{
d->changeImports(importsToBeAdded, importsToBeRemoved);
}
-void Model::setPossibleImports(const QList<Import> &possibleImports)
+void Model::setPossibleImports(Imports possibleImports)
{
+ std::sort(possibleImports.begin(), possibleImports.end());
+
if (d->m_possibleImportList != possibleImports) {
- d->m_possibleImportList = possibleImports;
- d->notifyPossibleImportsChanged(possibleImports);
+ d->m_possibleImportList = std::move(possibleImports);
+ d->notifyPossibleImportsChanged(d->m_possibleImportList);
}
}
-void Model::setUsedImports(const QList<Import> &usedImports)
+void Model::setUsedImports(Imports usedImports)
{
+ std::sort(usedImports.begin(), usedImports.end());
+
if (d->m_usedImportList != usedImports) {
- d->m_usedImportList = usedImports;
- d->notifyUsedImportsChanged(usedImports);
+ d->m_usedImportList = std::move(usedImports);
+ d->notifyUsedImportsChanged(d->m_usedImportList);
}
}
-static bool compareVersions(const QString &version1, const QString &version2, bool allowHigherVersion)
+static bool compareVersions(const Import &import1, const Import &import2, bool allowHigherVersion)
{
+ auto version1 = import1.toVersion();
+ auto version2 = import2.toVersion();
+
if (version2.isEmpty())
return true;
if (version1 == version2)
return true;
if (!allowHigherVersion)
return false;
- QStringList version1List = version1.split(QLatin1Char('.'));
- QStringList version2List = version2.split(QLatin1Char('.'));
- if (version1List.count() == 2 && version2List.count() == 2) {
- bool ok;
- int major1 = version1List.constFirst().toInt(&ok);
- if (!ok)
- return false;
- int major2 = version2List.constFirst().toInt(&ok);
- if (!ok)
- return false;
- if (major1 >= major2) {
- int minor1 = version1List.constLast().toInt(&ok);
- if (!ok)
- return false;
- int minor2 = version2List.constLast().toInt(&ok);
- if (!ok)
- return false;
- if (minor1 >= minor2)
- return true;
- }
- }
- return false;
+ return version1 >= version2;
}
bool Model::hasImport(const Import &import, bool ignoreAlias, bool allowHigherVersion) const
@@ -1485,7 +1537,7 @@ bool Model::hasImport(const Import &import, bool ignoreAlias, bool allowHigherVe
}
if (existingImport.isLibraryImport() && import.isLibraryImport()) {
if (existingImport.url() == import.url()
- && compareVersions(existingImport.version(), import.version(), allowHigherVersion)) {
+ && compareVersions(existingImport, import, allowHigherVersion)) {
return true;
}
}
@@ -1627,7 +1679,7 @@ void Model::endDrag()
d->notifyDragEnded();
}
-NotNullPointer<const ProjectStorage<Sqlite::Database>> Model::projectStorage() const
+NotNullPointer<const ProjectStorageType> Model::projectStorage() const
{
return d->projectStorage;
}
@@ -1659,7 +1711,7 @@ bool Model::isImportPossible(const Import &import, bool ignoreAlias, bool allowH
if (possibleImport.isLibraryImport() && import.isLibraryImport()) {
if (possibleImport.url() == import.url()
- && compareVersions(possibleImport.version(), import.version(), allowHigherVersion)) {
+ && compareVersions(possibleImport, import, allowHigherVersion)) {
return true;
}
}
@@ -1694,7 +1746,7 @@ Import Model::highestPossibleImport(const QString &importPath)
for (const Import &import : possibleImports()) {
if (import.url() == importPath) {
- if (candidate.isEmpty() || compareVersions(import.version(), candidate.version(), true))
+ if (candidate.isEmpty() || compareVersions(import, candidate, true))
candidate = import;
}
}
@@ -1804,7 +1856,7 @@ void Model::setMetaInfo(const MetaInfo &metaInfo)
template<const auto &moduleName, const auto &typeName>
NodeMetaInfo Model::createNodeMetaInfo() const
{
- auto typeId = d->projectStorage->commonTypeCache.typeId<moduleName, typeName>();
+ auto typeId = d->projectStorage->commonTypeCache().typeId<moduleName, typeName>();
return {typeId, d->projectStorage};
}
@@ -1939,6 +1991,16 @@ NodeMetaInfo Model::qtQuick3DTextureMetaInfo() const
}
}
+NodeMetaInfo Model::qtQuick3DBakedLightmapMetaInfo() const
+{
+ if constexpr (useProjectStorage()) {
+ using namespace Storage::Info;
+ return createNodeMetaInfo<QtQuick3D, BakedLightmap>();
+ } else {
+ return metaInfo("QtQuick3D.BakedLightmap");
+ }
+}
+
NodeMetaInfo Model::qtQuick3DMaterialMetaInfo() const
{
if constexpr (useProjectStorage()) {
@@ -2070,8 +2132,7 @@ NodeMetaInfo Model::metaInfo(const TypeName &typeName, int majorVersion, int min
ModuleId moduleId = d->projectStorage->moduleId(module);
TypeId typeId = d->projectStorage->typeId(moduleId,
componentName,
- Storage::Synchronization::Version{majorVersion,
- minorVersion});
+ Storage::Version{majorVersion, minorVersion});
return NodeMetaInfo(typeId, d->projectStorage);
} else {
return NodeMetaInfo(metaInfoProxyModel(), typeName, majorVersion, minorVersion);
@@ -2143,4 +2204,9 @@ void Model::detachView(AbstractView *view, ViewNotification emitDetachNotify)
d->detachView(view, emitNotify);
}
+QList<ModelNode> Model::allModelNodes() const
+{
+ return QmlDesigner::toModelNodeList(d->allNodes(), nullptr);
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h
index b08b7388518..b802d703f25 100644
--- a/src/plugins/qmldesigner/designercore/model/model_p.h
+++ b/src/plugins/qmldesigner/designercore/model/model_p.h
@@ -3,17 +3,20 @@
#pragma once
+#include "qmldesignercorelib_global.h"
+
+#include "abstractview.h"
+#include "metainfo.h"
+#include "modelnode.h"
+#include "skipiterator.h"
+
#include <QList>
#include <QPointer>
#include <QSet>
#include <QUrl>
#include <QVector3D>
-#include "modelnode.h"
-#include "abstractview.h"
-#include "metainfo.h"
-
-#include "qmldesignercorelib_global.h"
+#include <algorithm>
QT_BEGIN_NAMESPACE
class QPlainTextEdit;
@@ -64,7 +67,28 @@ private:
QPointer<ModelPrivate> m_model;
};
-class ModelPrivate : public QObject {
+struct Increment
+{
+ using iterator = QList<QPointer<AbstractView>>::const_iterator;
+ auto operator()(iterator current) {
+ return std::find_if(std::next(current),
+ end,
+ [] (iterator::reference &view) { return view && view->isEnabled(); });
+ }
+
+ iterator end;
+};
+
+class EnabledViewRange : public SkipRange<QList<QPointer<AbstractView>>, Increment>
+{
+public:
+ EnabledViewRange(const container &views)
+ : base{views, Increment{views.end()}}
+ {}
+};
+
+class ModelPrivate : public QObject
+{
Q_OBJECT
friend Model;
@@ -73,12 +97,18 @@ class ModelPrivate : public QObject {
public:
ModelPrivate(Model *model,
- ProjectStorage<Sqlite::Database> &projectStorage,
+ ProjectStorageType &projectStorage,
+ const TypeName &type,
+ int major,
+ int minor,
+ Model *metaInfoProxyModel,
+ std::unique_ptr<ModelResourceManagementInterface> resourceManagement);
+ ModelPrivate(Model *model,
const TypeName &type,
int major,
int minor,
- Model *metaInfoProxyModel);
- ModelPrivate(Model *model, const TypeName &type, int major, int minor, Model *metaInfoProxyModel);
+ Model *metaInfoProxyModel,
+ std::unique_ptr<ModelResourceManagementInterface> resourceManagement);
~ModelPrivate() override;
@@ -96,6 +126,7 @@ public:
bool isRootNode = false);
/*factory methods for internal use in model and rewriter*/
+ void removeNodeAndRelatedResources(const InternalNodePointer &node);
void removeNode(const InternalNodePointer &node);
void changeNodeId(const InternalNodePointer &node, const QString &id);
void changeNodeType(const InternalNodePointer &node, const TypeName &typeName, int majorVersion, int minorVersion);
@@ -202,17 +233,16 @@ public:
void resetModelByRewriter(const QString &description);
// Imports:
- const QList<Import> &imports() const { return m_imports; }
- void addImport(const Import &import);
- void removeImport(const Import &import);
- void changeImports(const QList<Import> &importsToBeAdded, const QList<Import> &importToBeRemoved);
- void notifyImportsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports);
- void notifyPossibleImportsChanged(const QList<Import> &possibleImports);
- void notifyUsedImportsChanged(const QList<Import> &usedImportsChanged);
+ const Imports &imports() const { return m_imports; }
+ void changeImports(const Imports &importsToBeAdded, const Imports &importToBeRemoved);
+ void notifyImportsChanged(const Imports &addedImports, const Imports &removedImports);
+ void notifyPossibleImportsChanged(const Imports &possibleImports);
+ void notifyUsedImportsChanged(const Imports &usedImportsChanged);
//node state property manipulation
void addProperty(const InternalNodePointer &node, const PropertyName &name);
void setPropertyValue(const InternalNodePointer &node,const PropertyName &name, const QVariant &value);
+ void removePropertyAndRelatedResources(const InternalPropertyPointer &property);
void removeProperty(const InternalPropertyPointer &property);
void setBindingProperty(const InternalNodePointer &node, const PropertyName &name, const QString &expression);
@@ -251,11 +281,6 @@ public:
InternalNodePointer currentStateNode() const;
InternalNodePointer currentTimelineNode() const;
- void updateEnabledViews();
-
-public:
- NotNullPointer<ProjectStorage<Sqlite::Database>> projectStorage = nullptr;
-
private:
void removePropertyWithoutNotification(const InternalPropertyPointer &property);
void removeAllSubNodes(const InternalNodePointer &node);
@@ -264,16 +289,19 @@ private:
QList<ModelNode> toModelNodeList(const QList<InternalNodePointer> &nodeList, AbstractView *view) const;
QVector<ModelNode> toModelNodeVector(const QVector<InternalNodePointer> &nodeVector, AbstractView *view) const;
QVector<InternalNodePointer> toInternalNodeVector(const QVector<ModelNode> &modelNodeVector) const;
- const QList<QPointer<AbstractView>> enabledViews() const;
+ EnabledViewRange enabledViews() const;
+ void handleResourceSet(const ModelResourceSet &resourceSet);
+
+public:
+ NotNullPointer<ProjectStorageType> projectStorage = nullptr;
private:
Model *m_model = nullptr;
MetaInfo m_metaInfo;
- QList<Import> m_imports;
- QList<Import> m_possibleImportList;
- QList<Import> m_usedImportList;
+ Imports m_imports;
+ Imports m_possibleImportList;
+ Imports m_usedImportList;
QList<QPointer<AbstractView>> m_viewList;
- QList<QPointer<AbstractView>> m_enabledViewList;
QList<InternalNodePointer> m_selectedInternalNodeList;
QHash<QString,InternalNodePointer> m_idNodeHash;
QHash<qint32, InternalNodePointer> m_internalIdNodeHash;
@@ -281,6 +309,7 @@ private:
InternalNodePointer m_currentStateNode;
InternalNodePointer m_rootInternalNode;
InternalNodePointer m_currentTimelineNode;
+ std::unique_ptr<ModelResourceManagementInterface> m_resourceManagement;
QUrl m_fileUrl;
QPointer<RewriterView> m_rewriterView;
QPointer<NodeInstanceView> m_nodeInstanceView;
diff --git a/src/plugins/qmldesigner/designercore/model/modelmerger.cpp b/src/plugins/qmldesigner/designercore/model/modelmerger.cpp
index 75cdcf83582..30d100f3503 100644
--- a/src/plugins/qmldesigner/designercore/model/modelmerger.cpp
+++ b/src/plugins/qmldesigner/designercore/model/modelmerger.cpp
@@ -173,7 +173,7 @@ ModelNode ModelMerger::insertModel(const ModelNode &modelNode, const MergePredic
return {};
RewriterTransaction transaction(view()->beginRewriterTransaction(QByteArrayLiteral("ModelMerger::insertModel")));
- QList<Import> newImports;
+ Imports newImports;
for (const Import &import : modelNode.model()->imports()) {
if (!view()->model()->hasImport(import, true, true))
diff --git a/src/plugins/qmldesigner/designercore/model/modelnode.cpp b/src/plugins/qmldesigner/designercore/model/modelnode.cpp
index aab0d13c249..7e64f4c4bf4 100644
--- a/src/plugins/qmldesigner/designercore/model/modelnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/modelnode.cpp
@@ -61,7 +61,6 @@ ModelNode::ModelNode(const InternalNodePointer &internalNode, Model *model, cons
m_model(model),
m_view(const_cast<AbstractView*>(view))
{
- Q_ASSERT(!m_model || m_view);
}
ModelNode::ModelNode(const ModelNode &modelNode, AbstractView *view)
@@ -291,7 +290,7 @@ A node might become invalid if e.g. it or one of its ancestors is deleted.
*/
bool ModelNode::isValid() const
{
- return !m_model.isNull() && !m_view.isNull() && m_internalNode && m_internalNode->isValid;
+ return !m_model.isNull() && m_internalNode && m_internalNode->isValid;
}
/*!
@@ -653,7 +652,7 @@ void ModelNode::removeProperty(const PropertyName &name) const
return;
if (m_internalNode->hasProperty(name))
- model()->d->removeProperty(m_internalNode->property(name));
+ model()->d->removePropertyAndRelatedResources(m_internalNode->property(name));
}
/*! \brief removes this node from the node tree
@@ -693,7 +692,7 @@ void ModelNode::destroy()
return;
removeModelNodeFromSelection(*this);
- model()->d->removeNode(m_internalNode);
+ model()->d->removeNodeAndRelatedResources(m_internalNode);
}
//\}
diff --git a/src/plugins/qmldesigner/designercore/model/modelresourcemanagementinterface.h b/src/plugins/qmldesigner/designercore/model/modelresourcemanagementinterface.h
new file mode 100644
index 00000000000..b2188132d6a
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/model/modelresourcemanagementinterface.h
@@ -0,0 +1,39 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <qmldesignercorelib_exports.h>
+
+#include <bindingproperty.h>
+
+namespace QmlDesigner {
+
+struct ModelResourceSet
+{
+ struct SetExpression
+ {
+ BindingProperty property;
+ QString expression;
+ };
+
+ QList<ModelNode> removeModelNodes;
+ QList<AbstractProperty> removeProperties;
+ QList<SetExpression> setExpressions;
+};
+
+class QMLDESIGNERCORE_EXPORT ModelResourceManagementInterface
+{
+public:
+ ModelResourceManagementInterface() = default;
+ virtual ~ModelResourceManagementInterface() = default;
+
+ ModelResourceManagementInterface(const ModelResourceManagementInterface &) = delete;
+ ModelResourceManagementInterface &operator=(const ModelResourceManagementInterface &) = delete;
+ ModelResourceManagementInterface(ModelResourceManagementInterface &&) = default;
+ ModelResourceManagementInterface &operator=(ModelResourceManagementInterface &&) = default;
+
+ virtual ModelResourceSet removeNode(const ModelNode &node) const = 0;
+ virtual ModelResourceSet removeProperty(const AbstractProperty &property) const = 0;
+};
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/model/modelutils.cpp b/src/plugins/qmldesigner/designercore/model/modelutils.cpp
new file mode 100644
index 00000000000..2e454527b88
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/model/modelutils.cpp
@@ -0,0 +1,93 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "modelutils.h"
+
+#include <utils/expected.h>
+
+#include <algorithm>
+
+namespace QmlDesigner::Utils {
+
+namespace {
+
+enum class ImportError { EmptyImportName, HasAlreadyImport, NoModule };
+
+::Utils::expected<Import, ImportError> findImport(const QString &importName,
+ const std::function<bool(const Import &)> &predicate,
+ const Imports &imports,
+ const Imports &modules)
+{
+ if (importName.isEmpty())
+ return ::Utils::make_unexpected(ImportError::EmptyImportName);
+
+ auto hasName = [&](const auto &import) {
+ return import.url() == importName || import.file() == importName;
+ };
+
+ bool hasImport = std::any_of(imports.begin(), imports.end(), hasName);
+
+ if (hasImport)
+ return ::Utils::make_unexpected(ImportError::HasAlreadyImport);
+
+ auto foundModule = std::find_if(modules.begin(), modules.end(), [&](const Import &import) {
+ return hasName(import) && predicate(import);
+ });
+
+ if (foundModule == modules.end())
+ return ::Utils::make_unexpected(ImportError::NoModule);
+
+ return *foundModule;
+}
+
+} // namespace
+
+bool addImportWithCheck(const QString &importName,
+ const std::function<bool(const Import &)> &predicate,
+ Model *model)
+{
+ return addImportsWithCheck({importName}, predicate, model);
+}
+
+bool addImportWithCheck(const QString &importName, Model *model)
+{
+ return addImportWithCheck(
+ importName, [](const Import &) { return true; }, model);
+}
+
+bool addImportsWithCheck(const QStringList &importNames, Model *model)
+{
+ return addImportsWithCheck(
+ importNames, [](const Import &) { return true; }, model);
+}
+
+bool addImportsWithCheck(const QStringList &importNames,
+ const std::function<bool(const Import &)> &predicate,
+ Model *model)
+{
+ const Imports &imports = model->imports();
+ const Imports &modules = model->possibleImports();
+
+ Imports importsToAdd;
+ importsToAdd.reserve(importNames.size());
+
+ for (const QString &importName : importNames) {
+ auto import = findImport(importName, predicate, imports, modules);
+
+ if (import) {
+ importsToAdd.push_back(*import);
+ } else {
+ if (import.error() == ImportError::NoModule)
+ return false;
+ else
+ continue;
+ }
+ }
+
+ if (!importsToAdd.isEmpty())
+ model->changeImports(std::move(importsToAdd), {});
+
+ return true;
+}
+
+} // namespace QmlDesigner::Utils
diff --git a/src/plugins/qmldesigner/designercore/model/modelutils.h b/src/plugins/qmldesigner/designercore/model/modelutils.h
new file mode 100644
index 00000000000..58055f39065
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/model/modelutils.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "qmldesignercorelib_global.h"
+
+#include <import.h>
+#include <model.h>
+
+#include <functional>
+
+namespace QmlDesigner::Utils {
+
+QMLDESIGNERCORE_EXPORT bool addImportsWithCheck(const QStringList &importNames,
+ const std::function<bool(const Import &)> &predicate,
+ Model *model);
+QMLDESIGNERCORE_EXPORT bool addImportsWithCheck(const QStringList &importNames, Model *model);
+QMLDESIGNERCORE_EXPORT bool addImportWithCheck(const QString &importName,
+ const std::function<bool(const Import &)> &predicate,
+ Model *model);
+QMLDESIGNERCORE_EXPORT bool addImportWithCheck(const QString &importName, Model *model);
+
+} // namespace QmlDesigner::Utils
diff --git a/src/plugins/qmldesigner/designercore/model/nodeabstractproperty.cpp b/src/plugins/qmldesigner/designercore/model/nodeabstractproperty.cpp
index e2ef9d76f06..60b4e77dc6d 100644
--- a/src/plugins/qmldesigner/designercore/model/nodeabstractproperty.cpp
+++ b/src/plugins/qmldesigner/designercore/model/nodeabstractproperty.cpp
@@ -71,7 +71,7 @@ void NodeAbstractProperty::reparentHere(const ModelNode &modelNode, bool isNode
return;
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isNodeAbstractProperty())
- privateModel()->removeProperty(internalNode()->property(name()));
+ privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
if (modelNode.hasParentProperty()) {
Internal::InternalNodeAbstractProperty::Pointer oldParentProperty = modelNode.internalNode()->parentProperty();
diff --git a/src/plugins/qmldesigner/designercore/model/nodeproperty.cpp b/src/plugins/qmldesigner/designercore/model/nodeproperty.cpp
index a9cc7a34f54..4af8428e6be 100644
--- a/src/plugins/qmldesigner/designercore/model/nodeproperty.cpp
+++ b/src/plugins/qmldesigner/designercore/model/nodeproperty.cpp
@@ -32,7 +32,7 @@ void NodeProperty::setModelNode(const ModelNode &modelNode)
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isNodeProperty())
- privateModel()->removeProperty(internalNode()->property(name()));
+ privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->reparentNode(internalNode(), name(), modelNode.internalNode(), false); //### we have to add a flag that this is not a list
}
diff --git a/src/plugins/qmldesigner/designercore/model/plaintexteditmodifier.cpp b/src/plugins/qmldesigner/designercore/model/plaintexteditmodifier.cpp
index 2318c3f2cf0..a1f88b3a687 100644
--- a/src/plugins/qmldesigner/designercore/model/plaintexteditmodifier.cpp
+++ b/src/plugins/qmldesigner/designercore/model/plaintexteditmodifier.cpp
@@ -3,12 +3,16 @@
#include "plaintexteditmodifier.h"
-#include <utils/changeset.h>
#include <qmljs/qmljsmodelmanagerinterface.h>
-#include <QPlainTextEdit>
+#include <qmljstools/qmljscodestylepreferences.h>
+#include <qmljstools/qmljsindenter.h>
+#include <qmljstools/qmljstoolssettings.h>
+
+#include <utils/changeset.h>
#include <QDebug>
+#include <QPlainTextEdit>
using namespace Utils;
using namespace QmlDesigner;
@@ -161,3 +165,41 @@ void PlainTextEditModifier::reactivateChangeSignals()
emit textChanged();
}
}
+
+IndentingTextEditModifier::IndentingTextEditModifier(QTextDocument *document, const QTextCursor &textCursor)
+ : NotIndentingTextEditModifier{document, textCursor}
+{
+ m_tabSettings = QmlJSTools::QmlJSToolsSettings::globalCodeStyle()->tabSettings();
+}
+
+void IndentingTextEditModifier::indent(int offset, int length)
+{
+ if (length == 0 || offset < 0 || offset + length >= text().length())
+ return;
+
+ int startLine = getLineInDocument(textDocument(), offset);
+ int endLine = getLineInDocument(textDocument(), offset + length);
+
+ if (startLine > -1 && endLine > -1)
+ indentLines(startLine, endLine);
+}
+
+void IndentingTextEditModifier::indentLines(int startLine, int endLine)
+{
+ if (startLine < 0)
+ return;
+
+ QTextCursor tc(textDocument());
+
+ tc.beginEditBlock();
+ for (int i = startLine; i <= endLine; i++) {
+ QTextBlock start = textDocument()->findBlockByNumber(i);
+
+ if (start.isValid()) {
+ QmlJSEditor::Internal::Indenter indenter(textDocument());
+ indenter.indentBlock(start, QChar::Null, m_tabSettings);
+ }
+ }
+ tc.endEditBlock();
+}
+
diff --git a/src/plugins/qmldesigner/designercore/model/qmlchangeset.cpp b/src/plugins/qmldesigner/designercore/model/qmlchangeset.cpp
index 5029fdc79d3..134c4bf1c20 100644
--- a/src/plugins/qmldesigner/designercore/model/qmlchangeset.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmlchangeset.cpp
@@ -76,7 +76,7 @@ bool QmlModelStateOperation::isValid() const
bool QmlModelStateOperation::isValidQmlModelStateOperation(const ModelNode &modelNode)
{
- return isValidQmlModelNodeFacade(modelNode) && modelNode.metaInfo().isQuickStateOperation();
+ return isValidQmlModelNodeFacade(modelNode) && modelNode.metaInfo().isQtQuickStateOperation();
}
void QmlPropertyChanges::removeProperty(const PropertyName &name)
diff --git a/src/plugins/qmldesigner/designercore/model/qmlmodelnodefacade.cpp b/src/plugins/qmldesigner/designercore/model/qmlmodelnodefacade.cpp
index 47699eae468..7e3bc793247 100644
--- a/src/plugins/qmldesigner/designercore/model/qmlmodelnodefacade.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmlmodelnodefacade.cpp
@@ -29,8 +29,6 @@ const NodeInstanceView *QmlModelNodeFacade::nodeInstanceView() const
return nodeInstanceView(m_modelNode);
}
-QmlModelNodeFacade::~QmlModelNodeFacade() = default;
-
bool QmlModelNodeFacade::hasModelNode() const
{
return m_modelNode.isValid();
diff --git a/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp b/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp
index c3ee4b975f7..3831a90d97c 100644
--- a/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp
+++ b/src/plugins/qmldesigner/designercore/model/qmlvisualnode.cpp
@@ -291,6 +291,7 @@ static QmlObjectNode createQmlObjectNodeFromSource(AbstractView *view,
rewriterView->setCheckSemanticErrors(false);
rewriterView->setTextModifier(&modifier);
rewriterView->setAllowComponentRoot(true);
+ rewriterView->setPossibleImportsEnabled(false);
inputModel->setRewriterView(rewriterView.data());
if (rewriterView->errors().isEmpty() && rewriterView->rootModelNode().isValid()) {
diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
index d8088de64be..53a0f4de596 100644
--- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
+++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp
@@ -261,7 +261,7 @@ void RewriterView::nodeReparented(const ModelNode &node, const NodeAbstractPrope
applyChanges();
}
-void RewriterView::importsChanged(const QList<Import> &addedImports, const QList<Import> &removedImports)
+void RewriterView::importsChanged(const Imports &addedImports, const Imports &removedImports)
{
for (const Import &import : addedImports)
importAdded(import);
diff --git a/src/plugins/qmldesigner/designercore/model/signalhandlerproperty.cpp b/src/plugins/qmldesigner/designercore/model/signalhandlerproperty.cpp
index 205105187d1..4690044fa61 100644
--- a/src/plugins/qmldesigner/designercore/model/signalhandlerproperty.cpp
+++ b/src/plugins/qmldesigner/designercore/model/signalhandlerproperty.cpp
@@ -41,7 +41,7 @@ void SignalHandlerProperty::setSource(const QString &source)
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isSignalHandlerProperty())
- privateModel()->removeProperty(internalNode()->property(name()));
+ privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->setSignalHandlerProperty(internalNode(), name(), source);
}
@@ -118,7 +118,7 @@ void SignalDeclarationProperty::setSignature(const QString &signature)
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isSignalDeclarationProperty())
- privateModel()->removeProperty(internalNode()->property(name()));
+ privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->setSignalDeclarationProperty(internalNode(), name(), signature);
}
diff --git a/src/plugins/qmldesigner/designercore/model/skipiterator.h b/src/plugins/qmldesigner/designercore/model/skipiterator.h
new file mode 100644
index 00000000000..11efb7d97f0
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/model/skipiterator.h
@@ -0,0 +1,77 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <iterator>
+
+namespace QmlDesigner {
+
+template<typename BaseIterator, typename Increment>
+class SkipIterator
+{
+public:
+ using iterator_category = std::forward_iterator_tag;
+ using difference_type = qsizetype;
+ using value_type = typename BaseIterator::value_type;
+ using pointer = typename BaseIterator::pointer;
+ using reference = typename BaseIterator::reference;
+
+ SkipIterator() = default;
+ SkipIterator(BaseIterator current, Increment increment)
+ : m_current{current}
+ , m_increment{std::move(increment)}
+ {}
+
+ SkipIterator operator++()
+ {
+ m_current = m_increment(m_current);
+ return *this;
+ }
+
+ SkipIterator operator++(int)
+ {
+ auto tmp = *this;
+ m_current = m_increment(m_current);
+ return tmp;
+ }
+
+ reference operator*() const { return *m_current; }
+ pointer operator->() const { return m_current.operator->(); }
+
+ friend bool operator==(const SkipIterator &first, const SkipIterator &second)
+ {
+ return first.m_current == second.m_current;
+ }
+
+ friend bool operator!=(const SkipIterator &first, const SkipIterator &second)
+ {
+ return first.m_current != second.m_current;
+ }
+
+private:
+ BaseIterator m_current = {};
+ Increment m_increment;
+};
+
+template<typename Container, typename Increment>
+class SkipRange
+{
+public:
+ using container = Container;
+ using base = SkipRange<Container, Increment>;
+ using iterator = SkipIterator<typename Container::const_iterator, Increment>;
+
+ SkipRange(const Container &container, Increment increment)
+ : m_begin{container.begin(), increment}
+ , m_end{container.end(), increment}
+ {}
+
+ iterator begin() const { return m_begin; }
+ iterator end() const { return m_end; }
+
+private:
+ iterator m_begin;
+ iterator m_end;
+};
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
index 4469793db83..ac89c54acd6 100644
--- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
+++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp
@@ -19,6 +19,8 @@
#include "signalhandlerproperty.h"
#include "variantproperty.h"
#include <externaldependenciesinterface.h>
+#include <import.h>
+#include <projectstorage/modulescanner.h>
#include <rewritingexception.h>
#include <enumeration.h>
@@ -44,6 +46,7 @@
#include <QSet>
#include <memory>
+#include <tuple>
using namespace LanguageUtils;
using namespace QmlJS;
@@ -59,12 +62,15 @@ bool isSupportedAttachedProperties(const QString &propertyName)
|| propertyName.startsWith(QLatin1String("InsightCategory."));
}
-QStringList supportedVersionsList()
+bool isSupportedVersion(QmlDesigner::Version version)
{
- static const QStringList list = {"2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6",
- "2.7", "2.8", "2.9", "2.10", "2.11", "2.12", "2.13",
- "2.14", "2.15", "6.0", "6.1", "6.2", "6.3", "6.4"};
- return list;
+ if (version.major == 2)
+ return version.minor <= 15;
+
+ if (version.major == 6)
+ return version.minor <= 5;
+
+ return false;
}
QStringList globalQtEnums()
@@ -99,13 +105,15 @@ QStringList knownEnumScopes()
"Grid",
"ItemLayer",
"ImageLayer",
- "SpriteLayer"};
+ "SpriteLayer",
+ "Light"};
return list;
}
-bool supportedQtQuickVersion(const QString &version)
+bool supportedQtQuickVersion(const QmlDesigner::Import &import)
{
- return version.isEmpty() || supportedVersionsList().contains(version);
+ auto version = import.toVersion();
+ return version.isEmpty() || isSupportedVersion(version);
}
QString stripQuotes(const QString &str)
@@ -117,7 +125,7 @@ QString stripQuotes(const QString &str)
return str;
}
-inline QString deEscape(const QString &value)
+QString deEscape(const QString &value)
{
QString result = value;
@@ -282,7 +290,7 @@ bool isComponentType(const QmlDesigner::TypeName &type)
{
return type == "Component" || type == "Qt.Component" || type == "QtQuick.Component"
|| type == "QtQml.Component" || type == "<cpp>.QQmlComponent" || type == "QQmlComponent"
- || type == "QML.Component";
+ || type == "QML.Component" || type == "QtQml.Base.Component";
}
bool isCustomParserType(const QmlDesigner::TypeName &type)
@@ -302,7 +310,8 @@ bool isPropertyChangesType(const QmlDesigner::TypeName &type)
bool isConnectionsType(const QmlDesigner::TypeName &type)
{
- return type == "Connections" || type == "QtQuick.Connections" || type == "Qt.Connections" || type == "QtQml.Connections";
+ return type == "Connections" || type == "QtQuick.Connections" || type == "Qt.Connections"
+ || type == "QtQml.Connections" || type == "QtQml.Base.Connections";
}
bool propertyIsComponentType(const QmlDesigner::NodeAbstractProperty &property, const QmlDesigner::TypeName &type, QmlDesigner::Model *model)
@@ -716,7 +725,7 @@ bool TextToModelMerger::isActive() const
void TextToModelMerger::setupImports(const Document::Ptr &doc,
DifferenceHandler &differenceHandler)
{
- QList<Import> existingImports = m_rewriterView->model()->imports();
+ Imports existingImports = m_rewriterView->model()->imports();
m_hasVersionlessImport = false;
@@ -756,162 +765,143 @@ void TextToModelMerger::setupImports(const Document::Ptr &doc,
differenceHandler.importAbsentInQMl(import);
}
-static bool isLatestImportVersion(const ImportKey &importKey, const QHash<QString, ImportKey> &filteredPossibleImportKeys)
+namespace {
+
+bool skipByMetaInfo(QStringView moduleName, const QStringList &skipModuleNames)
{
- return !filteredPossibleImportKeys.contains(importKey.path())
- || filteredPossibleImportKeys.value(importKey.path()).majorVersion < importKey.majorVersion
- || (filteredPossibleImportKeys.value(importKey.path()).majorVersion == importKey.majorVersion
- && filteredPossibleImportKeys.value(importKey.path()).minorVersion < importKey.minorVersion);
+ return std::any_of(skipModuleNames.begin(),
+ skipModuleNames.end(),
+ [&](const QString &skipModuleName) {
+ return moduleName.contains(skipModuleName);
+ });
}
-static bool filterByMetaInfo(const ImportKey &importKey, Model *model)
+class StartsWith : public QStringView
{
- if (model) {
- for (const QString &filter : model->metaInfo().itemLibraryInfo()->blacklistImports()) {
- if (importKey.libraryQualifiedPath().contains(filter))
- return true;
- }
+public:
+ using QStringView::QStringView;
+ bool operator()(QStringView moduleName) const { return moduleName.startsWith(*this); }
+};
+
+class EndsWith : public QStringView
+{
+public:
+ using QStringView::QStringView;
+ bool operator()(QStringView moduleName) const { return moduleName.endsWith(*this); }
+};
+class StartsAndEndsWith : public std::pair<QStringView, QStringView>
+{
+public:
+ using Base = std::pair<QStringView, QStringView>;
+ using Base::Base;
+ bool operator()(QStringView moduleName) const
+ {
+ return moduleName.startsWith(first) && moduleName.endsWith(second);
}
+};
- return false;
-}
+class Equals : public QStringView
+{
+public:
+ using QStringView::QStringView;
+ bool operator()(QStringView moduleName) const { return moduleName == *this; }
+};
-static bool isBlacklistImport(const ImportKey &importKey, Model *model)
-{
- const QString &importPathFirst = importKey.splitPath.constFirst();
- const QString &importPathLast = importKey.splitPath.constLast();
- return importPathFirst == QStringLiteral("<cpp>")
- || importPathFirst == QStringLiteral("QML")
- || importPathFirst == QStringLiteral("QtQml")
- || (importPathFirst == QStringLiteral("QtQuick") && importPathLast == QStringLiteral("PrivateWidgets"))
- || importPathLast == QStringLiteral("Private")
- || importPathLast == QStringLiteral("private")
- || importKey.libraryQualifiedPath() == QStringLiteral("QtQuick.Particles") //Unsupported
- || importKey.libraryQualifiedPath() == QStringLiteral("QtQuick.Dialogs") //Unsupported
- || importKey.libraryQualifiedPath() == QStringLiteral("QtQuick.Controls.Styles") //Unsupported
- || importKey.libraryQualifiedPath() == QStringLiteral("QtNfc") //Unsupported
- || importKey.libraryQualifiedPath() == QStringLiteral("Qt.WebSockets")
- || importKey.libraryQualifiedPath() == QStringLiteral("QtWebkit")
- || importKey.libraryQualifiedPath() == QStringLiteral("QtLocation")
- || importKey.libraryQualifiedPath() == QStringLiteral("QtWebChannel")
- || importKey.libraryQualifiedPath() == QStringLiteral("QtWinExtras")
- || importKey.libraryQualifiedPath() == QStringLiteral("QtPurchasing")
- || importKey.libraryQualifiedPath() == QStringLiteral("QtBluetooth")
- || importKey.libraryQualifiedPath() == QStringLiteral("Enginio")
-
- || filterByMetaInfo(importKey, model);
-}
-
-static QHash<QString, ImportKey> filterPossibleImportKeys(const QSet<ImportKey> &possibleImportKeys, Model *model)
-{
- QHash<QString, ImportKey> filteredPossibleImportKeys;
- for (const ImportKey &importKey : possibleImportKeys) {
- if (isLatestImportVersion(importKey, filteredPossibleImportKeys) && !isBlacklistImport(importKey, model))
- filteredPossibleImportKeys.insert(importKey.path(), importKey);
- }
+constexpr auto skipModules = std::make_tuple(EndsWith(u".impl"),
+ StartsWith(u"QML"),
+ StartsWith(u"QtQml"),
+ StartsAndEndsWith(u"QtQuick", u".PrivateWidgets"),
+ EndsWith(u".private"),
+ EndsWith(u".Private"),
+ Equals(u"QtQuick.Particles"),
+ Equals(u"QtQuick.Dialogs"),
+ Equals(u"QtQuick.Controls.Styles"),
+ Equals(u"QtNfc"),
+ Equals(u"Qt.WebSockets"),
+ Equals(u"QtWebkit"),
+ Equals(u"QtLocation"),
+ Equals(u"QtWebChannel"),
+ Equals(u"QtWinExtras"),
+ Equals(u"QtPurchasing"),
+ Equals(u"QtBluetooth"),
+ Equals(u"Enginio"));
- return filteredPossibleImportKeys;
+bool skipModule(QStringView moduleName)
+{
+ return std::apply([=](const auto &...skipModule) { return (skipModule(moduleName) || ...); },
+ skipModules);
}
-static void removeUsedImports(QHash<QString, ImportKey> &filteredPossibleImportKeys, const QList<QmlJS::Import> &usedImports)
+bool skipModule(QStringView moduleName, const QStringList &skipModuleNames)
{
- for (const QmlJS::Import &import : usedImports)
- filteredPossibleImportKeys.remove(import.info.path());
+ return skipModule(moduleName) || skipByMetaInfo(moduleName, skipModuleNames);
}
-static QList<QmlDesigner::Import> generatePossibleFileImports(const QString &path,
- const QList<QmlJS::Import> &usedImports)
+void collectPossibleFileImports(const QString &checkPath,
+ QSet<QString> usedImportsSet,
+ QList<QmlDesigner::Import> &possibleImports)
{
- QSet<QString> usedImportsSet;
- for (const QmlJS::Import &i : usedImports)
- usedImportsSet.insert(i.info.path());
-
- QList<QmlDesigner::Import> possibleImports;
const QStringList qmlList("*.qml");
const QStringList qmldirList("qmldir");
-
- QStringList fileImportPaths;
const QChar delimeter('/');
- std::function<void(const QString &)> checkDir;
- checkDir = [&](const QString &checkPath) {
-
- if (QFileInfo(checkPath).isRoot())
- return;
+ if (QFileInfo(checkPath).isRoot())
+ return;
- const QStringList entries = QDir(checkPath).entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot);
- const QString checkPathDelim = checkPath + delimeter;
- for (const QString &entry : entries) {
- QDir dir(checkPathDelim + entry);
- const QString dirPath = dir.path();
- if (!dir.entryInfoList(qmlList, QDir::Files).isEmpty()
- && dir.entryInfoList(qmldirList, QDir::Files).isEmpty()
- && !usedImportsSet.contains(dirPath)) {
- const QString importName = dir.path().mid(path.size() + 1);
- QmlDesigner::Import import = QmlDesigner::Import::createFileImport(importName);
- possibleImports.append(import);
- }
- checkDir(dirPath);
+ const QStringList entries = QDir(checkPath).entryList(QDir::Dirs | QDir::NoDot | QDir::NoDotDot);
+ const QString checkPathDelim = checkPath + delimeter;
+ for (const QString &entry : entries) {
+ QDir dir(checkPathDelim + entry);
+ const QString dirPath = dir.path();
+ if (!dir.entryInfoList(qmlList, QDir::Files).isEmpty()
+ && dir.entryInfoList(qmldirList, QDir::Files).isEmpty()
+ && !usedImportsSet.contains(dirPath)) {
+ const QString importName = dir.path().mid(checkPath.size() + 1);
+ QmlDesigner::Import import = QmlDesigner::Import::createFileImport(importName);
+ possibleImports.append(import);
}
- };
- checkDir(path);
-
- return possibleImports;
+ collectPossibleFileImports(dirPath, usedImportsSet, possibleImports);
+ }
}
-static QList<QmlDesigner::Import> generatePossibleLibraryImports(const QHash<QString, ImportKey> &filteredPossibleImportKeys)
+QList<QmlDesigner::Import> generatePossibleFileImports(const QString &path,
+ const QList<QmlJS::Import> &usedImports)
{
- QList<QmlDesigner::Import> possibleImports;
- QSet<QString> controlsImplVersions;
- bool hasVersionedControls = false;
- bool hasVersionlessControls = false;
- const QString controlsName = "QtQuick.Controls";
- const QString controlsImplName = "QtQuick.Controls.impl";
-
- for (const ImportKey &importKey : filteredPossibleImportKeys) {
- QString libraryName = importKey.splitPath.join(QLatin1Char('.'));
- int majorVersion = importKey.majorVersion;
- if (majorVersion >= 0) {
- int minorVersion = (importKey.minorVersion == LanguageUtils::ComponentVersion::NoVersion) ? 0 : importKey.minorVersion;
-
- if (libraryName.contains("QtQuick.Studio")) {
- majorVersion = 1;
- minorVersion = 0;
- }
+ QSet<QString> usedImportsSet;
+ for (const QmlJS::Import &i : usedImports)
+ usedImportsSet.insert(i.info.path());
- QString version = QStringLiteral("%1.%2").arg(majorVersion).arg(minorVersion);
- if (!libraryName.endsWith(".impl"))
- possibleImports.append(QmlDesigner::Import::createLibraryImport(libraryName, version));
-
- // In Qt6, QtQuick.Controls itself doesn't have any version as it has no types,
- // so it never gets added normally to possible imports.
- // We work around this by injecting corresponding QtQuick.Controls version for each
- // found impl version, if no valid QtQuick.Controls versions are found.
- if (!hasVersionedControls) {
- if (libraryName == controlsImplName)
- controlsImplVersions.insert(version);
- else if (libraryName == controlsName)
- hasVersionedControls = true;
- }
- } else if (!hasVersionlessControls && libraryName == controlsName) {
- // If QtQuick.Controls module is not included even in non-versioned, it means
- // QtQuick.Controls is either in use or not available at all,
- // so we shouldn't inject it.
- hasVersionlessControls = true;
- }
- }
+ QList<QmlDesigner::Import> possibleImports;
- if (hasVersionlessControls && !hasVersionedControls && !controlsImplVersions.isEmpty()) {
- for (const auto &version : std::as_const(controlsImplVersions))
- possibleImports.append(QmlDesigner::Import::createLibraryImport(controlsName, version));
- }
+ QStringList fileImportPaths;
+ collectPossibleFileImports(path, usedImportsSet, possibleImports);
return possibleImports;
}
-void TextToModelMerger::setupPossibleImports(const QmlJS::Snapshot &snapshot, const QmlJS::ViewerContext &viewContext)
+QmlDesigner::Imports createQt5Modules()
+{
+ return {QmlDesigner::Import::createLibraryImport("QtQuick", "5.15"),
+ QmlDesigner::Import::createLibraryImport("QtQuick3D", "5.15"),
+ QmlDesigner::Import::createLibraryImport("QtQuick.Controls", "5.15"),
+ QmlDesigner::Import::createLibraryImport("QtQuick.Window", "5.15"),
+ QmlDesigner::Import::createLibraryImport("QtQuick.Layouts", "5.15"),
+ QmlDesigner::Import::createLibraryImport("QtQuick.Timeline", "5.15"),
+ QmlDesigner::Import::createLibraryImport("QtCharts", "5.15"),
+ QmlDesigner::Import::createLibraryImport("QtDataVisulaization", "5.15"),
+ QmlDesigner::Import::createLibraryImport("QtQuick.Studio.Controls", "1.0"),
+ QmlDesigner::Import::createLibraryImport("QtQuick.Studio.Effects", "1.0"),
+ QmlDesigner::Import::createLibraryImport("FlowView", "1.0"),
+ QmlDesigner::Import::createLibraryImport("QtQuick.Studio.LogicHelper", "1.0"),
+ QmlDesigner::Import::createLibraryImport("QtQuick.Studio.MultiText", "1.0"),
+ QmlDesigner::Import::createLibraryImport("Qt.SafeRenderer", "2.0")};
+}
+
+} // namespace
+
+void TextToModelMerger::setupPossibleImports()
{
if (!m_rewriterView->possibleImportsEnabled())
return;
@@ -919,27 +909,42 @@ void TextToModelMerger::setupPossibleImports(const QmlJS::Snapshot &snapshot, co
static QUrl lastProjectUrl;
auto &externalDependencies = m_rewriterView->externalDependencies();
auto projectUrl = externalDependencies.projectUrl();
-
- if (m_possibleImportKeys.isEmpty() || projectUrl != lastProjectUrl)
- m_possibleImportKeys = snapshot.importDependencies()->libraryImports(viewContext);
+ auto allUsedImports = m_scopeChain->context()->imports(m_document.data())->all();
+
+ if (m_possibleModules.isEmpty() || projectUrl != lastProjectUrl) {
+
+ auto &externalDependencies = m_rewriterView->externalDependencies();
+ if (externalDependencies.isQt6Project()) {
+ const auto skipModuleNames = m_rewriterView->model()
+ ->metaInfo()
+ .itemLibraryInfo()
+ ->blacklistImports();
+ ModuleScanner moduleScanner{[&](QStringView moduleName) {
+ return skipModule(moduleName, skipModuleNames);
+ },
+ VersionScanning::No,
+ m_rewriterView->externalDependencies()};
+ moduleScanner.scan(m_rewriterView->externalDependencies().modulePaths());
+ m_possibleModules = moduleScanner.modules();
+ } else {
+ ModuleScanner moduleScanner{[&](QStringView) { return false; },
+ VersionScanning::Yes,
+ m_rewriterView->externalDependencies()};
+ m_possibleModules = createQt5Modules();
+ moduleScanner.scan(externalDependencies.projectModulePaths());
+ m_possibleModules.append(moduleScanner.modules());
+ }
+ }
lastProjectUrl = projectUrl;
- QHash<QString, ImportKey> filteredPossibleImportKeys = filterPossibleImportKeys(
- m_possibleImportKeys, m_rewriterView->model());
-
- const QmlJS::Imports *imports = m_scopeChain->context()->imports(m_document.data());
- if (imports)
- removeUsedImports(filteredPossibleImportKeys, imports->all());
-
- QList<QmlDesigner::Import> possibleImports = generatePossibleLibraryImports(filteredPossibleImportKeys);
+ auto modules = m_possibleModules;
if (document()->fileName() != "<internal>")
- possibleImports.append(
- generatePossibleFileImports(document()->path().toString(), imports->all()));
+ modules.append(generatePossibleFileImports(document()->path().toString(), allUsedImports));
if (m_rewriterView->isAttached())
- m_rewriterView->model()->setPossibleImports(possibleImports);
+ m_rewriterView->model()->setPossibleImports(modules);
}
void TextToModelMerger::setupUsedImports()
@@ -951,7 +956,7 @@ void TextToModelMerger::setupUsedImports()
const QList<QmlJS::Import> allImports = imports->all();
QSet<QString> usedImportsSet;
- QList<Import> usedImports;
+ Imports usedImports;
// populate usedImportsSet from current model nodes
const QList<ModelNode> allModelNodes = m_rewriterView->allModelNodes();
@@ -964,9 +969,6 @@ void TextToModelMerger::setupUsedImports()
for (const QmlJS::Import &import : allImports) {
QString version = import.info.version().toString();
- if (!import.info.version().isValid())
- version = getHighestPossibleImport(import.info.name());
-
if (!import.info.name().isEmpty() && usedImportsSet.contains(import.info.name())) {
if (import.info.type() == ImportType::Library)
usedImports.append(
@@ -1077,7 +1079,7 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH
collectLinkErrors(&errors, ctxt);
}
- setupPossibleImports(snapshot, m_vContext);
+ setupPossibleImports();
qCInfo(rewriterBenchmark) << "possible imports:" << time.elapsed();
@@ -1115,12 +1117,6 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH
setActive(false);
- // Clear possible imports cache if code model hasn't settled yet
- const int importKeysSize = m_possibleImportKeys.size();
- if (m_previousPossibleImportsSize != importKeysSize)
- m_possibleImportKeys.clear();
- m_previousPossibleImportsSize = importKeysSize;
-
return true;
} catch (Exception &e) {
DocumentMessage error(&e);
@@ -2174,13 +2170,12 @@ void TextToModelMerger::collectImportErrors(QList<DocumentMessage> *errors)
bool hasQtQuick = false;
for (const QmlDesigner::Import &import : m_rewriterView->model()->imports()) {
if (import.isLibraryImport() && import.url() == QStringLiteral("QtQuick")) {
-
- if (supportedQtQuickVersion(import.version())) {
+ if (supportedQtQuickVersion(import)) {
hasQtQuick = true;
auto &externalDependencies = m_rewriterView->externalDependencies();
if (externalDependencies.hasStartupTarget()) {
- const bool qt6import = import.version().startsWith("6");
+ const bool qt6import = !import.hasVersion() || import.majorVersion() == 6;
if (!externalDependencies.isQt6Import() && (m_hasVersionlessImport || qt6import)) {
const QmlJS::DiagnosticMessage diagnosticMessage(
@@ -2387,8 +2382,8 @@ QList<QmlTypeData> TextToModelMerger::getQMLSingletons() const
void TextToModelMerger::clearPossibleImportKeys()
{
- m_possibleImportKeys.clear();
- m_previousPossibleImportsSize = -1;
+ m_possibleModules.clear();
+ m_previousPossibleModulesSize = -1;
}
QString TextToModelMerger::textAt(const Document::Ptr &doc,
@@ -2403,19 +2398,3 @@ QString TextToModelMerger::textAt(const Document::Ptr &doc,
{
return doc->source().mid(from.offset, to.end() - from.begin());
}
-
-QString TextToModelMerger::getHighestPossibleImport(const QString &importName) const
-{
- QString version = "2.15";
- int maj = -1;
- const auto imports = m_possibleImportKeys.values();
- for (const ImportKey &import : imports) {
- if (importName == import.libraryQualifiedPath()) {
- if (import.majorVersion > maj) {
- version = QString("%1.%2").arg(import.majorVersion).arg(import.minorVersion);
- maj = import.majorVersion;
- }
- }
- }
- return version;
-}
diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h
index 5ed2e24c7a4..50b3a423678 100644
--- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h
+++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h
@@ -37,7 +37,7 @@ public:
bool isActive() const;
void setupImports(const QmlJS::Document::Ptr &doc, DifferenceHandler &differenceHandler);
- void setupPossibleImports(const QmlJS::Snapshot &snapshot, const QmlJS::ViewerContext &viewContext);
+ void setupPossibleImports();
void setupUsedImports();
bool load(const QString &data, DifferenceHandler &differenceHandler);
@@ -137,8 +137,6 @@ private:
const QmlJS::SourceLocation &from,
const QmlJS::SourceLocation &to);
- QString getHighestPossibleImport(const QString &importName) const;
-
private:
RewriterView *m_rewriterView;
bool m_isActive;
@@ -150,8 +148,8 @@ private:
QSet<ModelNode> m_clearImplicitComponentList;
QmlJS::ViewerContext m_vContext;
QSet<QPair<QString, QString> > m_qrcMapping;
- QSet<QmlJS::ImportKey> m_possibleImportKeys;
- int m_previousPossibleImportsSize = -1;
+ Imports m_possibleModules;
+ int m_previousPossibleModulesSize = -1;
bool m_hasVersionlessImport = false;
};
diff --git a/src/plugins/qmldesigner/designercore/model/variantproperty.cpp b/src/plugins/qmldesigner/designercore/model/variantproperty.cpp
index 48d0fa86300..c879ec7a347 100644
--- a/src/plugins/qmldesigner/designercore/model/variantproperty.cpp
+++ b/src/plugins/qmldesigner/designercore/model/variantproperty.cpp
@@ -47,7 +47,7 @@ void VariantProperty::setValue(const QVariant &value)
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isVariantProperty())
- privateModel()->removeProperty(internalNode()->property(name()));
+ privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->setVariantProperty(internalNode(), name(), value);
}
@@ -96,7 +96,7 @@ void VariantProperty::setDynamicTypeNameAndValue(const TypeName &type, const QVa
}
if (internalNode()->hasProperty(name()) && !internalNode()->property(name())->isVariantProperty())
- privateModel()->removeProperty(internalNode()->property(name()));
+ privateModel()->removePropertyAndRelatedResources(internalNode()->property(name()));
privateModel()->setDynamicVariantProperty(internalNode(), name(), type, value);
}
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h b/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h
index 3cd7f3a0167..0db44e3df76 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/commontypecache.h
@@ -49,6 +49,7 @@ inline constexpr char GroupItem[] = "GroupItem";
inline constexpr char Image[] = "Image";
inline constexpr char InstanceListEntry[] = "InstanceListEntry";
inline constexpr char InstanceList[] = "InstanceList";
+inline constexpr char Light[] = "Light";
inline constexpr char IntType[] = "int";
inline constexpr char Item[] = "Item";
inline constexpr char KeyframeGroup[] = "KeyframeGroup";
@@ -83,6 +84,7 @@ inline constexpr char QtQuick3D[] = "QtQuick3D";
inline constexpr char QtQuick3D_Particles3D[] = "QtQuick3D.Particles3D";
inline constexpr char QtQuick3D_Particles3D_cppnative[] = "QtQuick3D.Particles3D-cppnative";
inline constexpr char QtQuick[] = "QtQuick";
+inline constexpr char QtQuick_cppnative[] = "QtQuick-cppnative";
inline constexpr char QtQuick_Controls[] = "QtQuick.Controls";
inline constexpr char QtQuick_Dialogs[] = "QtQuick.Dialogs";
inline constexpr char QtQuick_Extras[] = "QtQuick.Extras";
@@ -90,9 +92,7 @@ inline constexpr char QtQuick_Layouts[] = "QtQuick.Layouts";
inline constexpr char QtQuick_Studio_Components[] = "QtQuick.Studio.Components";
inline constexpr char QtQuick_Timeline[] = "QtQuick.Timeline";
inline constexpr char QtQuick_Window[] = "QtQuick.Window";
-inline constexpr char QtQuick_cppnative[] = "QtQuick-cppnative";
inline constexpr char Qt_SafeRenderer[] = "Qt.SafeRenderer";
-inline constexpr char QuickStateOperation[] = "QuickStateOperation";
inline constexpr char Rectangle[] = "Rectangle";
inline constexpr char Repeater[] = "Repeater";
inline constexpr char SafePicture[] = "SafePicture";
@@ -158,7 +158,6 @@ class CommonTypeCache
CacheType<QML, url>,
CacheType<QML, var>,
CacheType<QML_cppnative, FloatType>,
- CacheType<QML_cppnative, QQuickStateOperation>,
CacheType<QtMultimedia, SoundEffect>,
CacheType<QtQuick, BorderImage>,
CacheType<QtQuick, Connections>,
@@ -194,12 +193,14 @@ class CommonTypeCache
CacheType<QtQuick3D, Effect>,
CacheType<QtQuick3D, InstanceList>,
CacheType<QtQuick3D, InstanceListEntry>,
+ CacheType<QtQuick3D, Light>,
CacheType<QtQuick3D, Material>,
CacheType<QtQuick3D, Model>,
CacheType<QtQuick3D, Node>,
CacheType<QtQuick3D, Pass>,
CacheType<QtQuick3D, PrincipledMaterial>,
CacheType<QtQuick3D, SceneEnvironment>,
+ CacheType<QtQuick3D, SpecularGlossyMaterial>,
CacheType<QtQuick3D, Shader>,
CacheType<QtQuick3D, Texture>,
CacheType<QtQuick3D, TextureInput>,
@@ -226,7 +227,7 @@ class CommonTypeCache
CacheType<QtQuick_Timeline, KeyframeGroup>,
CacheType<QtQuick_Timeline, Timeline>,
CacheType<QtQuick_Timeline, TimelineAnimation>,
- CacheType<QtQuick_cppnative, QuickStateOperation>,
+ CacheType<QtQuick_cppnative, QQuickStateOperation>,
CacheType<Qt_SafeRenderer, SafePicture>,
CacheType<Qt_SafeRenderer, SafeRendererPicture>,
CacheType<QtQuick_Window, Window>>;
@@ -242,15 +243,13 @@ public:
}
TypeId refreshTypedId(BaseCacheType &type,
- Utils::SmallStringView moduleName,
- Utils::SmallStringView typeName) const
+ ::Utils::SmallStringView moduleName,
+ ::Utils::SmallStringView typeName) const
{
if (!type.moduleId)
type.moduleId = m_projectStorage.moduleId(moduleName);
- type.typeId = m_projectStorage.typeId(type.moduleId,
- typeName,
- QmlDesigner::Storage::Synchronization::Version{});
+ type.typeId = m_projectStorage.typeId(type.moduleId, typeName, QmlDesigner::Storage::Version{});
return type.typeId;
}
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/modulescanner.cpp b/src/plugins/qmldesigner/designercore/projectstorage/modulescanner.cpp
new file mode 100644
index 00000000000..c458d8376b9
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/projectstorage/modulescanner.cpp
@@ -0,0 +1,110 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "modulescanner.h"
+
+#include <private/qqmldirparser_p.h>
+
+#include <QDirIterator>
+#include <QFile>
+#include <QHash>
+
+namespace QmlDesigner {
+
+namespace {
+
+std::optional<QString> contentAsQString(const QString &filePath)
+{
+ QFile file{filePath};
+ if (file.open(QIODevice::ReadOnly))
+ return {QString::fromUtf8(file.readAll())};
+
+ return {};
+}
+
+QString createVersion(const QMultiHash<QString, QQmlDirParser::Component> &components)
+{
+ auto found = std::max_element(components.begin(), components.end(), [](auto &&first, auto &&second) {
+ return first.version < second.version;
+ });
+
+ if (found != components.end() && found->version.isValid())
+ return QString{"%1.%2"}.arg(found->version.majorVersion()).arg(found->version.minorVersion());
+
+ return {};
+}
+
+constexpr auto coreModules = std::make_tuple(QStringView{u"QtQuick"},
+ QStringView{u"QtQuick.Controls"},
+ QStringView{u"QtQuick3D"},
+ QStringView{u"QtQuick3D.Helpers"},
+ QStringView{u"QtQuick3D.Particles3D"});
+
+bool isCoreVersion(QStringView moduleName)
+{
+ return std::apply([=](auto... coreModuleName) { return ((moduleName == coreModuleName) || ...); },
+ coreModules);
+}
+
+QString createCoreVersion(QStringView moduleName, ExternalDependenciesInterface &externalDependencies)
+{
+ if (isCoreVersion(moduleName))
+ return externalDependencies.qtQuickVersion();
+
+ return {};
+}
+
+} // namespace
+
+void ModuleScanner::scan(const QStringList &modulePaths)
+{
+ for (const QString &modulePath : modulePaths)
+ scan(modulePath.toStdString());
+}
+
+void ModuleScanner::scan([[maybe_unused]] std::string_view modulePath)
+{
+ if (modulePath.empty())
+ return;
+
+ QDirIterator dirIterator{QString::fromUtf8(modulePath),
+ QDir::Dirs | QDir::NoDotAndDotDot,
+ QDirIterator::Subdirectories};
+
+ while (dirIterator.hasNext()) {
+ auto directoryPath = dirIterator.next();
+ QString qmldirPath = directoryPath + "/qmldir";
+ if (QFileInfo::exists(qmldirPath)) {
+ QQmlDirParser parser;
+
+ auto content = contentAsQString(qmldirPath);
+ if (!content)
+ continue;
+
+ bool hasError = parser.parse(*content);
+ if (hasError)
+ continue;
+
+ auto moduleName = parser.typeNamespace();
+
+ if (moduleName.isEmpty() || m_skip(moduleName))
+ continue;
+
+ QString version = m_versionScanning == VersionScanning::Yes
+ ? createVersion(parser.components())
+ : QString{};
+
+ QString coreModuleVersion = createCoreVersion(moduleName, m_externalDependencies);
+
+ if (!coreModuleVersion.isEmpty())
+ version = coreModuleVersion;
+
+ m_modules.push_back(Import::createLibraryImport(moduleName, version));
+ }
+ }
+
+ std::sort(m_modules.begin(), m_modules.end());
+ m_modules.erase(std::unique(m_modules.begin(), m_modules.end()), m_modules.end());
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/modulescanner.h b/src/plugins/qmldesigner/designercore/projectstorage/modulescanner.h
new file mode 100644
index 00000000000..2083d1d48c0
--- /dev/null
+++ b/src/plugins/qmldesigner/designercore/projectstorage/modulescanner.h
@@ -0,0 +1,46 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <qmldesignercorelib_global.h>
+
+#include <externaldependenciesinterface.h>
+#include <import.h>
+
+#include <optional>
+
+namespace QmlDesigner {
+
+enum class VersionScanning { No, Yes };
+
+class QMLDESIGNERCORE_EXPORT ModuleScanner
+{
+public:
+ using SkipFunction = std::function<bool(QStringView)>;
+
+ ModuleScanner([[maybe_unused]] SkipFunction skip,
+ [[maybe_unused]] VersionScanning versionScanning,
+ [[maybe_unused]] ExternalDependenciesInterface &externalDependencies)
+ : m_skip{std::move(skip)}
+ , m_versionScanning{versionScanning}
+ , m_externalDependencies{externalDependencies}
+ {
+ m_modules.reserve(128);
+ }
+
+ void scan(const QStringList &modulePaths);
+
+ const Imports &modules() const { return m_modules; }
+
+private:
+ void scan(std::string_view modulePaths);
+
+private:
+ Imports m_modules;
+ SkipFunction m_skip;
+ VersionScanning m_versionScanning;
+ ExternalDependenciesInterface &m_externalDependencies;
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h
index ad3e8931af8..974ebdf6aab 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorage.h
@@ -45,63 +45,61 @@ public:
void synchronize(Storage::Synchronization::SynchronizationPackage package) override
{
- Sqlite::ImmediateTransaction transaction{database};
-
- AliasPropertyDeclarations insertedAliasPropertyDeclarations;
- AliasPropertyDeclarations updatedAliasPropertyDeclarations;
-
- AliasPropertyDeclarations relinkableAliasPropertyDeclarations;
- PropertyDeclarations relinkablePropertyDeclarations;
- Prototypes relinkablePrototypes;
- Prototypes relinkableExtensions;
- TypeIds deletedTypeIds;
-
- TypeIds updatedTypeIds;
- updatedTypeIds.reserve(package.types.size());
-
- TypeIds typeIdsToBeDeleted;
-
- std::sort(package.updatedSourceIds.begin(), package.updatedSourceIds.end());
-
- synchronizeFileStatuses(package.fileStatuses, package.updatedFileStatusSourceIds);
- synchronizeImports(package.imports,
- package.updatedSourceIds,
- package.moduleDependencies,
- package.updatedModuleDependencySourceIds,
- package.moduleExportedImports,
- package.updatedModuleIds);
- synchronizeTypes(package.types,
- updatedTypeIds,
- insertedAliasPropertyDeclarations,
- updatedAliasPropertyDeclarations,
- relinkableAliasPropertyDeclarations,
- relinkablePropertyDeclarations,
- relinkablePrototypes,
- relinkableExtensions,
- package.updatedSourceIds);
-
- deleteNotUpdatedTypes(updatedTypeIds,
- package.updatedSourceIds,
- typeIdsToBeDeleted,
- relinkableAliasPropertyDeclarations,
- relinkablePropertyDeclarations,
- relinkablePrototypes,
- relinkableExtensions,
- deletedTypeIds);
-
- relink(relinkableAliasPropertyDeclarations,
- relinkablePropertyDeclarations,
- relinkablePrototypes,
- relinkableExtensions,
- deletedTypeIds);
-
- linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations);
-
- synchronizeProjectDatas(package.projectDatas, package.updatedProjectSourceIds);
-
- commonTypeCache.resetTypeIds();
-
- transaction.commit();
+ Sqlite::withImmediateTransaction(database, [&] {
+ AliasPropertyDeclarations insertedAliasPropertyDeclarations;
+ AliasPropertyDeclarations updatedAliasPropertyDeclarations;
+
+ AliasPropertyDeclarations relinkableAliasPropertyDeclarations;
+ PropertyDeclarations relinkablePropertyDeclarations;
+ Prototypes relinkablePrototypes;
+ Prototypes relinkableExtensions;
+ TypeIds deletedTypeIds;
+
+ TypeIds updatedTypeIds;
+ updatedTypeIds.reserve(package.types.size());
+
+ TypeIds typeIdsToBeDeleted;
+
+ std::sort(package.updatedSourceIds.begin(), package.updatedSourceIds.end());
+
+ synchronizeFileStatuses(package.fileStatuses, package.updatedFileStatusSourceIds);
+ synchronizeImports(package.imports,
+ package.updatedSourceIds,
+ package.moduleDependencies,
+ package.updatedModuleDependencySourceIds,
+ package.moduleExportedImports,
+ package.updatedModuleIds);
+ synchronizeTypes(package.types,
+ updatedTypeIds,
+ insertedAliasPropertyDeclarations,
+ updatedAliasPropertyDeclarations,
+ relinkableAliasPropertyDeclarations,
+ relinkablePropertyDeclarations,
+ relinkablePrototypes,
+ relinkableExtensions,
+ package.updatedSourceIds);
+
+ deleteNotUpdatedTypes(updatedTypeIds,
+ package.updatedSourceIds,
+ typeIdsToBeDeleted,
+ relinkableAliasPropertyDeclarations,
+ relinkablePropertyDeclarations,
+ relinkablePrototypes,
+ relinkableExtensions,
+ deletedTypeIds);
+
+ relink(relinkableAliasPropertyDeclarations,
+ relinkablePropertyDeclarations,
+ relinkablePrototypes,
+ relinkableExtensions,
+ deletedTypeIds);
+
+ linkAliases(insertedAliasPropertyDeclarations, updatedAliasPropertyDeclarations);
+
+ synchronizeProjectDatas(package.projectDatas, package.updatedProjectSourceIds);
+
+ commonTypeCache_.resetTypeIds();
+ });
}
ModuleId moduleId(Utils::SmallStringView moduleName) const override
@@ -119,7 +117,7 @@ public:
TypeId typeId(ModuleId moduleId,
Utils::SmallStringView exportedTypeName,
- Storage::Synchronization::Version version) const
+ Storage::Version version) const override
{
if (version.minor)
return selectTypeIdByModuleIdAndExportedNameAndVersionStatement
@@ -136,19 +134,20 @@ public:
.template valueWithTransaction<TypeId>(moduleId, exportedTypeName);
}
- PropertyDeclarationIds propertyDeclarationIds(TypeId typeId) const
+ PropertyDeclarationIds propertyDeclarationIds(TypeId typeId) const override
{
return selectPropertyDeclarationIdsForTypeStatement
.template valuesWithTransaction<PropertyDeclarationId>(32, typeId);
}
- PropertyDeclarationIds localPropertyDeclarationIds(TypeId typeId) const
+ PropertyDeclarationIds localPropertyDeclarationIds(TypeId typeId) const override
{
return selectLocalPropertyDeclarationIdsForTypeStatement
.template valuesWithTransaction<PropertyDeclarationId>(16, typeId);
}
- PropertyDeclarationId propertyDeclarationId(TypeId typeId, Utils::SmallStringView propertyName) const
+ PropertyDeclarationId propertyDeclarationId(TypeId typeId,
+ Utils::SmallStringView propertyName) const override
{
return selectPropertyDeclarationIdForTypeAndPropertyNameStatement
.template valueWithTransaction<PropertyDeclarationId>(typeId, propertyName);
@@ -162,69 +161,74 @@ public:
}
std::optional<Storage::Info::PropertyDeclaration> propertyDeclaration(
- PropertyDeclarationId propertyDeclarationId) const
+ PropertyDeclarationId propertyDeclarationId) const override
{
return selectPropertyDeclarationForPropertyDeclarationIdStatement
.template optionalValueWithTransaction<Storage::Info::PropertyDeclaration>(
propertyDeclarationId);
}
- std::optional<Storage::Info::Type> type(TypeId typeId) const
+ std::optional<Storage::Info::Type> type(TypeId typeId) const override
{
return selectInfoTypeByTypeIdStatement.template optionalValueWithTransaction<Storage::Info::Type>(
typeId);
}
- std::vector<Utils::SmallString> signalDeclarationNames(TypeId typeId) const
+ std::vector<Utils::SmallString> signalDeclarationNames(TypeId typeId) const override
{
return selectSignalDeclarationNamesForTypeStatement
.template valuesWithTransaction<Utils::SmallString>(32, typeId);
}
- std::vector<Utils::SmallString> functionDeclarationNames(TypeId typeId) const
+ std::vector<Utils::SmallString> functionDeclarationNames(TypeId typeId) const override
{
return selectFuncionDeclarationNamesForTypeStatement
.template valuesWithTransaction<Utils::SmallString>(32, typeId);
}
- std::optional<Utils::SmallString> propertyName(PropertyDeclarationId propertyDeclarationId) const
+ std::optional<Utils::SmallString> propertyName(PropertyDeclarationId propertyDeclarationId) const override
{
return selectPropertyNameStatement.template optionalValueWithTransaction<Utils::SmallString>(
propertyDeclarationId);
}
+ const Storage::Info::CommonTypeCache<ProjectStorageInterface> &commonTypeCache() const override
+ {
+ return commonTypeCache_;
+ }
+
template<const char *moduleName, const char *typeName>
TypeId commonTypeId() const
{
- return commonTypeCache.template typeId<moduleName, typeName>();
+ return commonTypeCache_.template typeId<moduleName, typeName>();
}
template<typename BuiltinType>
TypeId builtinTypeId() const
{
- return commonTypeCache.template builtinTypeId<BuiltinType>();
+ return commonTypeCache_.template builtinTypeId<BuiltinType>();
}
template<const char *builtinType>
TypeId builtinTypeId() const
{
- return commonTypeCache.template builtinTypeId<builtinType>();
+ return commonTypeCache_.template builtinTypeId<builtinType>();
}
- TypeIds prototypeIds(TypeId type) const
+ TypeIds prototypeIds(TypeId type) const override
{
return selectPrototypeIdsForTypeIdInOrderStatement.template valuesWithTransaction<TypeId>(16,
type);
}
- TypeIds prototypeAndSelfIds(TypeId type) const
+ TypeIds prototypeAndSelfIds(TypeId type) const override
{
return selectPrototypeAndSelfIdsForTypeIdInOrderStatement
.template valuesWithTransaction<TypeId>(16, type);
}
template<typename... TypeIds>
- bool isBasedOn(TypeId typeId, TypeIds... baseTypeIds) const
+ bool isBasedOn_(TypeId typeId, TypeIds... baseTypeIds) const
{
static_assert(((std::is_same_v<TypeId, TypeIds>) &&...), "Parameter must be a TypeId!");
@@ -238,6 +242,48 @@ public:
return false;
}
+ bool isBasedOn(TypeId typeId) const { return isBasedOn_(typeId); }
+
+ bool isBasedOn(TypeId typeId, TypeId id1) const override { return isBasedOn_(typeId, id1); }
+
+ bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2) const override
+ {
+ return isBasedOn_(typeId, id1, id2);
+ }
+
+ bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3) const override
+ {
+ return isBasedOn_(typeId, id1, id2, id3);
+ }
+
+ bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4) const override
+ {
+ return isBasedOn_(typeId, id1, id2, id3, id4);
+ }
+
+ bool isBasedOn(TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5) const override
+ {
+ return isBasedOn_(typeId, id1, id2, id3, id4, id5);
+ }
+
+ bool isBasedOn(
+ TypeId typeId, TypeId id1, TypeId id2, TypeId id3, TypeId id4, TypeId id5, TypeId id6) const override
+ {
+ return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6);
+ }
+
+ bool isBasedOn(TypeId typeId,
+ TypeId id1,
+ TypeId id2,
+ TypeId id3,
+ TypeId id4,
+ TypeId id5,
+ TypeId id6,
+ TypeId id7) const override
+ {
+ return isBasedOn_(typeId, id1, id2, id3, id4, id5, id6, id7);
+ }
+
TypeId fetchTypeIdByExportedName(Utils::SmallStringView name) const
{
return selectTypeIdByExportedNameStatement.template valueWithTransaction<TypeId>(name);
@@ -257,38 +303,35 @@ public:
Storage::Synchronization::Type fetchTypeByTypeId(TypeId typeId)
{
- Sqlite::DeferredTransaction transaction{database};
-
- auto type = selectTypeByTypeIdStatement.template value<Storage::Synchronization::Type>(typeId);
+ return Sqlite::withDeferredTransaction(database, [&] {
+ auto type = selectTypeByTypeIdStatement.template value<Storage::Synchronization::Type>(
+ typeId);
- type.exportedTypes = fetchExportedTypes(typeId);
- type.propertyDeclarations = fetchPropertyDeclarations(type.typeId);
- type.functionDeclarations = fetchFunctionDeclarations(type.typeId);
- type.signalDeclarations = fetchSignalDeclarations(type.typeId);
- type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId);
-
- transaction.commit();
+ type.exportedTypes = fetchExportedTypes(typeId);
+ type.propertyDeclarations = fetchPropertyDeclarations(type.typeId);
+ type.functionDeclarations = fetchFunctionDeclarations(type.typeId);
+ type.signalDeclarations = fetchSignalDeclarations(type.typeId);
+ type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId);
- return type;
+ return type;
+ });
}
Storage::Synchronization::Types fetchTypes()
{
- Sqlite::DeferredTransaction transaction{database};
+ return Sqlite::withDeferredTransaction(database, [&] {
+ auto types = selectTypesStatement.template values<Storage::Synchronization::Type>(64);
- auto types = selectTypesStatement.template values<Storage::Synchronization::Type>(64);
-
- for (Storage::Synchronization::Type &type : types) {
- type.exportedTypes = fetchExportedTypes(type.typeId);
- type.propertyDeclarations = fetchPropertyDeclarations(type.typeId);
- type.functionDeclarations = fetchFunctionDeclarations(type.typeId);
- type.signalDeclarations = fetchSignalDeclarations(type.typeId);
- type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId);
- }
-
- transaction.commit();
+ for (Storage::Synchronization::Type &type : types) {
+ type.exportedTypes = fetchExportedTypes(type.typeId);
+ type.propertyDeclarations = fetchPropertyDeclarations(type.typeId);
+ type.functionDeclarations = fetchFunctionDeclarations(type.typeId);
+ type.signalDeclarations = fetchSignalDeclarations(type.typeId);
+ type.enumerationDeclarations = fetchEnumerationDeclarations(type.typeId);
+ }
- return types;
+ return types;
+ });
}
bool fetchIsProtype(TypeId type, TypeId prototype)
@@ -311,13 +354,9 @@ public:
SourceContextId fetchSourceContextId(Utils::SmallStringView sourceContextPath)
{
try {
- Sqlite::DeferredTransaction transaction{database};
-
- auto sourceContextId = fetchSourceContextIdUnguarded(sourceContextPath);
-
- transaction.commit();
-
- return sourceContextId;
+ return Sqlite::withDeferredTransaction(database, [&] {
+ return fetchSourceContextIdUnguarded(sourceContextPath);
+ });
} catch (const Sqlite::ConstraintPreventsModification &) {
return fetchSourceContextId(sourceContextPath);
}
@@ -325,18 +364,16 @@ public:
Utils::PathString fetchSourceContextPath(SourceContextId sourceContextId) const
{
- Sqlite::DeferredTransaction transaction{database};
-
- auto optionalSourceContextPath = selectSourceContextPathFromSourceContextsBySourceContextIdStatement
- .template optionalValue<Utils::PathString>(
- sourceContextId);
+ return Sqlite::withDeferredTransaction(database, [&] {
+ auto optionalSourceContextPath = selectSourceContextPathFromSourceContextsBySourceContextIdStatement
+ .template optionalValue<Utils::PathString>(
+ sourceContextId);
- if (!optionalSourceContextPath)
- throw SourceContextIdDoesNotExists();
+ if (!optionalSourceContextPath)
+ throw SourceContextIdDoesNotExists();
- transaction.commit();
-
- return std::move(*optionalSourceContextPath);
+ return std::move(*optionalSourceContextPath);
+ });
}
auto fetchAllSourceContexts() const
@@ -347,13 +384,9 @@ public:
SourceId fetchSourceId(SourceContextId sourceContextId, Utils::SmallStringView sourceName)
{
- Sqlite::DeferredTransaction transaction{database};
-
- auto sourceId = fetchSourceIdUnguarded(sourceContextId, sourceName);
-
- transaction.commit();
-
- return sourceId;
+ return Sqlite::withDeferredTransaction(database, [&] {
+ return fetchSourceIdUnguarded(sourceContextId, sourceName);
+ });
}
auto fetchSourceNameAndSourceContextId(SourceId sourceId) const
@@ -369,12 +402,10 @@ public:
void clearSources()
{
- Sqlite::ImmediateTransaction transaction{database};
-
- deleteAllSourceContextsStatement.execute();
- deleteAllSourcesStatement.execute();
-
- transaction.commit();
+ Sqlite::withImmediateTransaction(database, [&] {
+ deleteAllSourceContextsStatement.execute();
+ deleteAllSourcesStatement.execute();
+ });
}
SourceContextId fetchSourceContextId(SourceId sourceId) const
@@ -414,16 +445,22 @@ public:
sourceId);
}
+ std::optional<Storage::Synchronization::ProjectData> fetchProjectData(SourceId sourceId) const override
+ {
+ return selectProjectDataForSourceIdStatement
+ .template optionalValueWithTransaction<Storage::Synchronization::ProjectData>(sourceId);
+ }
+
Storage::Synchronization::ProjectDatas fetchProjectDatas(SourceId projectSourceId) const override
{
- return selectProjectDatasForModuleIdStatement
+ return selectProjectDatasForSourceIdStatement
.template valuesWithTransaction<Storage::Synchronization::ProjectData>(64,
projectSourceId);
}
Storage::Synchronization::ProjectDatas fetchProjectDatas(const SourceIds &projectSourceIds) const
{
- return selectProjectDatasForModuleIdsStatement.template valuesWithTransaction<
+ return selectProjectDatasForSourceIdsStatement.template valuesWithTransaction<
Storage::Synchronization::ProjectData>(64, toIntegers(projectSourceIds));
}
@@ -470,24 +507,15 @@ private:
ModuleId fetchModuleId(Utils::SmallStringView moduleName)
{
- Sqlite::DeferredTransaction transaction{database};
-
- ModuleId moduleId = fetchModuleIdUnguarded(moduleName);
-
- transaction.commit();
-
- return moduleId;
+ return Sqlite::withDeferredTransaction(database,
+ [&] { return fetchModuleIdUnguarded(moduleName); });
}
auto fetchModuleName(ModuleId id)
{
- Sqlite::DeferredTransaction transaction{database};
-
- auto moduleName = fetchModuleNameUnguarded(id);
-
- transaction.commit();
-
- return moduleName;
+ return Sqlite::withDeferredTransaction(database, [&] {
+ return fetchModuleNameUnguarded(id);
+ });
}
auto fetchAllModules() const
@@ -712,7 +740,7 @@ private:
< std::tie(second.projectSourceId, second.sourceId);
});
- auto range = selectProjectDatasForModuleIdsStatement
+ auto range = selectProjectDatasForSourceIdsStatement
.template range<Storage::Synchronization::ProjectData>(
toIntegers(updatedProjectSourceIds));
@@ -1527,7 +1555,7 @@ private:
ModuleExportedImportId moduleExportedImportId) {
Storage::Synchronization::Import additionImport{
exportedModuleId,
- Storage::Synchronization::Version{majorVersion, minorVersion},
+ Storage::Version{majorVersion, minorVersion},
import.sourceId};
auto exportedImportKind = importKind == Storage::Synchronization::ImportKind::Import
@@ -2581,6 +2609,7 @@ private:
table.addColumn("fileType", Sqlite::StrictColumnType::Integer);
table.addPrimaryKeyContraint({projectSourceIdColumn, sourceIdColumn});
+ table.addUniqueIndex({sourceIdColumn});
table.initialize(database);
}
@@ -2590,7 +2619,7 @@ public:
Database &database;
Initializer initializer;
mutable ModuleCache moduleCache{ModuleStorageAdapter{*this}};
- Storage::Info::CommonTypeCache<ProjectStorage<Database>> commonTypeCache{*this};
+ Storage::Info::CommonTypeCache<ProjectStorageInterface> commonTypeCache_{*this};
ReadWriteStatement<1, 3> upsertTypeStatement{
"INSERT INTO types(sourceId, name, traits) VALUES(?1, ?2, ?3) ON CONFLICT DO "
"UPDATE SET traits=excluded.traits WHERE traits IS NOT "
@@ -3082,7 +3111,7 @@ public:
"DELETE FROM exportedTypeNames WHERE exportedTypeNameId=?", database};
WriteStatement<2> updateExportedTypeNameTypeIdStatement{
"UPDATE exportedTypeNames SET typeId=?2 WHERE exportedTypeNameId=?1", database};
- mutable ReadStatement<4, 1> selectProjectDatasForModuleIdsStatement{
+ mutable ReadStatement<4, 1> selectProjectDatasForSourceIdsStatement{
"SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE "
"projectSourceId IN carray(?1) ORDER BY projectSourceId, sourceId",
database};
@@ -3095,10 +3124,14 @@ public:
WriteStatement<4> updateProjectDataStatement{
"UPDATE projectDatas SET moduleId=?3, fileType=?4 WHERE projectSourceId=?1 AND sourceId=?2",
database};
- mutable ReadStatement<4, 1> selectProjectDatasForModuleIdStatement{
+ mutable ReadStatement<4, 1> selectProjectDatasForSourceIdStatement{
"SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE "
"projectSourceId=?1",
database};
+ mutable ReadStatement<4, 1> selectProjectDataForSourceIdStatement{
+ "SELECT projectSourceId, sourceId, moduleId, fileType FROM projectDatas WHERE "
+ "sourceId=?1 LIMIT 1",
+ database};
mutable ReadStatement<1, 1> selectTypeIdsForSourceIdsStatement{
"SELECT typeId FROM types WHERE sourceId IN carray(?1)", database};
mutable ReadStatement<6, 1> selectModuleExportedImportsForSourceIdStatement{
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp
index d574ef54750..07e925df689 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.cpp
@@ -95,4 +95,9 @@ const char *FileStatusHasInvalidSourceId::what() const noexcept
return "The source id in file status is invalid!";
}
+const char *ProjectStorageError::what() const noexcept
+{
+ return "Project storage error!";
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h
index d78283ca180..e5e50e76092 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageexceptions.h
@@ -9,109 +9,115 @@
namespace QmlDesigner {
-class QMLDESIGNERCORE_EXPORT NoSourcePathForInvalidSourceId : std::exception
+class QMLDESIGNERCORE_EXPORT ProjectStorageError : std::exception
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT NoSourceContextPathForInvalidSourceContextId : std::exception
+class QMLDESIGNERCORE_EXPORT NoSourcePathForInvalidSourceId : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT SourceContextIdDoesNotExists : std::exception
+class QMLDESIGNERCORE_EXPORT NoSourceContextPathForInvalidSourceContextId : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT SourceIdDoesNotExists : std::exception
+class QMLDESIGNERCORE_EXPORT SourceContextIdDoesNotExists : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT TypeHasInvalidSourceId : std::exception
+class QMLDESIGNERCORE_EXPORT SourceIdDoesNotExists : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT ModuleDoesNotExists : std::exception
+class QMLDESIGNERCORE_EXPORT TypeHasInvalidSourceId : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT ModuleAlreadyExists : std::exception
+class QMLDESIGNERCORE_EXPORT ModuleDoesNotExists : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT ExportedTypeCannotBeInserted : std::exception
+class QMLDESIGNERCORE_EXPORT ModuleAlreadyExists : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT TypeNameDoesNotExists : std::exception
+class QMLDESIGNERCORE_EXPORT ExportedTypeCannotBeInserted : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT PropertyNameDoesNotExists : std::exception
+class QMLDESIGNERCORE_EXPORT TypeNameDoesNotExists : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT PrototypeChainCycle : std::exception
+class QMLDESIGNERCORE_EXPORT PropertyNameDoesNotExists : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT AliasChainCycle : std::exception
+class QMLDESIGNERCORE_EXPORT PrototypeChainCycle : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT CannotParseQmlTypesFile : std::exception
+class QMLDESIGNERCORE_EXPORT AliasChainCycle : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT CannotParseQmlDocumentFile : std::exception
+class QMLDESIGNERCORE_EXPORT CannotParseQmlTypesFile : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidProjectSourceId : std::exception
+class QMLDESIGNERCORE_EXPORT CannotParseQmlDocumentFile : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidSourceId : std::exception
+class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidProjectSourceId : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidModuleId : std::exception
+class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidSourceId : ProjectStorageError
{
public:
const char *what() const noexcept override;
};
-class QMLDESIGNERCORE_EXPORT FileStatusHasInvalidSourceId : std::exception
+class QMLDESIGNERCORE_EXPORT ProjectDataHasInvalidModuleId : ProjectStorageError
+{
+public:
+ const char *what() const noexcept override;
+};
+
+class QMLDESIGNERCORE_EXPORT FileStatusHasInvalidSourceId : ProjectStorageError
{
public:
const char *what() const noexcept override;
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h
index 461868ec659..db0cec068bc 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragefwd.h
@@ -5,9 +5,11 @@
namespace Sqlite {
class Database;
-};
+}
namespace QmlDesigner {
+class ProjectStorageInterface;
+
template<typename Database>
class ProjectStorage;
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h
index 71823d3ad86..b61a6ec331a 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinfotypes.h
@@ -59,7 +59,7 @@ constexpr TypeTraits operator&(TypeTraits first, TypeTraits second)
return static_cast<TypeTraits>(static_cast<int>(first) & static_cast<int>(second));
}
-using TypeNameString = Utils::BasicSmallString<63>;
+using TypeNameString = ::Utils::BasicSmallString<63>;
} // namespace QmlDesigner::Storage
@@ -69,7 +69,7 @@ class PropertyDeclaration
{
public:
PropertyDeclaration(TypeId typeId,
- Utils::SmallStringView name,
+ ::Utils::SmallStringView name,
PropertyDeclarationTraits traits,
TypeId propertyTypeId)
: typeId{typeId}
@@ -79,7 +79,7 @@ public:
{}
TypeId typeId;
- Utils::SmallString name;
+ ::Utils::SmallString name;
PropertyDeclarationTraits traits;
TypeId propertyTypeId;
};
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h
index f3e87e2cf4e..bc74172ecd7 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageinterface.h
@@ -3,9 +3,13 @@
#pragma once
+#include "commontypecache.h"
#include "filestatus.h"
+#include "projectstorageids.h"
#include "projectstoragetypes.h"
+#include <utils/smallstringview.h>
+
namespace QmlDesigner {
class ProjectStorageInterface
@@ -13,10 +17,56 @@ class ProjectStorageInterface
public:
virtual void synchronize(Storage::Synchronization::SynchronizationPackage package) = 0;
- virtual ModuleId moduleId(Utils::SmallStringView name) const = 0;
+ virtual ModuleId moduleId(::Utils::SmallStringView name) const = 0;
+ virtual std::optional<Storage::Info::PropertyDeclaration>
+ propertyDeclaration(PropertyDeclarationId propertyDeclarationId) const = 0;
+ virtual TypeId typeId(ModuleId moduleId,
+ ::Utils::SmallStringView exportedTypeName,
+ Storage::Version version) const
+ = 0;
+ virtual PropertyDeclarationIds propertyDeclarationIds(TypeId typeId) const = 0;
+ virtual PropertyDeclarationIds localPropertyDeclarationIds(TypeId typeId) const = 0;
+ virtual PropertyDeclarationId propertyDeclarationId(TypeId typeId,
+ ::Utils::SmallStringView propertyName) const
+ = 0;
+ virtual std::optional<Storage::Info::Type> type(TypeId typeId) const = 0;
+ virtual std::vector<::Utils::SmallString> signalDeclarationNames(TypeId typeId) const = 0;
+ virtual std::vector<::Utils::SmallString> functionDeclarationNames(TypeId typeId) const = 0;
+ virtual std::optional<::Utils::SmallString>
+ propertyName(PropertyDeclarationId propertyDeclarationId) const = 0;
+ virtual TypeIds prototypeAndSelfIds(TypeId type) const = 0;
+ virtual TypeIds prototypeIds(TypeId type) const = 0;
+ virtual bool isBasedOn(TypeId, TypeId) const = 0;
+ virtual bool isBasedOn(TypeId, TypeId, TypeId) const = 0;
+ virtual bool isBasedOn(TypeId, TypeId, TypeId, TypeId) const = 0;
+ virtual bool isBasedOn(TypeId, TypeId, TypeId, TypeId, TypeId) const = 0;
+ virtual bool isBasedOn(TypeId, TypeId, TypeId, TypeId, TypeId, TypeId) const = 0;
+ virtual bool isBasedOn(TypeId, TypeId, TypeId, TypeId, TypeId, TypeId, TypeId) const = 0;
+ virtual bool isBasedOn(TypeId, TypeId, TypeId, TypeId, TypeId, TypeId, TypeId, TypeId) const = 0;
virtual FileStatus fetchFileStatus(SourceId sourceId) const = 0;
virtual Storage::Synchronization::ProjectDatas fetchProjectDatas(SourceId sourceId) const = 0;
+ virtual std::optional<Storage::Synchronization::ProjectData> fetchProjectData(SourceId sourceId) const = 0;
+
+ virtual const Storage::Info::CommonTypeCache<ProjectStorageInterface> &commonTypeCache() const = 0;
+
+ template<const char *moduleName, const char *typeName>
+ TypeId commonTypeId() const
+ {
+ return commonTypeCache().template typeId<moduleName, typeName>();
+ }
+
+ template<typename BuiltinType>
+ TypeId builtinTypeId() const
+ {
+ return commonTypeCache().template builtinTypeId<BuiltinType>();
+ }
+
+ template<const char *builtinType>
+ TypeId builtinTypeId() const
+ {
+ return commonTypeCache().template builtinTypeId<builtinType>();
+ }
protected:
~ProjectStorageInterface() = default;
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcher.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcher.h
index 0d3bc730f81..d79b87807f8 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcher.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcher.h
@@ -71,7 +71,7 @@ public:
}
void updateContextIdPaths(const std::vector<IdPaths> &idPaths,
- const SourceContextIds &sourceContextIds)
+ const SourceContextIds &sourceContextIds) override
{
const auto &[entires, ids] = convertIdPathsToWatcherEntriesAndIds(idPaths);
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcherinterface.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcherinterface.h
index 110cf07cff0..8e67b80b9a7 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcherinterface.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragepathwatcherinterface.h
@@ -19,6 +19,9 @@ public:
ProjectStoragePathWatcherInterface &operator=(const ProjectStoragePathWatcherInterface &) = delete;
virtual void updateIdPaths(const std::vector<IdPaths> &idPaths) = 0;
+ virtual void updateContextIdPaths(const std::vector<IdPaths> &idPaths,
+ const SourceContextIds &sourceContextIds)
+ = 0;
virtual void removeIds(const ProjectPartIds &ids) = 0;
virtual void setNotifier(ProjectStoragePathWatcherNotifierInterface *notifier) = 0;
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h
index 1f20eb93713..83372893785 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstoragetypes.h
@@ -13,11 +13,7 @@
#include <variant>
#include <vector>
-namespace QmlDesigner::Storage::Synchronization {
-
-enum class TypeNameKind { Exported = 1, QualifiedExported = 2 };
-
-enum class FileType : char { QmlTypes, QmlDocument };
+namespace QmlDesigner::Storage {
class VersionNumber
{
@@ -83,6 +79,12 @@ public:
VersionNumber minor;
};
+namespace Synchronization {
+
+enum class TypeNameKind { Exported = 1, QualifiedExported = 2 };
+
+enum class FileType : char { QmlTypes, QmlDocument };
+
enum class IsQualified : int { No, Yes };
inline int operator-(IsQualified first, IsQualified second)
@@ -107,7 +109,7 @@ class Import
public:
explicit Import() = default;
- explicit Import(ModuleId moduleId, Version version, SourceId sourceId)
+ explicit Import(ModuleId moduleId, Storage::Version version, SourceId sourceId)
: version{version}
, moduleId{moduleId}
, sourceId{sourceId}
@@ -132,7 +134,7 @@ public:
}
public:
- Version version;
+ Storage::Version version;
ModuleId moduleId;
SourceId sourceId;
};
@@ -162,7 +164,7 @@ public:
ImportId importId;
SourceId sourceId;
ModuleId moduleId;
- Version version;
+ Storage::Version version;
};
enum class IsAutoVersion : char { No, Yes };
@@ -177,7 +179,7 @@ class ModuleExportedImport
public:
explicit ModuleExportedImport(ModuleId moduleId,
ModuleId exportedModuleId,
- Version version,
+ Storage::Version version,
IsAutoVersion isAutoVersion)
: version{version}
, moduleId{moduleId}
@@ -199,7 +201,7 @@ public:
}
public:
- Version version;
+ Storage::Version version;
ModuleId moduleId;
ModuleId exportedModuleId;
IsAutoVersion isAutoVersion = IsAutoVersion::No;
@@ -234,7 +236,7 @@ public:
public:
ModuleExportedImportId moduleExportedImportId;
- Version version;
+ Storage::Version version;
ModuleId moduleId;
ModuleId exportedModuleId;
IsAutoVersion isAutoVersion = IsAutoVersion::No;
@@ -244,7 +246,7 @@ class ImportedType
{
public:
explicit ImportedType() = default;
- explicit ImportedType(Utils::SmallStringView name)
+ explicit ImportedType(::Utils::SmallStringView name)
: name{name}
{}
@@ -261,7 +263,7 @@ class QualifiedImportedType
{
public:
explicit QualifiedImportedType() = default;
- explicit QualifiedImportedType(Utils::SmallStringView name, Import import)
+ explicit QualifiedImportedType(::Utils::SmallStringView name, Import import)
: name{name}
, import{std::move(import)}
{}
@@ -282,25 +284,33 @@ class ExportedType
{
public:
explicit ExportedType() = default;
- explicit ExportedType(Utils::SmallStringView name, Version version = Version{})
+ explicit ExportedType(::Utils::SmallStringView name, Storage::Version version = Storage::Version{})
: name{name}
, version{version}
{}
- explicit ExportedType(ModuleId moduleId, Utils::SmallStringView name, Version version = Version{})
+ explicit ExportedType(ModuleId moduleId,
+ ::Utils::SmallStringView name,
+ Storage::Version version = Storage::Version{})
: name{name}
, version{version}
, moduleId{moduleId}
{}
- explicit ExportedType(Utils::SmallStringView name, Version version, TypeId typeId, ModuleId moduleId)
+ explicit ExportedType(::Utils::SmallStringView name,
+ Storage::Version version,
+ TypeId typeId,
+ ModuleId moduleId)
: name{name}
, version{version}
, typeId{typeId}
, moduleId{moduleId}
{}
- explicit ExportedType(ModuleId moduleId, Utils::SmallStringView name, int majorVersion, int minorVersion)
+ explicit ExportedType(ModuleId moduleId,
+ ::Utils::SmallStringView name,
+ int majorVersion,
+ int minorVersion)
: name{name}
, version{majorVersion, minorVersion}
, moduleId{moduleId}
@@ -318,8 +328,8 @@ public:
}
public:
- Utils::SmallString name;
- Version version;
+ ::Utils::SmallString name;
+ Storage::Version version;
TypeId typeId;
ModuleId moduleId;
};
@@ -330,13 +340,13 @@ class ExportedTypeView
{
public:
explicit ExportedTypeView() = default;
- explicit ExportedTypeView(ModuleId moduleId, Utils::SmallStringView name, Version version)
+ explicit ExportedTypeView(ModuleId moduleId, ::Utils::SmallStringView name, Storage::Version version)
: name{name}
, version{version}
, moduleId{moduleId}
{}
explicit ExportedTypeView(ModuleId moduleId,
- Utils::SmallStringView name,
+ ::Utils::SmallStringView name,
int majorVersion,
int minorVersion,
TypeId typeId,
@@ -349,8 +359,8 @@ public:
{}
public:
- Utils::SmallStringView name;
- Version version;
+ ::Utils::SmallStringView name;
+ Storage::Version version;
TypeId typeId;
ModuleId moduleId;
ExportedTypeNameId exportedTypeNameId;
@@ -362,13 +372,13 @@ class EnumeratorDeclaration
{
public:
explicit EnumeratorDeclaration() = default;
- explicit EnumeratorDeclaration(Utils::SmallStringView name, long long value, int hasValue = true)
+ explicit EnumeratorDeclaration(::Utils::SmallStringView name, long long value, int hasValue = true)
: name{name}
, value{value}
, hasValue{bool(hasValue)}
{}
- explicit EnumeratorDeclaration(Utils::SmallStringView name)
+ explicit EnumeratorDeclaration(::Utils::SmallStringView name)
: name{name}
{}
@@ -379,7 +389,7 @@ public:
}
public:
- Utils::SmallString name;
+ ::Utils::SmallString name;
long long value = 0;
bool hasValue = false;
};
@@ -390,7 +400,7 @@ class EnumerationDeclaration
{
public:
explicit EnumerationDeclaration() = default;
- explicit EnumerationDeclaration(Utils::SmallStringView name,
+ explicit EnumerationDeclaration(::Utils::SmallStringView name,
EnumeratorDeclarations enumeratorDeclarations)
: name{name}
, enumeratorDeclarations{std::move(enumeratorDeclarations)}
@@ -413,8 +423,8 @@ class EnumerationDeclarationView
{
public:
explicit EnumerationDeclarationView() = default;
- explicit EnumerationDeclarationView(Utils::SmallStringView name,
- Utils::SmallStringView enumeratorDeclarations,
+ explicit EnumerationDeclarationView(::Utils::SmallStringView name,
+ ::Utils::SmallStringView enumeratorDeclarations,
EnumerationDeclarationId id)
: name{name}
, enumeratorDeclarations{std::move(enumeratorDeclarations)}
@@ -422,8 +432,8 @@ public:
{}
public:
- Utils::SmallStringView name;
- Utils::SmallStringView enumeratorDeclarations;
+ ::Utils::SmallStringView name;
+ ::Utils::SmallStringView enumeratorDeclarations;
EnumerationDeclarationId id;
};
@@ -431,8 +441,8 @@ class ParameterDeclaration
{
public:
explicit ParameterDeclaration() = default;
- explicit ParameterDeclaration(Utils::SmallStringView name,
- Utils::SmallStringView typeName,
+ explicit ParameterDeclaration(::Utils::SmallStringView name,
+ ::Utils::SmallStringView typeName,
PropertyDeclarationTraits traits = {})
: name{name}
, typeName{typeName}
@@ -446,7 +456,7 @@ public:
}
public:
- Utils::SmallString name;
+ ::Utils::SmallString name;
TypeNameString typeName;
PropertyDeclarationTraits traits = {};
};
@@ -457,12 +467,12 @@ class SignalDeclaration
{
public:
explicit SignalDeclaration() = default;
- explicit SignalDeclaration(Utils::SmallString name, ParameterDeclarations parameters)
+ explicit SignalDeclaration(::Utils::SmallString name, ParameterDeclarations parameters)
: name{name}
, parameters{std::move(parameters)}
{}
- explicit SignalDeclaration(Utils::SmallString name)
+ explicit SignalDeclaration(::Utils::SmallString name)
: name{name}
{}
@@ -472,7 +482,7 @@ public:
}
public:
- Utils::SmallString name;
+ ::Utils::SmallString name;
ParameterDeclarations parameters;
};
@@ -482,8 +492,8 @@ class SignalDeclarationView
{
public:
explicit SignalDeclarationView() = default;
- explicit SignalDeclarationView(Utils::SmallStringView name,
- Utils::SmallStringView signature,
+ explicit SignalDeclarationView(::Utils::SmallStringView name,
+ ::Utils::SmallStringView signature,
SignalDeclarationId id)
: name{name}
, signature{signature}
@@ -491,8 +501,8 @@ public:
{}
public:
- Utils::SmallStringView name;
- Utils::SmallStringView signature;
+ ::Utils::SmallStringView name;
+ ::Utils::SmallStringView signature;
SignalDeclarationId id;
};
@@ -500,16 +510,16 @@ class FunctionDeclaration
{
public:
explicit FunctionDeclaration() = default;
- explicit FunctionDeclaration(Utils::SmallStringView name,
- Utils::SmallStringView returnTypeName,
+ explicit FunctionDeclaration(::Utils::SmallStringView name,
+ ::Utils::SmallStringView returnTypeName,
ParameterDeclarations parameters)
: name{name}
, returnTypeName{returnTypeName}
, parameters{std::move(parameters)}
{}
- explicit FunctionDeclaration(Utils::SmallStringView name,
- Utils::SmallStringView returnTypeName = {})
+ explicit FunctionDeclaration(::Utils::SmallStringView name,
+ ::Utils::SmallStringView returnTypeName = {})
: name{name}
, returnTypeName{returnTypeName}
{}
@@ -521,7 +531,7 @@ public:
}
public:
- Utils::SmallString name;
+ ::Utils::SmallString name;
TypeNameString returnTypeName;
ParameterDeclarations parameters;
};
@@ -532,9 +542,9 @@ class FunctionDeclarationView
{
public:
explicit FunctionDeclarationView() = default;
- explicit FunctionDeclarationView(Utils::SmallStringView name,
- Utils::SmallStringView returnTypeName,
- Utils::SmallStringView signature,
+ explicit FunctionDeclarationView(::Utils::SmallStringView name,
+ ::Utils::SmallStringView returnTypeName,
+ ::Utils::SmallStringView signature,
FunctionDeclarationId id)
: name{name}
, returnTypeName{returnTypeName}
@@ -543,9 +553,9 @@ public:
{}
public:
- Utils::SmallStringView name;
- Utils::SmallStringView returnTypeName;
- Utils::SmallStringView signature;
+ ::Utils::SmallStringView name;
+ ::Utils::SmallStringView returnTypeName;
+ ::Utils::SmallStringView signature;
FunctionDeclarationId id;
};
@@ -555,7 +565,7 @@ class PropertyDeclaration
{
public:
explicit PropertyDeclaration() = default;
- explicit PropertyDeclaration(Utils::SmallStringView name,
+ explicit PropertyDeclaration(::Utils::SmallStringView name,
ImportedTypeName typeName,
PropertyDeclarationTraits traits)
: name{name}
@@ -564,7 +574,7 @@ public:
, kind{PropertyKind::Property}
{}
- explicit PropertyDeclaration(Utils::SmallStringView name,
+ explicit PropertyDeclaration(::Utils::SmallStringView name,
TypeId propertyTypeId,
PropertyDeclarationTraits traits)
: name{name}
@@ -573,11 +583,11 @@ public:
, kind{PropertyKind::Property}
{}
- explicit PropertyDeclaration(Utils::SmallStringView name,
+ explicit PropertyDeclaration(::Utils::SmallStringView name,
ImportedTypeName typeName,
PropertyDeclarationTraits traits,
- Utils::SmallStringView aliasPropertyName,
- Utils::SmallStringView aliasPropertyNameTail = {})
+ ::Utils::SmallStringView aliasPropertyName,
+ ::Utils::SmallStringView aliasPropertyNameTail = {})
: name{name}
, typeName{std::move(typeName)}
, aliasPropertyName{aliasPropertyName}
@@ -587,11 +597,11 @@ public:
, kind{PropertyKind::Property}
{}
- explicit PropertyDeclaration(Utils::SmallStringView name,
+ explicit PropertyDeclaration(::Utils::SmallStringView name,
TypeId propertyTypeId,
PropertyDeclarationTraits traits,
- Utils::SmallStringView aliasPropertyName,
- Utils::SmallStringView aliasPropertyNameTail = {})
+ ::Utils::SmallStringView aliasPropertyName,
+ ::Utils::SmallStringView aliasPropertyNameTail = {})
: name{name}
, aliasPropertyName{aliasPropertyName}
, aliasPropertyNameTail{aliasPropertyNameTail}
@@ -600,10 +610,10 @@ public:
, kind{PropertyKind::Property}
{}
- explicit PropertyDeclaration(Utils::SmallStringView name,
+ explicit PropertyDeclaration(::Utils::SmallStringView name,
ImportedTypeName aliasTypeName,
- Utils::SmallStringView aliasPropertyName,
- Utils::SmallStringView aliasPropertyNameTail = {})
+ ::Utils::SmallStringView aliasPropertyName,
+ ::Utils::SmallStringView aliasPropertyNameTail = {})
: name{name}
, typeName{std::move(aliasTypeName)}
, aliasPropertyName{aliasPropertyName}
@@ -621,10 +631,10 @@ public:
}
public:
- Utils::SmallString name;
+ ::Utils::SmallString name;
ImportedTypeName typeName;
- Utils::SmallString aliasPropertyName;
- Utils::SmallString aliasPropertyNameTail;
+ ::Utils::SmallString aliasPropertyName;
+ ::Utils::SmallString aliasPropertyNameTail;
PropertyDeclarationTraits traits = {};
TypeId propertyTypeId;
TypeId typeId;
@@ -636,7 +646,7 @@ using PropertyDeclarations = std::vector<PropertyDeclaration>;
class PropertyDeclarationView
{
public:
- explicit PropertyDeclarationView(Utils::SmallStringView name,
+ explicit PropertyDeclarationView(::Utils::SmallStringView name,
PropertyDeclarationTraits traits,
TypeId typeId,
ImportedTypeNameId typeNameId,
@@ -651,7 +661,7 @@ public:
{}
public:
- Utils::SmallStringView name;
+ ::Utils::SmallStringView name;
PropertyDeclarationTraits traits = {};
TypeId typeId;
ImportedTypeNameId typeNameId;
@@ -665,7 +675,7 @@ class Type
{
public:
explicit Type() = default;
- explicit Type(Utils::SmallStringView typeName,
+ explicit Type(::Utils::SmallStringView typeName,
ImportedTypeName prototype,
ImportedTypeName extension,
TypeTraits traits,
@@ -676,7 +686,7 @@ public:
SignalDeclarations signalDeclarations = {},
EnumerationDeclarations enumerationDeclarations = {},
ChangeLevel changeLevel = ChangeLevel::Full,
- Utils::SmallStringView defaultPropertyName = {})
+ ::Utils::SmallStringView defaultPropertyName = {})
: typeName{typeName}
, defaultPropertyName{defaultPropertyName}
, prototype{std::move(prototype)}
@@ -691,7 +701,7 @@ public:
, changeLevel{changeLevel}
{}
- explicit Type(Utils::SmallStringView typeName,
+ explicit Type(::Utils::SmallStringView typeName,
TypeId prototypeId,
TypeId extensionId,
TypeTraits traits,
@@ -703,7 +713,7 @@ public:
, extensionId{extensionId}
{}
- explicit Type(Utils::SmallStringView typeName,
+ explicit Type(::Utils::SmallStringView typeName,
ImportedTypeName prototype,
TypeTraits traits,
SourceId sourceId,
@@ -715,9 +725,9 @@ public:
, changeLevel{changeLevel}
{}
- explicit Type(Utils::SmallStringView typeName,
- Utils::SmallStringView prototype,
- Utils::SmallStringView extension,
+ explicit Type(::Utils::SmallStringView typeName,
+ ::Utils::SmallStringView prototype,
+ ::Utils::SmallStringView extension,
TypeTraits traits,
SourceId sourceId)
: typeName{typeName}
@@ -729,12 +739,12 @@ public:
{}
explicit Type(SourceId sourceId,
- Utils::SmallStringView typeName,
+ ::Utils::SmallStringView typeName,
TypeId typeId,
TypeId prototypeId,
TypeId extensionId,
TypeTraits traits,
- Utils::SmallStringView defaultPropertyName)
+ ::Utils::SmallStringView defaultPropertyName)
: typeName{typeName}
, defaultPropertyName{defaultPropertyName}
, traits{traits}
@@ -758,7 +768,7 @@ public:
public:
TypeNameString typeName;
- Utils::SmallString defaultPropertyName;
+ ::Utils::SmallString defaultPropertyName;
ImportedTypeName prototype;
ImportedTypeName extension;
ExportedTypes exportedTypes;
@@ -855,5 +865,5 @@ public:
ModuleIds updatedModuleIds;
};
-} // namespace QmlDesigner::Storage::Synchronization
-
+} // namespace Synchronization
+} // namespace QmlDesigner::Storage
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp
index f98c69734a8..4713dd0136f 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.cpp
@@ -113,9 +113,9 @@ void addSourceIds(SourceIds &sourceIds, const Storage::Synchronization::ProjectD
sourceIds.push_back(projectData.sourceId);
}
-Storage::Synchronization::Version convertVersion(LanguageUtils::ComponentVersion version)
+Storage::Version convertVersion(LanguageUtils::ComponentVersion version)
{
- return Storage::Synchronization::Version{version.majorVersion(), version.minorVersion()};
+ return Storage::Version{version.majorVersion(), version.minorVersion()};
}
Storage::Synchronization::IsAutoVersion convertToIsAutoVersion(QmlDirParser::Import::Flags flags)
@@ -133,7 +133,7 @@ void addDependencies(Storage::Synchronization::Imports &dependencies,
for (const QmlDirParser::Import &qmldirDependency : qmldirDependencies) {
ModuleId moduleId = projectStorage.moduleId(Utils::PathString{qmldirDependency.module}
+ "-cppnative");
- dependencies.emplace_back(moduleId, Storage::Synchronization::Version{}, sourceId);
+ dependencies.emplace_back(moduleId, Storage::Version{}, sourceId);
}
}
@@ -154,46 +154,53 @@ void addModuleExportedImports(Storage::Synchronization::ModuleExportedImports &i
Utils::PathString{qmldirImport.module} + "-cppnative");
imports.emplace_back(cppModuleId,
exportedCppModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
Storage::Synchronization::IsAutoVersion::No);
}
}
-} // namespace
-
-void ProjectStorageUpdater::update(QStringList directories,
- QStringList qmlTypesPaths,
+std::vector<IdPaths> createIdPaths(ProjectStorageUpdater::WatchedSourceIdsIds watchedSourceIds,
ProjectPartId projectPartId)
{
- Storage::Synchronization::SynchronizationPackage package;
- SourceIdsData sourceIdsData{static_cast<std::size_t>(directories.size())};
std::vector<IdPaths> idPaths;
idPaths.reserve(4);
- updateDirectories(directories, package, sourceIdsData);
- updateQmlTypes(qmlTypesPaths, package, sourceIdsData);
+ idPaths.push_back(
+ {projectPartId, SourceType::Directory, std::move(watchedSourceIds.directorySourceIds)});
+ idPaths.push_back({projectPartId, SourceType::QmlDir, std::move(watchedSourceIds.qmldirSourceIds)});
+ idPaths.push_back({projectPartId, SourceType::Qml, std::move(watchedSourceIds.qmlSourceIds)});
+ idPaths.push_back(
+ {projectPartId, SourceType::QmlTypes, std::move(watchedSourceIds.qmltypesSourceIds)});
+
+ return idPaths;
+}
+
+} // namespace
+
+void ProjectStorageUpdater::update(QStringList directories, QStringList qmlTypesPaths)
+{
+ Storage::Synchronization::SynchronizationPackage package;
+ WatchedSourceIdsIds watchedSourceIds{Utils::span{directories}.size()};
+ NotUpdatedSourceIds notUpdatedSourceIds{Utils::span{directories}.size()};
+
+ updateDirectories(directories, package, notUpdatedSourceIds, watchedSourceIds);
+ updateQmlTypes(qmlTypesPaths, package, notUpdatedSourceIds, watchedSourceIds);
package.updatedSourceIds = filterNotUpdatedSourceIds(std::move(package.updatedSourceIds),
- std::move(sourceIdsData.notUpdatedSourceIds));
+ std::move(notUpdatedSourceIds.sourceIds));
package.updatedFileStatusSourceIds = filterNotUpdatedSourceIds(
std::move(package.updatedFileStatusSourceIds),
- std::move(sourceIdsData.notUpdatedFileStatusSourceIds));
+ std::move(notUpdatedSourceIds.fileStatusSourceIds));
m_projectStorage.synchronize(std::move(package));
- idPaths.push_back(
- {projectPartId, SourceType::Directory, std::move(sourceIdsData.watchedDirectorySourceIds)});
- idPaths.push_back(
- {projectPartId, SourceType::QmlDir, std::move(sourceIdsData.watchedQmldirSourceIds)});
- idPaths.push_back({projectPartId, SourceType::Qml, std::move(sourceIdsData.watchedQmlSourceIds)});
- idPaths.push_back(
- {projectPartId, SourceType::QmlTypes, std::move(sourceIdsData.watchedQmltypesSourceIds)});
- m_pathWatcher.updateIdPaths(idPaths);
+ m_pathWatcher.updateIdPaths(createIdPaths(watchedSourceIds, m_projectPartId));
}
void ProjectStorageUpdater::updateQmlTypes(const QStringList &qmlTypesPaths,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdsData)
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds)
{
if (qmlTypesPaths.empty())
return;
@@ -202,7 +209,7 @@ void ProjectStorageUpdater::updateQmlTypes(const QStringList &qmlTypesPaths,
for (const QString &qmlTypesPath : qmlTypesPaths) {
SourceId sourceId = m_pathCache.sourceId(SourcePath{qmlTypesPath});
- sourceIdsData.watchedQmltypesSourceIds.push_back(sourceId);
+ watchedSourceIdsIds.qmltypesSourceIds.push_back(sourceId);
Storage::Synchronization::ProjectData projectData{sourceId,
sourceId,
@@ -212,7 +219,7 @@ void ProjectStorageUpdater::updateQmlTypes(const QStringList &qmlTypesPaths,
FileState state = parseTypeInfo(projectData,
Utils::PathString{qmlTypesPath},
package,
- sourceIdsData);
+ notUpdatedSourceIds);
if (state == FileState::Changed)
package.projectDatas.push_back(std::move(projectData));
@@ -235,28 +242,30 @@ ProjectStorageUpdater::FileState combineState(FileStates... fileStates)
void ProjectStorageUpdater::updateDirectories(const QStringList &directories,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdsData)
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds)
{
for (const QString &directory : directories)
- updateDirectory({directory}, package, sourceIdsData);
+ updateDirectory({directory}, package, notUpdatedSourceIds, watchedSourceIdsIds);
}
void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPath,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdsData)
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds)
{
SourcePath qmldirSourcePath{directoryPath + "/qmldir"};
auto [directoryId, qmlDirSourceId] = m_pathCache.sourceContextAndSourceId(qmldirSourcePath);
SourcePath directorySourcePath{directoryPath + "/."};
auto directorySourceId = m_pathCache.sourceId(directorySourcePath);
- auto directoryState = fileState(directorySourceId, package, sourceIdsData);
+ auto directoryState = fileState(directorySourceId, package, notUpdatedSourceIds);
if (directoryState != FileState::NotExists)
- sourceIdsData.watchedDirectorySourceIds.push_back(directorySourceId);
+ watchedSourceIdsIds.directorySourceIds.push_back(directorySourceId);
- auto qmldirState = fileState(qmlDirSourceId, package, sourceIdsData);
+ auto qmldirState = fileState(qmlDirSourceId, package, notUpdatedSourceIds);
if (qmldirState != FileState::NotExists)
- sourceIdsData.watchedQmldirSourceIds.push_back(qmlDirSourceId);
+ watchedSourceIdsIds.qmldirSourceIds.push_back(qmlDirSourceId);
switch (combineState(directoryState, qmldirState)) {
case FileState::Changed: {
@@ -295,20 +304,25 @@ void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPa
directoryPath,
cppModuleId,
package,
- sourceIdsData);
+ notUpdatedSourceIds,
+ watchedSourceIdsIds);
}
parseQmlComponents(
createComponents(parser.components(), moduleId, pathModuleId, m_fileSystem, directoryPath),
directorySourceId,
directoryId,
package,
- sourceIdsData,
+ notUpdatedSourceIds,
+ watchedSourceIdsIds,
qmldirState);
package.updatedProjectSourceIds.push_back(directorySourceId);
break;
}
case FileState::NotChanged: {
- parseProjectDatas(m_projectStorage.fetchProjectDatas(directorySourceId), package, sourceIdsData);
+ parseProjectDatas(m_projectStorage.fetchProjectDatas(directorySourceId),
+ package,
+ notUpdatedSourceIds,
+ watchedSourceIdsIds);
break;
}
case FileState::NotExists: {
@@ -327,7 +341,118 @@ void ProjectStorageUpdater::updateDirectory(const Utils::PathString &directoryPa
}
}
-void ProjectStorageUpdater::pathsWithIdsChanged([[maybe_unused]] const std::vector<IdPaths> &) {}
+namespace {
+SourceContextIds filterUniqueSourceContextIds(const SourceIds &sourceIds,
+ ProjectStorageUpdater::PathCache &pathCache)
+{
+ auto sourceContextIds = Utils::transform(sourceIds, [&](SourceId sourceId) {
+ return pathCache.sourceContextId(sourceId);
+ });
+
+ std::sort(sourceContextIds.begin(), sourceContextIds.end());
+ auto newEnd = std::unique(sourceContextIds.begin(), sourceContextIds.end());
+ sourceContextIds.erase(newEnd, sourceContextIds.end());
+
+ return sourceContextIds;
+}
+
+SourceIds filterUniqueSourceIds(SourceIds sourceIds)
+{
+ std::sort(sourceIds.begin(), sourceIds.end());
+ auto newEnd = std::unique(sourceIds.begin(), sourceIds.end());
+ sourceIds.erase(newEnd, sourceIds.end());
+
+ return sourceIds;
+}
+
+template<typename Container, typename Id>
+bool contains(const Container &container, Id id)
+{
+ return std::find(container.begin(), container.end(), id) != container.end();
+}
+} // namespace
+
+void ProjectStorageUpdater::pathsWithIdsChanged(const std::vector<IdPaths> &changedIdPaths)
+{
+ m_changedIdPaths.insert(m_changedIdPaths.end(), changedIdPaths.begin(), changedIdPaths.end());
+
+ Storage::Synchronization::SynchronizationPackage package;
+
+ WatchedSourceIdsIds watchedSourceIds{10};
+ NotUpdatedSourceIds notUpdatedSourceIds{10};
+ std::vector<IdPaths> idPaths;
+ idPaths.reserve(4);
+
+ SourceIds directorySourceIds;
+ directorySourceIds.reserve(32);
+ SourceIds qmlDocumentSourceIds;
+ qmlDocumentSourceIds.reserve(128);
+ SourceIds qmltypesSourceIds;
+ qmltypesSourceIds.reserve(32);
+
+ for (const auto &[projectChunkId, sourceIds] : m_changedIdPaths) {
+ if (projectChunkId.id != m_projectPartId)
+ continue;
+
+ switch (projectChunkId.sourceType) {
+ case SourceType::Directory:
+ case SourceType::QmlDir:
+ directorySourceIds.insert(directorySourceIds.end(), sourceIds.begin(), sourceIds.end());
+ break;
+ case SourceType::Qml:
+ case SourceType::QmlUi:
+ qmlDocumentSourceIds.insert(qmlDocumentSourceIds.end(), sourceIds.begin(), sourceIds.end());
+ break;
+ case SourceType::QmlTypes:
+ qmltypesSourceIds.insert(qmltypesSourceIds.end(), sourceIds.begin(), sourceIds.end());
+ break;
+ }
+ }
+
+ auto directorySourceContextIds = filterUniqueSourceContextIds(directorySourceIds, m_pathCache);
+
+ for (auto sourceContextId : directorySourceContextIds) {
+ Utils::PathString directory = m_pathCache.sourceContextPath(sourceContextId);
+ updateDirectory(directory, package, notUpdatedSourceIds, watchedSourceIds);
+ }
+
+ for (SourceId sourceId : filterUniqueSourceIds(qmlDocumentSourceIds)) {
+ if (!contains(directorySourceContextIds, m_pathCache.sourceContextId(sourceId)))
+ parseQmlComponent(sourceId, package, notUpdatedSourceIds);
+ }
+
+ try {
+ for (SourceId sourceId : filterUniqueSourceIds(std::move(qmltypesSourceIds))) {
+ if (!contains(directorySourceContextIds, m_pathCache.sourceContextId(sourceId))) {
+ auto qmltypesPath = m_pathCache.sourcePath(sourceId);
+ auto projectData = m_projectStorage.fetchProjectData(sourceId);
+ if (projectData)
+ parseTypeInfo(*projectData, qmltypesPath, package, notUpdatedSourceIds);
+ }
+ }
+ } catch (const QmlDesigner::CannotParseQmlTypesFile &) {
+ return;
+ }
+
+ package.updatedSourceIds = filterNotUpdatedSourceIds(std::move(package.updatedSourceIds),
+ std::move(notUpdatedSourceIds.sourceIds));
+ package.updatedFileStatusSourceIds = filterNotUpdatedSourceIds(
+ std::move(package.updatedFileStatusSourceIds),
+ std::move(notUpdatedSourceIds.fileStatusSourceIds));
+
+ try {
+ m_projectStorage.synchronize(std::move(package));
+ } catch (const ProjectStorageError &) {
+ return;
+ }
+
+ if (directorySourceContextIds.size()) {
+ m_pathWatcher.updateContextIdPaths(createIdPaths(watchedSourceIds, m_projectPartId),
+ directorySourceContextIds);
+ }
+
+ m_changedIdPaths.clear();
+}
void ProjectStorageUpdater::pathsChanged(const SourceIds &) {}
@@ -338,14 +463,15 @@ void ProjectStorageUpdater::parseTypeInfos(const QStringList &typeInfos,
Utils::SmallStringView directoryPath,
ModuleId moduleId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData)
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIds)
{
for (const QString &typeInfo : typeInfos) {
Utils::PathString qmltypesPath = Utils::PathString::join(
{directoryPath, "/", Utils::SmallString{typeInfo}});
SourceId sourceId = m_pathCache.sourceId(SourcePathView{qmltypesPath});
- sourceIdData.watchedQmltypesSourceIds.push_back(sourceId);
+ watchedSourceIds.qmltypesSourceIds.push_back(sourceId);
addDependencies(package.moduleDependencies,
sourceId,
@@ -356,27 +482,28 @@ void ProjectStorageUpdater::parseTypeInfos(const QStringList &typeInfos,
auto projectData = package.projectDatas.emplace_back(
directorySourceId, sourceId, moduleId, Storage::Synchronization::FileType::QmlTypes);
- parseTypeInfo(projectData, qmltypesPath, package, sourceIdData);
+ parseTypeInfo(projectData, qmltypesPath, package, notUpdatedSourceIds);
}
}
void ProjectStorageUpdater::parseProjectDatas(const Storage::Synchronization::ProjectDatas &projectDatas,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData)
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIds)
{
for (const Storage::Synchronization::ProjectData &projectData : projectDatas) {
switch (projectData.fileType) {
case Storage::Synchronization::FileType::QmlTypes: {
- sourceIdData.watchedQmltypesSourceIds.push_back(projectData.sourceId);
+ watchedSourceIds.qmltypesSourceIds.push_back(projectData.sourceId);
auto qmltypesPath = m_pathCache.sourcePath(projectData.sourceId);
- parseTypeInfo(projectData, qmltypesPath, package, sourceIdData);
+ parseTypeInfo(projectData, qmltypesPath, package, notUpdatedSourceIds);
break;
}
case Storage::Synchronization::FileType::QmlDocument: {
- sourceIdData.watchedQmlSourceIds.push_back(projectData.sourceId);
+ watchedSourceIds.qmlSourceIds.push_back(projectData.sourceId);
- parseQmlComponent(projectData.sourceId, package, sourceIdData);
+ parseQmlComponent(projectData.sourceId, package, notUpdatedSourceIds);
}
};
}
@@ -385,9 +512,9 @@ void ProjectStorageUpdater::parseProjectDatas(const Storage::Synchronization::Pr
auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::ProjectData &projectData,
Utils::SmallStringView qmltypesPath,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData) -> FileState
+ NotUpdatedSourceIds &notUpdatedSourceIds) -> FileState
{
- auto state = fileState(projectData.sourceId, package, sourceIdData);
+ auto state = fileState(projectData.sourceId, package, notUpdatedSourceIds);
switch (state) {
case FileState::Changed: {
package.updatedSourceIds.push_back(projectData.sourceId);
@@ -397,7 +524,7 @@ auto ProjectStorageUpdater::parseTypeInfo(const Storage::Synchronization::Projec
break;
}
case FileState::NotChanged: {
- sourceIdData.notUpdatedSourceIds.push_back(projectData.sourceId);
+ notUpdatedSourceIds.sourceIds.push_back(projectData.sourceId);
break;
}
case FileState::NotExists:
@@ -413,7 +540,8 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil
Storage::Synchronization::ExportedTypes exportedTypes,
SourceId directorySourceId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIds,
FileState qmldirState)
{
if (std::find(relativeFilePath.begin(), relativeFilePath.end(), '+') != relativeFilePath.end())
@@ -423,14 +551,14 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil
SourceId sourceId = m_pathCache.sourceId(SourcePathView{qmlFilePath});
Storage::Synchronization::Type type;
- auto state = fileState(sourceId, package, sourceIdData);
+ auto state = fileState(sourceId, package, notUpdatedSourceIds);
- sourceIdData.watchedQmlSourceIds.push_back(sourceId);
+ watchedSourceIds.qmlSourceIds.push_back(sourceId);
switch (state) {
case FileState::NotChanged:
if (qmldirState == FileState::NotExists) {
- sourceIdData.notUpdatedSourceIds.emplace_back(sourceId);
+ notUpdatedSourceIds.sourceIds.emplace_back(sourceId);
package.projectDatas.emplace_back(directorySourceId,
sourceId,
ModuleId{},
@@ -465,14 +593,17 @@ void ProjectStorageUpdater::parseQmlComponent(Utils::SmallStringView relativeFil
void ProjectStorageUpdater::parseQmlComponent(SourceId sourceId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData)
+ NotUpdatedSourceIds &notUpdatedSourceIds)
{
- auto state = fileState(sourceId, package, sourceIdData);
- if (state != FileState::Changed)
+ auto state = fileState(sourceId, package, notUpdatedSourceIds);
+ if (state == FileState::NotChanged)
return;
package.updatedSourceIds.push_back(sourceId);
+ if (state == FileState::NotExists)
+ return;
+
SourcePath sourcePath = m_pathCache.sourcePath(sourceId);
const auto content = m_fileSystem.contentAsQString(QString{sourcePath});
@@ -513,8 +644,7 @@ Storage::Synchronization::ExportedTypes createExportedTypes(ProjectStorageUpdate
for (const ProjectStorageUpdater::Component &component : components) {
exportedTypes.emplace_back(component.moduleId,
Utils::SmallString{component.typeName},
- Storage::Synchronization::Version{component.majorVersion,
- component.minorVersion});
+ Storage::Version{component.majorVersion, component.minorVersion});
}
return exportedTypes;
@@ -526,7 +656,8 @@ void ProjectStorageUpdater::parseQmlComponents(Components components,
SourceId directorySourceId,
SourceContextId directoryId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdsData,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds,
FileState qmldirState)
{
std::sort(components.begin(), components.end(), [](auto &&first, auto &&second) {
@@ -543,7 +674,8 @@ void ProjectStorageUpdater::parseQmlComponents(Components components,
createExportedTypes(componentsWithSameFileName),
directorySourceId,
package,
- sourceIdsData,
+ notUpdatedSourceIds,
+ watchedSourceIdsIds,
qmldirState);
};
@@ -553,7 +685,7 @@ void ProjectStorageUpdater::parseQmlComponents(Components components,
ProjectStorageUpdater::FileState ProjectStorageUpdater::fileState(
SourceId sourceId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData) const
+ NotUpdatedSourceIds &notUpdatedSourceIds) const
{
auto currentFileStatus = m_fileStatusCache.find(sourceId);
@@ -570,7 +702,7 @@ ProjectStorageUpdater::FileState ProjectStorageUpdater::fileState(
return FileState::Changed;
}
- sourceIdData.notUpdatedFileStatusSourceIds.push_back(sourceId);
+ notUpdatedSourceIds.fileStatusSourceIds.push_back(sourceId);
return FileState::NotChanged;
}
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h
index 90ce4d543d1..22778ac932a 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/projectstorageupdater.h
@@ -43,7 +43,8 @@ public:
PathCache &pathCache,
QmlDocumentParserInterface &qmlDocumentParser,
QmlTypesParserInterface &qmlTypesParser,
- class ProjectStoragePathWatcherInterface &pathWatcher)
+ class ProjectStoragePathWatcherInterface &pathWatcher,
+ ProjectPartId projectPartId)
: m_fileSystem{fileSystem}
, m_projectStorage{projectStorage}
, m_fileStatusCache{fileStatusCache}
@@ -51,11 +52,10 @@ public:
, m_qmlDocumentParser{qmlDocumentParser}
, m_qmlTypesParser{qmlTypesParser}
, m_pathWatcher{pathWatcher}
+ , m_projectPartId{projectPartId}
{}
- void update(QStringList directories,
- QStringList qmlTypesPaths,
- ProjectPartId projectPartId = ProjectPartId{});
+ void update(QStringList directories, QStringList qmlTypesPaths);
void pathsWithIdsChanged(const std::vector<IdPaths> &idPaths) override;
void pathsChanged(const SourceIds &filePathIds) override;
@@ -96,38 +96,49 @@ public:
NotExists,
};
-private:
- struct SourceIdsData
+ struct WatchedSourceIdsIds
+ {
+ WatchedSourceIdsIds(std::size_t reserve)
+ {
+ directorySourceIds.reserve(reserve);
+ qmldirSourceIds.reserve(reserve);
+ qmlSourceIds.reserve(reserve * 30);
+ qmltypesSourceIds.reserve(reserve * 30);
+ }
+
+ SourceIds directorySourceIds;
+ SourceIds qmldirSourceIds;
+ SourceIds qmlSourceIds;
+ SourceIds qmltypesSourceIds;
+ };
+
+ struct NotUpdatedSourceIds
{
- SourceIdsData(std::size_t reserve)
+ NotUpdatedSourceIds(std::size_t reserve)
{
- notUpdatedFileStatusSourceIds.reserve(reserve * 30);
- notUpdatedSourceIds.reserve(reserve * 30);
- watchedDirectorySourceIds.reserve(reserve);
- watchedQmldirSourceIds.reserve(reserve);
- watchedQmlSourceIds.reserve(reserve * 30);
- watchedQmltypesSourceIds.reserve(reserve * 30);
+ fileStatusSourceIds.reserve(reserve * 30);
+ sourceIds.reserve(reserve * 30);
}
- SourceIds notUpdatedFileStatusSourceIds;
- SourceIds notUpdatedSourceIds;
- SourceIds watchedDirectorySourceIds;
- SourceIds watchedQmldirSourceIds;
- SourceIds watchedQmlSourceIds;
- SourceIds watchedQmltypesSourceIds;
+ SourceIds fileStatusSourceIds;
+ SourceIds sourceIds;
};
+private:
void updateQmlTypes(const QStringList &qmlTypesPaths,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData);
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds);
void updateDirectories(const QStringList &directories,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData);
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds);
void updateDirectory(const Utils::PathString &directory,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData);
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds);
void parseTypeInfos(const QStringList &typeInfos,
const QList<QmlDirParser::Import> &qmldirDependencies,
@@ -136,36 +147,41 @@ private:
Utils::SmallStringView directoryPath,
ModuleId moduleId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData);
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds);
void parseProjectDatas(const Storage::Synchronization::ProjectDatas &projectDatas,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData);
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds);
FileState parseTypeInfo(const Storage::Synchronization::ProjectData &projectData,
Utils::SmallStringView qmltypesPath,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData);
+ NotUpdatedSourceIds &notUpdatedSourceIds);
void parseQmlComponents(Components components,
SourceId directorySourceId,
SourceContextId directoryId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds,
FileState qmldirState);
void parseQmlComponent(Utils::SmallStringView fileName,
Utils::SmallStringView directory,
Storage::Synchronization::ExportedTypes exportedTypes,
SourceId directorySourceId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData,
+ NotUpdatedSourceIds &notUpdatedSourceIds,
+ WatchedSourceIdsIds &watchedSourceIdsIds,
FileState qmldirState);
void parseQmlComponent(SourceId sourceId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData);
+ NotUpdatedSourceIds &notUpdatedSourceIds);
FileState fileState(SourceId sourceId,
Storage::Synchronization::SynchronizationPackage &package,
- SourceIdsData &sourceIdData) const;
+ NotUpdatedSourceIds &notUpdatedSourceIds) const;
private:
+ std::vector<IdPaths> m_changedIdPaths;
FileSystemInterface &m_fileSystem;
ProjectStorageInterface &m_projectStorage;
FileStatusCache &m_fileStatusCache;
@@ -173,6 +189,7 @@ private:
QmlDocumentParserInterface &m_qmlDocumentParser;
QmlTypesParserInterface &m_qmlTypesParser;
ProjectStoragePathWatcherInterface &m_pathWatcher;
+ ProjectPartId m_projectPartId;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp
index 97aac6a8577..3e9ac43deda 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.cpp
@@ -10,7 +10,7 @@
#include <sqlitedatabase.h>
-#ifdef QDS_HAS_QMLDOM
+#ifdef QDS_BUILD_QMLPARSER
#include <private/qqmldomtop_p.h>
#endif
@@ -19,7 +19,7 @@
namespace QmlDesigner {
-#ifdef QDS_HAS_QMLDOM
+#ifdef QDS_BUILD_QMLPARSER
namespace QmlDom = QQmlJS::Dom;
@@ -32,9 +32,9 @@ int convertVersionNumber(qint32 versionNumber)
return versionNumber < 0 ? -1 : versionNumber;
}
-Storage::Synchronization::Version convertVersion(QmlDom::Version version)
+Storage::Version convertVersion(QmlDom::Version version)
{
- return Storage::Synchronization::Version{convertVersionNumber(version.majorVersion),
+ return Storage::Version{convertVersionNumber(version.majorVersion),
convertVersionNumber(version.minorVersion)};
}
@@ -66,7 +66,7 @@ Storage::Synchronization::Import createImport(const QmlDom::Import &qmlImport,
if (uri.kind() == QmlUriKind::RelativePath) {
auto path = createNormalizedPath(directoryPath, uri.localPath());
auto moduleId = storage.moduleId(createNormalizedPath(directoryPath, uri.localPath()));
- return Storage::Synchronization::Import(moduleId, Storage::Synchronization::Version{}, sourceId);
+ return Storage::Synchronization::Import(moduleId, Storage::Version{}, sourceId);
}
if (uri.kind() == QmlUriKind::ModuleUri) {
@@ -109,11 +109,11 @@ void addImports(Storage::Synchronization::Imports &imports,
}
auto localDirectoryModuleId = storage.moduleId(directoryPath);
- imports.emplace_back(localDirectoryModuleId, Storage::Synchronization::Version{}, sourceId);
+ imports.emplace_back(localDirectoryModuleId, Storage::Version{}, sourceId);
++importCount;
auto qmlModuleId = storage.moduleId("QML");
- imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId);
+ imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId);
++importCount;
auto end = imports.end();
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h
index 744825aadc5..2896d54ebe7 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/qmldocumentparser.h
@@ -18,7 +18,7 @@ public:
using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>;
using PathCache = QmlDesigner::SourcePathCache<ProjectStorage, NonLockingMutex>;
-#ifdef QDS_HAS_QMLDOM
+#ifdef QDS_BUILD_QMLPARSER
QmlDocumentParser(ProjectStorage &storage, PathCache &pathCache)
: m_storage{storage}
, m_pathCache{pathCache}
@@ -35,7 +35,7 @@ public:
private:
// m_pathCache and m_storage are only used when compiled for QDS
-#ifdef QDS_HAS_QMLDOM
+#ifdef QDS_BUILD_QMLPARSER
ProjectStorage &m_storage;
PathCache &m_pathCache;
#endif
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp
index bca7b3279d8..c858076aa19 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp
+++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.cpp
@@ -4,11 +4,10 @@
#include "qmltypesparser.h"
#include "projectstorage.h"
-#include "sourcepathcache.h"
#include <sqlitedatabase.h>
-#ifdef QDS_HAS_QMLDOM
+#ifdef QDS_BUILD_QMLPARSER
#include <private/qqmldomtop_p.h>
#include <private/qqmljstypedescriptionreader_p.h>
#endif
@@ -20,7 +19,7 @@
namespace QmlDesigner {
-#ifdef QDS_HAS_QMLDOM
+#ifdef QDS_BUILD_QMLPARSER
namespace QmlDom = QQmlJS::Dom;
@@ -63,7 +62,7 @@ void appendImports(Storage::Synchronization::Imports &imports,
moduleName.append("-cppnative");
ModuleId cppModuleId = storage.moduleId(moduleName);
- imports.emplace_back(cppModuleId, Storage::Synchronization::Version{}, sourceId);
+ imports.emplace_back(cppModuleId, Storage::Version{}, sourceId);
}
void addImports(Storage::Synchronization::Imports &imports,
@@ -75,10 +74,10 @@ void addImports(Storage::Synchronization::Imports &imports,
for (const QString &dependency : dependencies)
appendImports(imports, dependency, sourceId, storage);
- imports.emplace_back(cppModuleId, Storage::Synchronization::Version{}, sourceId);
+ imports.emplace_back(cppModuleId, Storage::Version{}, sourceId);
if (ModuleId qmlCppModuleId = storage.moduleId("QML-cppnative"); cppModuleId != qmlCppModuleId)
- imports.emplace_back(qmlCppModuleId, Storage::Synchronization::Version{}, sourceId);
+ imports.emplace_back(qmlCppModuleId, Storage::Version{}, sourceId);
}
Storage::TypeTraits createTypeTraits(QQmlJSScope::AccessSemantics accessSematics)
@@ -97,9 +96,9 @@ Storage::TypeTraits createTypeTraits(QQmlJSScope::AccessSemantics accessSematics
return Storage::TypeTraits::None;
}
-Storage::Synchronization::Version createVersion(QTypeRevision qmlVersion)
+Storage::Version createVersion(QTypeRevision qmlVersion)
{
- return Storage::Synchronization::Version{qmlVersion.majorVersion(), qmlVersion.minorVersion()};
+ return Storage::Version{qmlVersion.majorVersion(), qmlVersion.minorVersion()};
}
Storage::Synchronization::ExportedTypes createExports(const QList<QQmlJSScope::Export> &qmlExports,
diff --git a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h
index 09513bb74e3..c1d9a3a0d45 100644
--- a/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h
+++ b/src/plugins/qmldesigner/designercore/projectstorage/qmltypesparser.h
@@ -22,16 +22,13 @@ class QmlTypesParser : public QmlTypesParserInterface
{
public:
using ProjectStorage = QmlDesigner::ProjectStorage<Sqlite::Database>;
- using PathCache = QmlDesigner::SourcePathCache<ProjectStorage, NonLockingMutex>;
-#ifdef QDS_HAS_QMLDOM
- QmlTypesParser(PathCache &pathCache, ProjectStorage &storage)
- : m_pathCache{pathCache}
- , m_storage{storage}
+#ifdef QDS_BUILD_QMLPARSER
+ QmlTypesParser(ProjectStorage &storage)
+ : m_storage{storage}
{}
#else
- QmlTypesParser(PathCache &, ProjectStorage &)
- {}
+ QmlTypesParser(ProjectStorage &) {}
#endif
void parse(const QString &sourceContent,
@@ -40,9 +37,7 @@ public:
const Storage::Synchronization::ProjectData &projectData) override;
private:
- // m_pathCache and m_storage are only used when compiled for QDS
-#ifdef QDS_HAS_QMLDOM
- [[maybe_unused]] PathCache &m_pathCache;
+#ifdef QDS_BUILD_QMLPARSER
ProjectStorage &m_storage;
#endif
};
diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp
index 2acdff18230..1bb427bd055 100644
--- a/src/plugins/qmldesigner/designmodewidget.cpp
+++ b/src/plugins/qmldesigner/designmodewidget.cpp
@@ -20,6 +20,7 @@
#include <coreplugin/actionmanager/command.h>
#include <coreplugin/modemanager.h>
#include <qmldesigner/qmldesignerconstants.h>
+#include <qmldesignerbase/qmldesignerbaseplugin.h>
#include <coreplugin/outputpane.h>
#include <coreplugin/modemanager.h>
@@ -39,6 +40,7 @@
#include <utils/stylehelper.h>
#include <QActionGroup>
+#include <QApplication>
#include <QBoxLayout>
#include <QComboBox>
#include <QDir>
@@ -92,6 +94,8 @@ DesignModeWidget::DesignModeWidget()
, m_crumbleBar(new CrumbleBar(this))
{
setAcceptDrops(true);
+ if (Utils::StyleHelper::isQDSTheme())
+ qApp->setStyle(QmlDesignerBasePlugin::style());
}
DesignModeWidget::~DesignModeWidget()
@@ -182,6 +186,7 @@ void DesignModeWidget::setup()
Core::ICore::resourcePath("qmldesigner/workspacePresets/").toString());
QString sheet = QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/dockwidgets.css"));
+ sheet += QString::fromUtf8(Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css"));
m_dockManager->setStyleSheet(Theme::replaceCssColors(sheet));
// Setup icons
@@ -216,14 +221,29 @@ void DesignModeWidget::setup()
mworkspaces->setOnAllDisabledBehavior(Core::ActionContainer::Show);
// Connect opening of the 'workspaces' menu with creation of the workspaces menu
connect(mworkspaces->menu(), &QMenu::aboutToShow, this, &DesignModeWidget::aboutToShowWorkspaces);
- // Disable workspace menu when context is different to C_DESIGN_MODE
- connect(Core::ICore::instance(), &Core::ICore::contextChanged,
- this, [mworkspaces](const Core::Context &context){
- if (context.contains(Core::Constants::C_DESIGN_MODE))
+
+ Core::ActionContainer *mpanes = Core::ActionManager::actionContainer(Core::Constants::M_VIEW_PANES);
+
+ // Initially disable menus
+ mviews->menu()->setEnabled(false);
+ mworkspaces->menu()->setEnabled(false);
+ mpanes->menu()->setEnabled(false);
+
+ // Enable/disable menus when mode is different to MODE_DESIGN
+ connect(Core::ModeManager::instance(),
+ &Core::ModeManager::currentModeChanged,
+ this,
+ [mviews, mworkspaces, mpanes](Utils::Id mode, Utils::Id) {
+ if (mode == Core::Constants::MODE_DESIGN) {
+ mviews->menu()->setEnabled(true);
mworkspaces->menu()->setEnabled(true);
- else
+ mpanes->menu()->setEnabled(true);
+ } else {
+ mviews->menu()->setEnabled(false);
mworkspaces->menu()->setEnabled(false);
- });
+ mpanes->menu()->setEnabled(false);
+ }
+ });
// Create a DockWidget for each QWidget and add them to the DockManager
const Core::Context designContext(Core::Constants::C_DESIGN_MODE);
@@ -231,60 +251,48 @@ void DesignModeWidget::setup()
// First get all navigation views
QList<Core::INavigationWidgetFactory *> factories = Core::INavigationWidgetFactory::allNavigationFactories();
-
- QList<Core::Command*> viewCommands;
+ QList<Core::Command *> viewCommands;
+ const QList<Utils::Id> navigationViewIds = {"Projects", "File System", "Open Documents"};
for (Core::INavigationWidgetFactory *factory : factories) {
- Core::NavigationView navigationView;
- navigationView.widget = nullptr;
- QString uniqueId;
- QString title;
+ Core::NavigationView navigationView = {nullptr, {}};
- if (factory->id() == "Projects") {
- navigationView = factory->createWidget();
- hideToolButtons(navigationView.dockToolBarWidgets);
- navigationView.widget->setWindowTitle(tr(factory->id().name()));
- uniqueId = "Projects";
- title = "Projects";
- }
- if (factory->id() == "File System") {
- navigationView = factory->createWidget();
- hideToolButtons(navigationView.dockToolBarWidgets);
- navigationView.widget->setWindowTitle(tr(factory->id().name()));
- uniqueId = "FileSystem";
- title = "File System";
- }
- if (factory->id() == "Open Documents") {
- navigationView = factory->createWidget();
- hideToolButtons(navigationView.dockToolBarWidgets);
- navigationView.widget->setWindowTitle(tr(factory->id().name()));
- uniqueId = "OpenDocuments";
- title = "Open Documents";
- }
+ if (!navigationViewIds.contains(factory->id()))
+ continue;
- if (navigationView.widget) {
- // Apply stylesheet to QWidget
- QByteArray sheet = Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css");
- sheet += Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css");
- sheet += "QLabel { background-color: creatorTheme.DSsectionHeadBackground; }";
- navigationView.widget->setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(sheet)));
-
- // Create DockWidget
- ADS::DockWidget *dockWidget = new ADS::DockWidget(uniqueId);
- dockWidget->setWidget(navigationView.widget);
- dockWidget->setWindowTitle(title);
- m_dockManager->addDockWidget(ADS::NoDockWidgetArea, dockWidget);
-
- // Set unique id as object name
- navigationView.widget->setObjectName(uniqueId);
-
- // Create menu action
- auto command = Core::ActionManager::registerAction(dockWidget->toggleViewAction(),
- actionToggle.withSuffix(uniqueId + "Widget"),
- designContext);
- command->setAttribute(Core::Command::CA_Hide);
- viewCommands.append(command);
- }
+ navigationView = factory->createWidget();
+
+ if (!navigationView.widget)
+ continue;
+
+ hideToolButtons(navigationView.dockToolBarWidgets);
+ navigationView.widget->setWindowTitle(tr(factory->id().name()));
+
+ QString idString = factory->id().toSetting().toString();
+ const QString title = idString;
+ const QString uniqueId = idString.remove(" "); // title without whitespaces
+
+ // Apply stylesheet to QWidget
+ QByteArray sheet = Utils::FileReader::fetchQrc(":/qmldesigner/stylesheet.css");
+ sheet += Utils::FileReader::fetchQrc(":/qmldesigner/scrollbar.css");
+ sheet += "QLabel { background-color: creatorTheme.DSsectionHeadBackground; }";
+ navigationView.widget->setStyleSheet(Theme::replaceCssColors(QString::fromUtf8(sheet)));
+
+ // Create DockWidget
+ ADS::DockWidget *dockWidget = new ADS::DockWidget(uniqueId);
+ dockWidget->setWidget(navigationView.widget);
+ dockWidget->setWindowTitle(title);
+ m_dockManager->addDockWidget(ADS::NoDockWidgetArea, dockWidget);
+
+ // Set unique id as object name
+ navigationView.widget->setObjectName(uniqueId);
+
+ // Create menu action
+ auto command = Core::ActionManager::registerAction(dockWidget->toggleViewAction(),
+ actionToggle.withSuffix(uniqueId + "Widget"),
+ designContext);
+ command->setAttribute(Core::Command::CA_Hide);
+ viewCommands.append(command);
}
// Afterwards get all the other widgets
@@ -303,7 +311,8 @@ void DesignModeWidget::setup()
// Create menu action
auto command = Core::ActionManager::registerAction(dockWidget->toggleViewAction(),
- actionToggle.withSuffix(widgetInfo.uniqueId + "Widget"),
+ actionToggle.withSuffix(
+ widgetInfo.uniqueId + "Widget"),
designContext);
command->setAttribute(Core::Command::CA_Hide);
viewCommands.append(command);
@@ -328,22 +337,13 @@ void DesignModeWidget::setup()
command->setAttribute(Core::Command::CA_Hide);
viewCommands.append(command);
- connect(command->action(), &QAction::triggered, this, [command]() {
- if (!command->action()->isChecked())
- return;
-
- auto cmd = Core::ActionManager::command("QtCreator.Pane.ApplicationOutput");
- QTC_ASSERT(cmd, return);
- cmd->action()->trigger();
- });
-
connect(outputPanePlaceholder,
&Core::OutputPanePlaceHolder::visibilityChangeRequested,
m_outputPaneDockWidget,
&ADS::DockWidget::toggleView);
}
- std::sort(viewCommands.begin(), viewCommands.end(), [](Core::Command *first, Core::Command *second){
+ std::sort(viewCommands.begin(), viewCommands.end(), [](Core::Command *first, Core::Command *second) {
return first->description() < second->description();
});
@@ -356,7 +356,10 @@ void DesignModeWidget::setup()
toolBar->addAction(viewManager().componentViewAction());
toolBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
- DesignerActionToolBar *designerToolBar = QmlDesignerPlugin::instance()->viewManager().designerActionManager().createToolBar(m_toolBar);
+ DesignerActionToolBar *designerToolBar = QmlDesignerPlugin::instance()
+ ->viewManager()
+ .designerActionManager()
+ .createToolBar(m_toolBar);
designerToolBar->layout()->addWidget(toolBar);
@@ -365,9 +368,14 @@ void DesignModeWidget::setup()
m_toolBar->setToolbarCreationFlags(Core::EditorToolBar::FlagsStandalone);
m_toolBar->setNavigationVisible(true);
- connect(m_toolBar, &Core::EditorToolBar::goForwardClicked, this, &DesignModeWidget::toolBarOnGoForwardClicked);
- connect(m_toolBar, &Core::EditorToolBar::goBackClicked, this, &DesignModeWidget::toolBarOnGoBackClicked);
-
+ connect(m_toolBar,
+ &Core::EditorToolBar::goForwardClicked,
+ this,
+ &DesignModeWidget::toolBarOnGoForwardClicked);
+ connect(m_toolBar,
+ &Core::EditorToolBar::goBackClicked,
+ this,
+ &DesignModeWidget::toolBarOnGoBackClicked);
QToolBar* toolBarWrapper = new QToolBar();
toolBarWrapper->addWidget(m_toolBar);
@@ -375,32 +383,8 @@ void DesignModeWidget::setup()
toolBarWrapper->setMovable(false);
addToolBar(Qt::TopToolBarArea, toolBarWrapper);
-
addSpacerToToolBar(toolBar);
- auto workspaceComboBox = new QComboBox();
- workspaceComboBox->setMinimumWidth(120);
- workspaceComboBox->setToolTip(tr("Switch the active workspace."));
- auto sortedWorkspaces = m_dockManager->workspaces();
- Utils::sort(sortedWorkspaces);
- workspaceComboBox->addItems(sortedWorkspaces);
- workspaceComboBox->setCurrentText(m_dockManager->activeWorkspace());
- toolBar->addWidget(workspaceComboBox);
-
- connect(m_dockManager, &ADS::DockManager::workspaceListChanged,
- workspaceComboBox, [this, workspaceComboBox]() {
- workspaceComboBox->clear();
- auto sortedWorkspaces = m_dockManager->workspaces();
- Utils::sort(sortedWorkspaces);
- workspaceComboBox->addItems(sortedWorkspaces);
- workspaceComboBox->setCurrentText(m_dockManager->activeWorkspace());
- });
- connect(m_dockManager, &ADS::DockManager::workspaceLoaded, workspaceComboBox, &QComboBox::setCurrentText);
- connect(workspaceComboBox, &QComboBox::activated,
- m_dockManager, [this, workspaceComboBox]([[maybe_unused]] int index) {
- m_dockManager->openWorkspace(workspaceComboBox->currentText());
- });
-
const QIcon gaIcon = Utils::StyleHelper::getIconFromIconFont(
fontName, Theme::getIconUnicode(Theme::Icon::annotationBubble),
36, 36, Theme::getColor(Theme::IconsBaseColor));
@@ -412,7 +396,6 @@ void DesignModeWidget::setup()
m_globalAnnotationEditor.showWidget();
}
});
-
}
if (currentDesignDocument())
@@ -444,8 +427,6 @@ void DesignModeWidget::setup()
}
});
-
-
viewManager().enableWidgets();
readSettings();
show();
@@ -453,15 +434,15 @@ void DesignModeWidget::setup()
void DesignModeWidget::aboutToShowWorkspaces()
{
- Core::ActionContainer *aci = Core::ActionManager::actionContainer(QmlDesigner::Constants::M_VIEW_WORKSPACES);
+ Core::ActionContainer *aci = Core::ActionManager::actionContainer(
+ QmlDesigner::Constants::M_VIEW_WORKSPACES);
QMenu *menu = aci->menu();
menu->clear();
auto *ag = new QActionGroup(menu);
connect(ag, &QActionGroup::triggered, this, [this](QAction *action) {
- QString workspace = action->data().toString();
- m_dockManager->openWorkspace(workspace);
+ m_dockManager->openWorkspace(action->data().toString());
});
QAction *action = menu->addAction(tr("Manage..."));
@@ -469,21 +450,18 @@ void DesignModeWidget::aboutToShowWorkspaces()
QAction *resetWorkspace = menu->addAction(tr("Reset Active"));
connect(resetWorkspace, &QAction::triggered, this, [this]() {
- if (m_dockManager->resetWorkspacePreset(m_dockManager->activeWorkspace()))
+ if (m_dockManager->resetWorkspacePreset(m_dockManager->activeWorkspace()->fileName()))
m_dockManager->reloadActiveWorkspace();
});
menu->addSeparator();
- // Sort the list of workspaces
- auto sortedWorkspaces = m_dockManager->workspaces();
- Utils::sort(sortedWorkspaces);
-
- for (const auto &workspace : std::as_const(sortedWorkspaces)) {
- QAction *action = ag->addAction(workspace);
- action->setData(workspace);
+ auto workspaces = m_dockManager->workspaces();
+ for (const auto &workspace : std::as_const(workspaces)) {
+ QAction *action = ag->addAction(workspace.name());
+ action->setData(workspace.fileName());
action->setCheckable(true);
- if (workspace == m_dockManager->activeWorkspace())
+ if (workspace == *m_dockManager->activeWorkspace())
action->setChecked(true);
}
menu->addActions(ag->actions());
diff --git a/src/plugins/qmldesigner/puppetenvironmentbuilder.cpp b/src/plugins/qmldesigner/puppetenvironmentbuilder.cpp
index 7d7957753c4..079cc0a326b 100644
--- a/src/plugins/qmldesigner/puppetenvironmentbuilder.cpp
+++ b/src/plugins/qmldesigner/puppetenvironmentbuilder.cpp
@@ -51,6 +51,7 @@ QProcessEnvironment PuppetEnvironmentBuilder::processEnvironment() const
addMultiLanguageDatatbase();
addImportPaths();
addCustomFileSelectors();
+ addDisableDeferredProperties();
qCInfo(puppetEnvirmentBuild) << "Puppet environment:" << m_environment.toStringList();
@@ -228,6 +229,11 @@ void PuppetEnvironmentBuilder::addCustomFileSelectors() const
qCInfo(puppetEnvirmentBuild) << "Puppet selectors:" << customFileSelectors;
}
+void PuppetEnvironmentBuilder::addDisableDeferredProperties() const
+{
+ m_environment.set("QML_DISABLE_INTERNAL_DEFERRED_PROPERTIES", "true");
+}
+
PuppetType PuppetEnvironmentBuilder::determinePuppetType() const
{
if (m_target && m_target->kit() && m_target->kit()->isValid()) {
diff --git a/src/plugins/qmldesigner/puppetenvironmentbuilder.h b/src/plugins/qmldesigner/puppetenvironmentbuilder.h
index e3ef33a7211..3c2ffba271e 100644
--- a/src/plugins/qmldesigner/puppetenvironmentbuilder.h
+++ b/src/plugins/qmldesigner/puppetenvironmentbuilder.h
@@ -49,6 +49,7 @@ private:
void addMultiLanguageDatatbase() const;
void addImportPaths() const;
void addCustomFileSelectors() const;
+ void addDisableDeferredProperties() const;
private:
ProjectExplorer::Target *m_target = nullptr;
diff --git a/src/plugins/qmldesigner/qmldesignerconstants.h b/src/plugins/qmldesigner/qmldesignerconstants.h
index 18039187509..d38dad74c7e 100644
--- a/src/plugins/qmldesigner/qmldesignerconstants.h
+++ b/src/plugins/qmldesigner/qmldesignerconstants.h
@@ -30,6 +30,7 @@ const char TOGGLE_RIGHT_SIDEBAR[] = "QmlDesigner.ToggleRightSideBar";
const char TOGGLE_STATES_EDITOR[] = "QmlDesigner.ToggleStatesEditor";
const char GO_INTO_COMPONENT[] = "QmlDesigner.GoIntoComponent";
const char EXPORT_AS_IMAGE[] = "QmlDesigner.ExportAsImage";
+const char TAKE_SCREENSHOT[] = "QmlDesigner.TakeScreenshot";
const char FORMEDITOR_REFRESH[] = "QmlDesigner.FormEditor.Refresh";
const char FORMEDITOR_SNAPPING[] = "QmlDesigner.FormEditor.Snapping";
const char FORMEDITOR_NO_SNAPPING[] = "QmlDesigner.FormEditor.NoSnapping";
@@ -61,7 +62,7 @@ const char EDIT3D_PARTICLES_SEEKER[] = "QmlDesigner.Editor3D.ParticlesSeeker"
const char EDIT3D_PARTICLES_RESTART[] = "QmlDesigner.Editor3D.ParticlesRestart";
const char EDIT3D_VISIBILITY_TOGGLES[] = "QmlDesigner.Editor3D.VisibilityToggles";
const char EDIT3D_BACKGROUND_COLOR_ACTIONS[] = "QmlDesigner.Editor3D.BackgroundColorActions";
-
+const char EDIT3D_BAKE_LIGHTS[] = "QmlDesigner.Editor3D.BakeLights";
const char QML_DESIGNER_SUBFOLDER[] = "/designer/";
const char COMPONENT_BUNDLES_FOLDER[] = "/ComponentBundles";
diff --git a/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp b/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp
index 8282ea419a4..1bd58991657 100644
--- a/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp
+++ b/src/plugins/qmldesigner/qmldesignerexternaldependencies.cpp
@@ -15,6 +15,7 @@
#include <qmlpuppetpaths.h>
#include <qtsupport/baseqtversion.h>
#include <qtsupport/qtkitinformation.h>
+#include <qmlprojectmanager/buildsystem/qmlbuildsystem.h>
#include <coreplugin/icore.h>
@@ -186,4 +187,95 @@ Utils::FilePath ExternalDependencies::qmlPuppetPath() const
return puppetPath;
}
+namespace {
+
+QString qmlPath(ProjectExplorer::Target *target)
+{
+ auto kit = target->kit();
+
+ if (!kit)
+ return {};
+
+ auto qtVersion = QtSupport::QtKitAspect::qtVersion(kit);
+ if (!qtVersion)
+ return {};
+
+ return qtVersion->qmlPath().toString();
+}
+
+std::tuple<ProjectExplorer::Project *, ProjectExplorer::Target *, QmlProjectManager::QmlBuildSystem *>
+activeProjectEntries()
+{
+ auto project = ProjectExplorer::ProjectManager::startupProject();
+
+ if (!project)
+ return {};
+
+ auto target = project->activeTarget();
+
+ if (!target)
+ return {};
+
+ const auto qmlBuildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>(
+ target->buildSystem());
+
+ if (qmlBuildSystem)
+ return std::make_tuple(project, target, qmlBuildSystem);
+
+ return {};
+}
+} // namespace
+
+QStringList ExternalDependencies::modulePaths() const
+{
+ auto [project, target, qmlBuildSystem] = activeProjectEntries();
+
+ if (project && target && qmlBuildSystem) {
+ QStringList modulePaths;
+
+ if (auto path = qmlPath(target); !path.isEmpty())
+ modulePaths.push_back(path);
+
+ for (const QString &modulePath : qmlBuildSystem->customImportPaths())
+ modulePaths.append(project->projectDirectory().pathAppended(modulePath).toString());
+
+ return modulePaths;
+ }
+
+ return {};
+}
+
+QStringList ExternalDependencies::projectModulePaths() const
+{
+ auto [project, target, qmlBuildSystem] = activeProjectEntries();
+
+ if (project && target && qmlBuildSystem) {
+ QStringList modulePaths;
+
+ for (const QString &modulePath : qmlBuildSystem->customImportPaths())
+ modulePaths.append(project->projectDirectory().pathAppended(modulePath).toString());
+ }
+
+ return {};
+}
+
+bool ExternalDependencies::isQt6Project() const
+{
+ auto [project, target, qmlBuildSystem] = activeProjectEntries();
+
+ return qmlBuildSystem && qmlBuildSystem->qt6Project();
+}
+
+QString ExternalDependencies::qtQuickVersion() const
+{
+ auto [project, target, qmlBuildSystem] = activeProjectEntries();
+
+ return qmlBuildSystem ? qmlBuildSystem->versionQtQuick() : QString{};
+}
+
+Utils::FilePath ExternalDependencies::resourcePath(const QString &relativePath) const
+{
+ return Core::ICore::resourcePath(relativePath);
+}
+
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/qmldesignerexternaldependencies.h b/src/plugins/qmldesigner/qmldesignerexternaldependencies.h
index 3e57847ce9d..0f6acf2c106 100644
--- a/src/plugins/qmldesigner/qmldesignerexternaldependencies.h
+++ b/src/plugins/qmldesigner/qmldesignerexternaldependencies.h
@@ -36,6 +36,11 @@ public:
PuppetStartData puppetStartData(const class Model &model) const override;
bool instantQmlTextUpdate() const override;
Utils::FilePath qmlPuppetPath() const override;
+ QStringList modulePaths() const override;
+ QStringList projectModulePaths() const override;
+ bool isQt6Project() const override;
+ QString qtQuickVersion() const override;
+ Utils::FilePath resourcePath(const QString &relativePath) const override;
private:
const DesignerSettings &m_designerSettings;
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp
index 039528475a5..a25bbb832b8 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.cpp
+++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp
@@ -31,7 +31,6 @@
#include <texttool/texttool.h>
#include <timelineeditor/timelineview.h>
#include <transitioneditor/transitioneditorview.h>
-
#include <qmljseditor/qmljseditor.h>
#include <qmljseditor/qmljseditorconstants.h>
#include <qmljseditor/qmljseditordocument.h>
@@ -66,6 +65,7 @@
#include <utils/algorithm.h>
#include <utils/hostosinfo.h>
#include <utils/qtcassert.h>
+#include <utils/uniqueobjectptr.h>
#include <QAction>
#include <QApplication>
@@ -144,6 +144,8 @@ public:
DesignModeWidget mainWidget;
QtQuickDesignerFactory m_qtQuickDesignerFactory;
bool blockEditorChange = false;
+ Utils::UniqueObjectPtr<QToolBar> toolBar;
+ Utils::UniqueObjectPtr<QWidget> statusBar;
};
QmlDesignerPlugin *QmlDesignerPlugin::m_instance = nullptr;
@@ -184,8 +186,9 @@ static bool isDesignerMode(Utils::Id mode)
static bool documentIsAlreadyOpen(DesignDocument *designDocument, Core::IEditor *editor, Utils::Id newMode)
{
return designDocument
- && editor == designDocument->editor()
- && isDesignerMode(newMode);
+ && editor == designDocument->editor()
+ && isDesignerMode(newMode)
+ && designDocument->fileName() == editor->document()->filePath();
}
static bool shouldAssertInException()
@@ -241,7 +244,7 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e
->addAction(cmd, Core::Constants::G_HELP_SUPPORT);
connect(action, &QAction::triggered, this, [this] {
- lauchFeedbackPopup(Core::Constants::IDE_DISPLAY_NAME);
+ lauchFeedbackPopupInternal(Core::Constants::IDE_DISPLAY_NAME);
});
if (!Utils::HostOsInfo::canCreateOpenGLContext(errorMessage))
@@ -273,8 +276,8 @@ bool QmlDesignerPlugin::initialize(const QStringList & /*arguments*/, QString *e
});
if (QmlProjectManager::QmlProject::isQtDesignStudio()) {
- ToolBar::create();
- ToolBar::createStatusBar();
+ d->toolBar = ToolBar::create();
+ d->statusBar = ToolBar::createStatusBar();
}
return true;
@@ -289,10 +292,10 @@ bool QmlDesignerPlugin::delayedInitialize()
Utils::transform(ExtensionSystem::PluginManager::pluginPaths(), [postfix](const QString &p) {
return QString(p + postfix);
});
- MetaInfo::setPluginPaths(pluginPaths);
- d->viewManager.registerView(
- std::make_unique<ConnectionView>(d->externalDependencies));
+ MetaInfo::initializeGlobal(pluginPaths, d->externalDependencies);
+
+ d->viewManager.registerView(std::make_unique<ConnectionView>(d->externalDependencies));
auto timelineView = d->viewManager.registerView(
std::make_unique<TimelineView>(d->externalDependencies));
@@ -334,8 +337,6 @@ bool QmlDesignerPlugin::delayedInitialize()
Core::ICore::appendAboutInformation(tr("Licensee: %1").arg(licensee()));
}
- MetaInfo::global();
-
return true;
}
@@ -438,14 +439,12 @@ void QmlDesignerPlugin::integrateIntoQtCreator(QWidget *modeWidget)
&Core::ModeManager::currentModeChanged,
[this](Utils::Id newMode, Utils::Id oldMode) {
Core::IEditor *currentEditor = Core::EditorManager::currentEditor();
- if (d && currentEditor && checkIfEditorIsQtQuick(currentEditor)
+ if (isDesignerMode(newMode) && checkIfEditorIsQtQuick(currentEditor)
&& !documentIsAlreadyOpen(currentDesignDocument(), currentEditor, newMode)) {
- if (isDesignerMode(newMode)) {
- showDesigner();
- } else if (currentDesignDocument()
- || (!isDesignerMode(newMode) && isDesignerMode(oldMode))) {
- hideDesigner();
- }
+ showDesigner();
+ } else if (currentDesignDocument()
+ || (!isDesignerMode(newMode) && isDesignerMode(oldMode))) {
+ hideDesigner();
}
});
}
@@ -731,6 +730,18 @@ void QmlDesignerPlugin::trackWidgetFocusTime(QWidget *widget, const QString &ide
void QmlDesignerPlugin::lauchFeedbackPopup(const QString &identifier)
{
+ if (Core::ModeManager::currentModeId() == Core::Constants::MODE_DESIGN)
+ lauchFeedbackPopupInternal(identifier);
+}
+
+void QmlDesignerPlugin::handleFeedback(const QString &feedback, int rating)
+{
+ const QString identifier = sender()->property("identifier").toString();
+ emit usageStatisticsInsertFeedback(identifier, feedback, rating);
+}
+
+void QmlDesignerPlugin::lauchFeedbackPopupInternal(const QString &identifier)
+{
m_feedbackWidget = new QQuickWidget(Core::ICore::dialogParent());
m_feedbackWidget->setObjectName(Constants::OBJECT_NAME_TOP_FEEDBACK);
@@ -767,12 +778,6 @@ void QmlDesignerPlugin::lauchFeedbackPopup(const QString &identifier)
m_feedbackWidget->show();
}
-void QmlDesignerPlugin::handleFeedback(const QString &feedback, int rating)
-{
- const QString identifier = sender()->property("identifier").toString();
- emit usageStatisticsInsertFeedback(identifier, feedback, rating);
-}
-
void QmlDesignerPlugin::closeFeedbackPopup()
{
if (m_feedbackWidget) {
diff --git a/src/plugins/qmldesigner/qmldesignerplugin.h b/src/plugins/qmldesigner/qmldesignerplugin.h
index 78bf02ac042..ee078b273ab 100644
--- a/src/plugins/qmldesigner/qmldesignerplugin.h
+++ b/src/plugins/qmldesigner/qmldesignerplugin.h
@@ -95,6 +95,7 @@ private slots:
void handleFeedback(const QString &feedback, int rating);
private: // functions
+ void lauchFeedbackPopupInternal(const QString &identifier);
void integrateIntoQtCreator(QWidget *modeWidget);
void showDesigner();
void hideDesigner();
@@ -114,7 +115,6 @@ private: // variables
QmlDesignerPluginPrivate *d = nullptr;
static QmlDesignerPlugin *m_instance;
QElapsedTimer m_usageTimer;
- StudioConfigSettingsPage m_settingsPage;
};
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp
index a80b3148b36..4d327b5491d 100644
--- a/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp
+++ b/src/plugins/qmldesigner/qmldesignerprojectmanager.cpp
@@ -39,6 +39,7 @@
#include <coreplugin/icore.h>
+#include <QDirIterator>
#include <QFileSystemWatcher>
#include <QQmlEngine>
@@ -175,24 +176,27 @@ class ProjectStorageData
public:
ProjectStorageData(::ProjectExplorer::Project *project)
: database{project->projectDirectory().pathAppended("projectstorage.db").toString()}
+ , projectPartId{ProjectPartId::create(
+ pathCache.sourceId(SourcePath{project->projectDirectory().toString() + "/."}).internalId())}
{}
-
Sqlite::Database database;
ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()};
ProjectStorageUpdater::PathCache pathCache{storage};
FileSystem fileSystem{pathCache};
FileStatusCache fileStatusCache{fileSystem};
QmlDocumentParser qmlDocumentParser{storage, pathCache};
- QmlTypesParser qmlTypesParser{pathCache, storage};
+ QmlTypesParser qmlTypesParser{storage};
ProjectStoragePathWatcher<QFileSystemWatcher, QTimer, ProjectStorageUpdater::PathCache>
pathWatcher{pathCache, fileSystem, &updater};
+ ProjectPartId projectPartId;
ProjectStorageUpdater updater{fileSystem,
storage,
fileStatusCache,
pathCache,
qmlDocumentParser,
qmlTypesParser,
- pathWatcher};
+ pathWatcher,
+ projectPartId};
};
std::unique_ptr<ProjectStorageData> createProjectStorageData(::ProjectExplorer::Project *project)
@@ -339,18 +343,25 @@ void projectQmldirPaths(::ProjectExplorer::Target *target, QStringList &qmldirPa
qmldirPaths.push_back(QDir::cleanPath(pojectDirectory.absoluteFilePath(importPath))
+ "/qmldir");
}
-#ifdef QDS_HAS_QMLDOM
-bool skipPath(const std::filesystem::path &path)
+
+#ifdef QDS_HAS_QMLPRIVATE
+QStringView currentDirectoryName(const QString &path)
{
- auto directory = path.filename();
- qDebug() << path.string().data();
+ auto found = std::find(path.rbegin(), path.rend(), u'/');
- bool skip = directory == "QtApplicationManager" || directory == "QtInterfaceFramework"
- || directory == "QtOpcUa" || directory == "Qt3D" || directory == "Qt3D"
- || directory == "Scene2D" || directory == "Scene3D" || directory == "QtWayland"
- || directory == "Qt5Compat";
- if (skip)
- qDebug() << "skip" << path.string().data();
+ if (found == path.rend())
+ return {};
+
+ return QStringView{found.base(), path.end()};
+}
+bool skipPath(const QString &path)
+{
+ auto directory = currentDirectoryName(path);
+
+ bool skip = directory == u"QtApplicationManager" || directory == u"QtInterfaceFramework"
+ || directory == u"QtOpcUa" || directory == u"Qt3D" || directory == u"Qt3D"
+ || directory == u"Scene2D" || directory == u"Scene3D" || directory == u"QtWayland"
+ || directory == u"Qt5Compat";
return skip;
}
@@ -359,22 +370,17 @@ bool skipPath(const std::filesystem::path &path)
void qtQmldirPaths([[maybe_unused]] ::ProjectExplorer::Target *target,
[[maybe_unused]] QStringList &qmldirPaths)
{
-#ifdef QDS_HAS_QMLDOM
- const QString installDirectory = qmlPath(target).toString();
+#ifdef QDS_HAS_QMLPRIVATE
+ if (useProjectStorage()) {
+ const QString installDirectory = qmlPath(target).toString();
+ QDirIterator dirIterator{installDirectory, QDir::Dirs, QDirIterator::Subdirectories};
- const std::filesystem::path installDirectoryPath{installDirectory.toStdString()};
+ while (dirIterator.hasNext()) {
+ auto directoryPath = dirIterator.next();
- auto current = std::filesystem::recursive_directory_iterator{installDirectoryPath};
- auto end = std::filesystem::end(current);
- for (; current != end; ++current) {
- const auto &entry = *current;
- auto path = entry.path();
- if (current.depth() < 3 && !current->is_regular_file() && skipPath(path)) {
- current.disable_recursion_pending();
- continue;
- }
- if (path.filename() == "qmldir") {
- qmldirPaths.push_back(QString::fromStdU16String(path.generic_u16string()));
+ QString qmldirPath = directoryPath + "/qmldir";
+ if (!skipPath(directoryPath) && QFileInfo::exists(qmldirPath))
+ qmldirPaths.push_back(directoryPath);
}
}
#endif
diff --git a/src/plugins/qmldesigner/qtquickplugin/quick.metainfo b/src/plugins/qmldesigner/qtquickplugin/quick.metainfo
index 45e01621280..f1aeaa9ebbd 100644
--- a/src/plugins/qmldesigner/qtquickplugin/quick.metainfo
+++ b/src/plugins/qmldesigner/qtquickplugin/quick.metainfo
@@ -571,6 +571,7 @@ MetaInfo {
requiredImport: "QtQuick3D"
QmlSource { source: ":/qtquickplugin/source/component3d.qml" }
+ toolTip: qsTr("Allows you to define 3D components inline, within a QML document.")
}
}
diff --git a/src/plugins/qmldesigner/settingspage.cpp b/src/plugins/qmldesigner/settingspage.cpp
index 873811ee28b..8c3222d72c3 100644
--- a/src/plugins/qmldesigner/settingspage.cpp
+++ b/src/plugins/qmldesigner/settingspage.cpp
@@ -41,7 +41,7 @@ namespace Internal {
static QStringList puppetModes()
{
- static QStringList puppetModeList{"", "all", "editormode", "rendermode", "previewmode"};
+ static QStringList puppetModeList{"", "all", "editormode", "rendermode", "previewmode", "bakelightsmode"};
return puppetModeList;
}
diff --git a/src/plugins/qmldesigner/shortcutmanager.cpp b/src/plugins/qmldesigner/shortcutmanager.cpp
index efb3bf49eee..87a873339df 100644
--- a/src/plugins/qmldesigner/shortcutmanager.cpp
+++ b/src/plugins/qmldesigner/shortcutmanager.cpp
@@ -14,11 +14,12 @@
#include <coreplugin/actionmanager/actionmanager.h>
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/command.h>
-#include <coreplugin/icore.h>
-#include <coreplugin/idocument.h>
#include <coreplugin/editormanager/documentmodel.h>
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/coreconstants.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/idocument.h>
+#include <coreplugin/modemanager.h>
#include <qmljseditor/qmljseditorconstants.h>
#include <qmlprojectmanager/qmlprojectmanagerconstants.h>
@@ -39,21 +40,24 @@
#include <QApplication>
#include <QClipboard>
+#include <QMainWindow>
+#include <QStandardPaths>
namespace QmlDesigner {
ShortCutManager::ShortCutManager()
- : QObject(),
- m_exportAsImageAction(tr("Export as &Image...")),
- m_undoAction(tr("&Undo")),
- m_redoAction(tr("&Redo")),
- m_deleteAction(tr("Delete")),
- m_cutAction(tr("Cu&t")),
- m_copyAction(tr("&Copy")),
- m_pasteAction(tr("&Paste")),
- m_duplicateAction(tr("&Duplicate")),
- m_selectAllAction(tr("Select &All")),
- m_escapeAction(this)
+ : QObject()
+ , m_exportAsImageAction(tr("Export as &Image..."))
+ , m_takeScreenshotAction(tr("Take Screenshot"))
+ , m_undoAction(tr("&Undo"))
+ , m_redoAction(tr("&Redo"))
+ , m_deleteAction(tr("Delete"))
+ , m_cutAction(tr("Cu&t"))
+ , m_copyAction(tr("&Copy"))
+ , m_pasteAction(tr("&Paste"))
+ , m_duplicateAction(tr("&Duplicate"))
+ , m_selectAllAction(tr("Select &All"))
+ , m_escapeAction(this)
{
}
@@ -106,12 +110,33 @@ void ShortCutManager::registerActions(const Core::Context &qmlDesignerMainContex
QmlDesignerPlugin::instance()->viewManager().exportAsImage();
});
+ // Edit Global Annotations
QAction *action = new QAction(tr("Edit Global Annotations..."), this);
command = Core::ActionManager::registerAction(action, "Edit.Annotations", qmlDesignerMainContext);
Core::ActionManager::actionContainer(Core::Constants::M_EDIT)
->addAction(command, Core::Constants::G_EDIT_OTHER);
-
connect(action, &QAction::triggered, this, [] { ToolBarBackend::launchGlobalAnnotations(); });
+ connect(Core::ModeManager::instance(), &Core::ModeManager::currentModeChanged, this, [action] {
+ action->setEnabled(Core::ModeManager::currentModeId() == Core::Constants::MODE_DESIGN);
+ });
+ action->setEnabled(false);
+
+ command = Core::ActionManager::registerAction(&m_takeScreenshotAction,
+ QmlDesigner::Constants::TAKE_SCREENSHOT);
+ connect(&m_takeScreenshotAction, &QAction::triggered, [] {
+ const auto folder = Utils::FilePath::fromString(
+ QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation))
+ .pathAppended("QtDesignStudio/screenshots/");
+ folder.createDir();
+
+ const auto file = folder.pathAppended(QDateTime::currentDateTime().toString("dddd-hh-mm-ss")
+ + ".png");
+
+ QPixmap pixmap = Core::ICore::mainWindow()->grab();
+
+ const bool b = pixmap.save(file.toString(), "PNG");
+ qWarning() << "screenshot" << file << b << pixmap;
+ });
Core::ActionContainer *exportMenu = Core::ActionManager::actionContainer(
QmlProjectManager::Constants::EXPORT_MENU);
diff --git a/src/plugins/qmldesigner/shortcutmanager.h b/src/plugins/qmldesigner/shortcutmanager.h
index 9b4762748ef..b97fd834ee7 100644
--- a/src/plugins/qmldesigner/shortcutmanager.h
+++ b/src/plugins/qmldesigner/shortcutmanager.h
@@ -52,6 +52,7 @@ private:
QAction m_saveAction;
QAction m_saveAsAction;
QAction m_exportAsImageAction;
+ QAction m_takeScreenshotAction;
QAction m_closeCurrentEditorAction;
QAction m_closeAllEditorsAction;
QAction m_closeOtherEditorsAction;
diff --git a/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo b/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo
index 94f14c296dd..2998ea2f67b 100644
--- a/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo
+++ b/src/plugins/qmldesigner/studioplugin/studioplugin.metainfo
@@ -34,7 +34,16 @@ MetaInfo {
"QtQuick.Templates",
"QtQuick.Shapes",
"QtQuick.Studio.EventSystem",
- "QtQuick.Studio.EventSimulator"
+ "QtQuick.Studio.EventSimulator",
+ "QtQuick.Pdf",
+ "QmlTime",
+ "Qt.test.controls",
+ "QtOpcUa",
+ "QtVncServer",
+ "QtTextToSpeech",
+ "QtQuick3D MaterialEditor",
+ "QtDataVisualization",
+ "QtQuick3D.ParticleEffects"
]
showTagsForImports: [
diff --git a/src/plugins/qmldesigner/utils/filedownloader.cpp b/src/plugins/qmldesigner/utils/filedownloader.cpp
index b5c735d87a8..7825be5081b 100644
--- a/src/plugins/qmldesigner/utils/filedownloader.cpp
+++ b/src/plugins/qmldesigner/utils/filedownloader.cpp
@@ -253,23 +253,23 @@ void FileDownloader::doProbeUrl()
m_available = true;
emit availableChanged();
+
+ reply->deleteLater();
});
QNetworkReply::connect(reply,
&QNetworkReply::errorOccurred,
this,
- [this](QNetworkReply::NetworkError) {
- QQmlData *data = QQmlData::get(this, false);
- if (!data) {
- qDebug() << Q_FUNC_INFO << "FileDownloader is nullptr.";
- return;
- }
+ [this](QNetworkReply::NetworkError code) {
if (QQmlData::wasDeleted(this)) {
qDebug() << Q_FUNC_INFO << "FileDownloader was deleted.";
return;
}
+ qDebug() << Q_FUNC_INFO << "Network error:" << code
+ << qobject_cast<QNetworkReply *>(sender())->errorString();
+
m_available = false;
emit availableChanged();
});
diff --git a/src/plugins/qmldesigner/utils/fileextractor.cpp b/src/plugins/qmldesigner/utils/fileextractor.cpp
index c6aa83fb7ae..7c32381b69c 100644
--- a/src/plugins/qmldesigner/utils/fileextractor.cpp
+++ b/src/plugins/qmldesigner/utils/fileextractor.cpp
@@ -51,7 +51,11 @@ FileExtractor::FileExtractor(QObject *parent)
// We can not get the uncompressed size of the archive yet, that is why we use an
// approximation. We assume a 50% compression rate.
- int progress = std::min(100ll, currentSize * 100 / m_compressedSize * 2);
+
+ int progress = 0;
+ if (m_compressedSize > 0)
+ progress = std::min(100ll, currentSize * 100 / m_compressedSize * 2);
+
if (progress >= 0) {
m_progress = progress;
emit progressChanged();
@@ -212,6 +216,8 @@ void FileExtractor::extract()
m_timer.start();
m_bytesBefore = QStorageInfo(m_targetPath.toFileInfo().dir()).bytesAvailable();
m_compressedSize = QFileInfo(m_sourceFile.toString()).size();
+ if (m_compressedSize <= 0)
+ qWarning() << "Compressed size for file '" << m_sourceFile << "' is zero or invalid: " << m_compressedSize;
QObject::connect(archive, &Utils::Archive::outputReceived, this, [this](const QString &output) {
m_detailedText += output;
diff --git a/src/plugins/qmldesigner/utils/multifiledownloader.cpp b/src/plugins/qmldesigner/utils/multifiledownloader.cpp
index c36476f05d6..6a8ac9761e9 100644
--- a/src/plugins/qmldesigner/utils/multifiledownloader.cpp
+++ b/src/plugins/qmldesigner/utils/multifiledownloader.cpp
@@ -23,7 +23,10 @@ void MultiFileDownloader::setDownloader(FileDownloader *downloader)
});
QObject::connect(m_downloader, &FileDownloader::progressChanged, this, [this]() {
- m_progress = (m_nextFile + m_downloader->progress()) / m_files.count();
+ double curProgress = m_downloader->progress() / 100.0;
+ double totalProgress = (m_nextFile + curProgress) / m_files.count();
+ m_progress = totalProgress * 100;
+ emit progressChanged();
});
QObject::connect(m_downloader, &FileDownloader::downloadFailed, this, [this]() {
@@ -48,6 +51,7 @@ FileDownloader *MultiFileDownloader::downloader()
void MultiFileDownloader::start()
{
+ m_canceled = false;
emit downloadStarting();
}
diff --git a/src/plugins/qmldesignerbase/CMakeLists.txt b/src/plugins/qmldesignerbase/CMakeLists.txt
index f03498f28d9..628403874c0 100644
--- a/src/plugins/qmldesignerbase/CMakeLists.txt
+++ b/src/plugins/qmldesignerbase/CMakeLists.txt
@@ -1,5 +1,9 @@
+env_with_default("QDS_DISABLE_COMPILE_WARNING_AS_ERROR" ENV_QDS_DISABLE_COMPILE_WARNING_AS_ERROR OFF)
+option(DISABLE_COMPILE_WARNING_AS_ERROR "Dont treat warnings as errors" ${ENV_QDS_DISABLE_COMPILE_WARNING_AS_ERROR})
+add_feature_info("Treat warnings as errors" ${DISABLE_COMPILE_WARNING_AS_ERROR} "")
+
add_qtc_plugin(QmlDesignerBase
- PROPERTIES COMPILE_WARNING_AS_ERROR ON
+ CONDITION TARGET Qt::QuickWidgets
DEPENDS Qt::Core Qt::QuickWidgets
PLUGIN_DEPENDS Core ProjectExplorer QtSupport
SOURCES
@@ -8,10 +12,24 @@ add_qtc_plugin(QmlDesignerBase
)
extend_qtc_plugin(QmlDesignerBase
+ CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR
+ PROPERTIES COMPILE_WARNING_AS_ERROR ON
+)
+
+extend_qtc_plugin(QmlDesignerBase
PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/utils
SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/utils
SOURCES
+ designerpaths.cpp designerpaths.h
designersettings.cpp designersettings.h
qmlpuppetpaths.cpp qmlpuppetpaths.h
+)
+
+extend_qtc_plugin(QmlDesignerBase
+ PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/studio
+ SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/studio
+ SOURCES
+ studiostyle.cpp studiostyle.h
studioquickwidget.cpp studioquickwidget.h
+ studiosettingspage.cpp studiosettingspage.h
)
diff --git a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp
index 0a9ef8483a1..c9af4f22836 100644
--- a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp
+++ b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.cpp
@@ -3,33 +3,29 @@
#include "qmldesignerbaseplugin.h"
+#include "studiosettingspage.h"
+
+#include "studio/studiostyle.h"
#include "utils/designersettings.h"
-#include <coreplugin/coreconstants.h>
-#include <coreplugin/dialogs/restartdialog.h>
#include <coreplugin/icore.h>
-#include <projectexplorer/projectexplorer.h>
-#include <projectexplorer/projectexplorerconstants.h>
-#include <utils/hostosinfo.h>
+#include <utils/uniqueobjectptr.h>
-#include <QCheckBox>
-#include <QGroupBox>
-#include <QHBoxLayout>
-#include <QLabel>
-#include <QPushButton>
-#include <QSpacerItem>
-#include <QStandardPaths>
-#include <QVBoxLayout>
+#include <QApplication>
namespace QmlDesigner {
-const char EXAMPLES_DOWNLOAD_PATH[] = "StudioConfig/ExamplesDownloadPath";
-const char BUNDLES_DOWNLOAD_PATH[] = "StudioConfig/BundlesDownloadPath";
class QmlDesignerBasePlugin::Data
{
public:
- DesignerSettings settings{Core::ICore::instance()->settings()};
+ DesignerSettings settings;
+ StudioStyle *style = nullptr;
+ StudioConfigSettingsPage studioConfigSettingsPage;
+
+ Data()
+ : settings(Core::ICore::settings())
+ {}
};
namespace {
@@ -41,12 +37,6 @@ QmlDesignerBasePlugin::QmlDesignerBasePlugin()
global = this;
};
-QmlDesignerBasePlugin *QmlDesignerBasePlugin::instance()
-{
- return global;
-};
-
-
QmlDesignerBasePlugin::~QmlDesignerBasePlugin() = default;
DesignerSettings &QmlDesignerBasePlugin::settings()
@@ -54,219 +44,24 @@ DesignerSettings &QmlDesignerBasePlugin::settings()
return global->d->settings;
}
-bool QmlDesignerBasePlugin::initialize(const QStringList &, QString *)
-{
- d = std::make_unique<Data>();
-
- return true;
-}
-
-Utils::FilePath QmlDesignerBasePlugin::defaultExamplesPath()
-{
- QStandardPaths::StandardLocation location = Utils::HostOsInfo::isMacHost()
- ? QStandardPaths::HomeLocation
- : QStandardPaths::DocumentsLocation;
-
- return Utils::FilePath::fromString(QStandardPaths::writableLocation(location))
- .pathAppended("QtDesignStudio/examples");
-}
-
-Utils::FilePath QmlDesignerBasePlugin::defaultBundlesPath()
-{
- QStandardPaths::StandardLocation location = Utils::HostOsInfo::isMacHost()
- ? QStandardPaths::HomeLocation
- : QStandardPaths::DocumentsLocation;
-
- return Utils::FilePath::fromString(QStandardPaths::writableLocation(location))
- .pathAppended("QtDesignStudio/bundles");
-}
-
-QString QmlDesignerBasePlugin::examplesPathSetting()
-{
- return Core::ICore::settings()
- ->value(EXAMPLES_DOWNLOAD_PATH, defaultExamplesPath().toString())
- .toString();
-}
-
-QString QmlDesignerBasePlugin::bundlesPathSetting()
-{
- return Core::ICore::settings()
- ->value(BUNDLES_DOWNLOAD_PATH, defaultBundlesPath().toString())
- .toString();
-}
-
-static bool hideBuildMenuSetting()
-{
- return Core::ICore::settings()
- ->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_BUILD, false)
- .toBool();
-}
-
-static bool hideDebugMenuSetting()
-{
- return Core::ICore::settings()
- ->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_DEBUG, false)
- .toBool();
-}
-
-static bool hideAnalyzeMenuSetting()
-{
- return Core::ICore::settings()
- ->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_ANALYZE, false)
- .toBool();
-}
-
-static bool hideToolsMenuSetting()
+QStyle *QmlDesignerBasePlugin::style()
{
- return Core::ICore::settings()->value(Core::Constants::SETTINGS_MENU_HIDE_TOOLS, false).toBool();
-}
+ if (!global->d->style)
+ global->d->style = new StudioStyle(QApplication::style());
-void setSettingIfDifferent(const QString &key, bool value, bool &dirty)
-{
- QSettings *s = Core::ICore::settings();
- if (s->value(key, false).toBool() != value) {
- dirty = true;
- s->setValue(key, value);
- }
+ return global->d->style;
}
-StudioSettingsPage::StudioSettingsPage()
- : m_buildCheckBox(new QCheckBox(tr("Build")))
- , m_debugCheckBox(new QCheckBox(tr("Debug")))
- , m_analyzeCheckBox(new QCheckBox(tr("Analyze")))
- , m_toolsCheckBox(new QCheckBox(tr("Tools")))
- , m_pathChooserExamples(new Utils::PathChooser())
- , m_pathChooserBundles(new Utils::PathChooser())
+StudioConfigSettingsPage *QmlDesignerBasePlugin::studioConfigSettingsPage()
{
- 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> "
- "are only required for debugging and profiling. <b>Tools</b> can be useful for bookmarks "
- "and git integration.");
-
- QVBoxLayout *boxLayout = new QVBoxLayout();
- setLayout(boxLayout);
- auto groupBox = new QGroupBox(tr("Hide Menu"));
- groupBox->setToolTip(toolTip);
- boxLayout->addWidget(groupBox);
-
- auto verticalLayout = new QVBoxLayout();
- groupBox->setLayout(verticalLayout);
-
- m_buildCheckBox->setToolTip(toolTip);
- m_debugCheckBox->setToolTip(toolTip);
- m_analyzeCheckBox->setToolTip(toolTip);
- m_toolsCheckBox->setToolTip(toolTip);
-
- verticalLayout->addWidget(m_buildCheckBox);
- verticalLayout->addWidget(m_debugCheckBox);
- verticalLayout->addWidget(m_analyzeCheckBox);
- verticalLayout->addWidget(m_toolsCheckBox);
-
- verticalLayout->addSpacerItem(
- new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum));
-
- m_buildCheckBox->setChecked(hideBuildMenuSetting());
- m_debugCheckBox->setChecked(hideDebugMenuSetting());
- m_analyzeCheckBox->setChecked(hideAnalyzeMenuSetting());
- m_toolsCheckBox->setChecked(hideToolsMenuSetting());
-
- // Examples path setting
- auto examplesGroupBox = new QGroupBox(tr("Examples"));
- boxLayout->addWidget(examplesGroupBox);
-
- auto examplesLayout = new QHBoxLayout(this);
- examplesGroupBox->setLayout(examplesLayout);
-
- auto examplesLabel = new QLabel(tr("Examples path:"));
- m_pathChooserExamples->setFilePath(
- Utils::FilePath::fromString(QmlDesignerBasePlugin::examplesPathSetting()));
- auto examplesResetButton = new QPushButton(tr("Reset Path"));
-
- connect(examplesResetButton, &QPushButton::clicked, this, [this]() {
- m_pathChooserExamples->setFilePath(QmlDesignerBasePlugin::defaultExamplesPath());
- });
-
- examplesLayout->addWidget(examplesLabel);
- examplesLayout->addWidget(m_pathChooserExamples);
- examplesLayout->addWidget(examplesResetButton);
-
- // Bundles path setting
- auto bundlesGroupBox = new QGroupBox(tr("Bundles"));
- boxLayout->addWidget(bundlesGroupBox);
-
- auto bundlesLayout = new QHBoxLayout(this);
- bundlesGroupBox->setLayout(bundlesLayout);
-
- QLabel *bundlesLabel = new QLabel(tr("Bundles path:"));
- m_pathChooserBundles->setFilePath(
- Utils::FilePath::fromString(QmlDesignerBasePlugin::bundlesPathSetting()));
- QPushButton *bundlesResetButton = new QPushButton(tr("Reset Path"));
-
- connect(bundlesResetButton, &QPushButton::clicked, this, [this]() {
- m_pathChooserBundles->setFilePath(QmlDesignerBasePlugin::defaultBundlesPath());
- });
-
- bundlesLayout->addWidget(bundlesLabel);
- bundlesLayout->addWidget(m_pathChooserBundles);
- bundlesLayout->addWidget(bundlesResetButton);
-
- boxLayout->addSpacerItem(new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Expanding));
+ return &global->d->studioConfigSettingsPage;
}
-void StudioSettingsPage::apply()
+bool QmlDesignerBasePlugin::initialize(const QStringList &, QString *)
{
- bool dirty = false;
-
- setSettingIfDifferent(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_BUILD,
- m_buildCheckBox->isChecked(),
- dirty);
-
- setSettingIfDifferent(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_DEBUG,
- m_debugCheckBox->isChecked(),
- dirty);
-
- setSettingIfDifferent(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_ANALYZE,
- m_analyzeCheckBox->isChecked(),
- dirty);
-
- setSettingIfDifferent(Core::Constants::SETTINGS_MENU_HIDE_TOOLS,
- m_toolsCheckBox->isChecked(),
- dirty);
-
- if (dirty) {
- const QString restartText = tr("The menu visibility change will take effect after restart.");
- Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
- restartDialog.exec();
- }
-
- QSettings *s = Core::ICore::settings();
- const QString value = m_pathChooserExamples->filePath().toString();
-
- if (s->value(EXAMPLES_DOWNLOAD_PATH, false).toString() != value) {
- s->setValue(EXAMPLES_DOWNLOAD_PATH, value);
- emit global->examplesDownloadPathChanged(value);
- }
-
- const QString bundlesPath = m_pathChooserBundles->filePath().toString();
-
- if (s->value(BUNDLES_DOWNLOAD_PATH).toString() != bundlesPath) {
- s->setValue(BUNDLES_DOWNLOAD_PATH, bundlesPath);
- emit global->bundlesDownloadPathChanged(bundlesPath);
-
- const QString restartText = tr("Changing bundle path will take effect after restart.");
- Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
- restartDialog.exec();
- }
-}
+ d = std::make_unique<Data>();
-StudioConfigSettingsPage::StudioConfigSettingsPage()
-{
- setId("Z.StudioConfig.Settings");
- setDisplayName(StudioSettingsPage::tr("Qt Design Studio Configuration"));
- setCategory(Core::Constants::SETTINGS_CATEGORY_CORE);
- setWidgetCreator([] { return new StudioSettingsPage; });
+ return true;
}
} // namespace QmlDesigner
diff --git a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h
index 3676a04e8c1..997189dacf6 100644
--- a/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h
+++ b/src/plugins/qmldesignerbase/qmldesignerbaseplugin.h
@@ -5,40 +5,16 @@
#include "qmldesignerbase_global.h"
-#include <coreplugin/dialogs/ioptionspage.h>
#include <extensionsystem/iplugin.h>
-#include <utils/pathchooser.h>
#include <memory>
-QT_FORWARD_DECLARE_CLASS(QCheckBox)
+QT_BEGIN_NAMESPACE
+class QStyle;
+QT_END_NAMESPACE
namespace QmlDesigner {
-class StudioSettingsPage : public Core::IOptionsPageWidget
-{
- Q_OBJECT
-
-public:
- void apply() final;
-
- StudioSettingsPage();
-
-private:
- QCheckBox *m_buildCheckBox;
- QCheckBox *m_debugCheckBox;
- QCheckBox *m_analyzeCheckBox;
- QCheckBox *m_toolsCheckBox;
- Utils::PathChooser *m_pathChooserExamples;
- Utils::PathChooser *m_pathChooserBundles;
-};
-
-class QMLDESIGNERBASE_EXPORT StudioConfigSettingsPage : public Core::IOptionsPage
-{
-public:
- StudioConfigSettingsPage();
-};
-
class QMLDESIGNERBASE_EXPORT QmlDesignerBasePlugin final : public ExtensionSystem::IPlugin
{
Q_OBJECT
@@ -48,18 +24,9 @@ public:
QmlDesignerBasePlugin();
~QmlDesignerBasePlugin();
- static QmlDesignerBasePlugin *instance();
-
- static Utils::FilePath defaultExamplesPath();
- static Utils::FilePath defaultBundlesPath();
- static QString examplesPathSetting();
- static QString bundlesPathSetting();
-
static class DesignerSettings &settings();
-
-signals:
- void examplesDownloadPathChanged(const QString &path);
- void bundlesDownloadPathChanged(const QString &path);
+ static QStyle *style();
+ static class StudioConfigSettingsPage *studioConfigSettingsPage();
private:
bool initialize(const QStringList &arguments, QString *errorMessage) override;
diff --git a/src/plugins/qmldesignerbase/utils/studioquickwidget.cpp b/src/plugins/qmldesignerbase/studio/studioquickwidget.cpp
index 2cfe5aa9741..2cfe5aa9741 100644
--- a/src/plugins/qmldesignerbase/utils/studioquickwidget.cpp
+++ b/src/plugins/qmldesignerbase/studio/studioquickwidget.cpp
diff --git a/src/plugins/qmldesignerbase/utils/studioquickwidget.h b/src/plugins/qmldesignerbase/studio/studioquickwidget.h
index ef64fb6a69d..ef64fb6a69d 100644
--- a/src/plugins/qmldesignerbase/utils/studioquickwidget.h
+++ b/src/plugins/qmldesignerbase/studio/studioquickwidget.h
diff --git a/src/plugins/qmldesignerbase/studio/studiosettingspage.cpp b/src/plugins/qmldesignerbase/studio/studiosettingspage.cpp
new file mode 100644
index 00000000000..d88c4cf409b
--- /dev/null
+++ b/src/plugins/qmldesignerbase/studio/studiosettingspage.cpp
@@ -0,0 +1,217 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "studiosettingspage.h"
+
+#include "../utils/designerpaths.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/dialogs/restartdialog.h>
+#include <coreplugin/icore.h>
+#include <projectexplorer/projectexplorer.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <utils/theme/theme.h>
+
+#include <QApplication>
+#include <QCheckBox>
+#include <QGroupBox>
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QPushButton>
+#include <QSpacerItem>
+#include <QStyle>
+#include <QStyleFactory>
+#include <QVBoxLayout>
+
+namespace QmlDesigner {
+
+namespace {
+
+bool hideBuildMenuSetting()
+{
+ return Core::ICore::settings()
+ ->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_BUILD, false)
+ .toBool();
+}
+
+bool hideDebugMenuSetting()
+{
+ return Core::ICore::settings()
+ ->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_DEBUG, false)
+ .toBool();
+}
+
+bool hideAnalyzeMenuSetting()
+{
+ return Core::ICore::settings()
+ ->value(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_ANALYZE, false)
+ .toBool();
+}
+
+bool hideToolsMenuSetting()
+{
+ return Core::ICore::settings()->value(Core::Constants::SETTINGS_MENU_HIDE_TOOLS, false).toBool();
+}
+
+void setSettingIfDifferent(const QString &key, bool value, bool &dirty)
+{
+ QSettings *s = Core::ICore::settings();
+ if (s->value(key, false).toBool() != value) {
+ dirty = true;
+ s->setValue(key, value);
+ }
+}
+
+} // namespace
+
+StudioSettingsPage::StudioSettingsPage()
+ : m_buildCheckBox(new QCheckBox(tr("Build")))
+ , m_debugCheckBox(new QCheckBox(tr("Debug")))
+ , m_analyzeCheckBox(new QCheckBox(tr("Analyze")))
+ , m_toolsCheckBox(new QCheckBox(tr("Tools")))
+ , m_pathChooserExamples(new Utils::PathChooser())
+ , m_pathChooserBundles(new Utils::PathChooser())
+{
+ 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> "
+ "are only required for debugging and profiling. <b>Tools</b> can be useful for bookmarks "
+ "and git integration.");
+
+ QVBoxLayout *boxLayout = new QVBoxLayout();
+ setLayout(boxLayout);
+ auto groupBox = new QGroupBox(tr("Hide Menu"));
+ groupBox->setToolTip(toolTip);
+ boxLayout->addWidget(groupBox);
+
+ auto verticalLayout = new QVBoxLayout();
+ groupBox->setLayout(verticalLayout);
+
+ m_buildCheckBox->setToolTip(toolTip);
+ m_debugCheckBox->setToolTip(toolTip);
+ m_analyzeCheckBox->setToolTip(toolTip);
+ m_toolsCheckBox->setToolTip(toolTip);
+
+ verticalLayout->addWidget(m_buildCheckBox);
+ verticalLayout->addWidget(m_debugCheckBox);
+ verticalLayout->addWidget(m_analyzeCheckBox);
+ verticalLayout->addWidget(m_toolsCheckBox);
+
+ verticalLayout->addSpacerItem(
+ new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum));
+
+ m_buildCheckBox->setChecked(hideBuildMenuSetting());
+ m_debugCheckBox->setChecked(hideDebugMenuSetting());
+ m_analyzeCheckBox->setChecked(hideAnalyzeMenuSetting());
+ m_toolsCheckBox->setChecked(hideToolsMenuSetting());
+
+ // Examples path setting
+ auto examplesGroupBox = new QGroupBox(tr("Examples"));
+ boxLayout->addWidget(examplesGroupBox);
+
+ auto examplesLayout = new QHBoxLayout(this);
+ examplesGroupBox->setLayout(examplesLayout);
+
+ auto examplesLabel = new QLabel(tr("Examples path:"));
+ m_pathChooserExamples->setFilePath(Utils::FilePath::fromString(Paths::examplesPathSetting()));
+ auto examplesResetButton = new QPushButton(tr("Reset Path"));
+
+ connect(examplesResetButton, &QPushButton::clicked, this, [this]() {
+ m_pathChooserExamples->setFilePath(Paths::defaultExamplesPath());
+ });
+
+ examplesLayout->addWidget(examplesLabel);
+ examplesLayout->addWidget(m_pathChooserExamples);
+ examplesLayout->addWidget(examplesResetButton);
+
+ // Bundles path setting
+ auto bundlesGroupBox = new QGroupBox(tr("Bundles"));
+ boxLayout->addWidget(bundlesGroupBox);
+
+ auto bundlesLayout = new QHBoxLayout(this);
+ bundlesGroupBox->setLayout(bundlesLayout);
+
+ QLabel *bundlesLabel = new QLabel(tr("Bundles path:"));
+ m_pathChooserBundles->setFilePath(Utils::FilePath::fromString(Paths::bundlesPathSetting()));
+ QPushButton *bundlesResetButton = new QPushButton(tr("Reset Path"));
+
+ connect(bundlesResetButton, &QPushButton::clicked, this, [this]() {
+ m_pathChooserBundles->setFilePath(Paths::defaultBundlesPath());
+ });
+
+ bundlesLayout->addWidget(bundlesLabel);
+ bundlesLayout->addWidget(m_pathChooserBundles);
+ bundlesLayout->addWidget(bundlesResetButton);
+
+ boxLayout->addSpacerItem(
+ new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Expanding));
+}
+
+void StudioSettingsPage::apply()
+{
+ bool dirty = false;
+
+ setSettingIfDifferent(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_BUILD,
+ m_buildCheckBox->isChecked(),
+ dirty);
+
+ setSettingIfDifferent(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_DEBUG,
+ m_debugCheckBox->isChecked(),
+ dirty);
+
+ setSettingIfDifferent(ProjectExplorer::Constants::SETTINGS_MENU_HIDE_ANALYZE,
+ m_analyzeCheckBox->isChecked(),
+ dirty);
+
+ setSettingIfDifferent(Core::Constants::SETTINGS_MENU_HIDE_TOOLS,
+ m_toolsCheckBox->isChecked(),
+ dirty);
+
+ if (dirty) {
+ const QString restartText = tr(
+ "The menu visibility change will take effect after restart.");
+ Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
+ restartDialog.exec();
+ }
+
+ QSettings *s = Core::ICore::settings();
+ const QString value = m_pathChooserExamples->filePath().toString();
+
+ if (s->value(Paths::exampleDownloadPath, false).toString() != value) {
+ s->setValue(Paths::exampleDownloadPath, value);
+ emit examplesDownloadPathChanged(value);
+ }
+
+ const QString bundlesPath = m_pathChooserBundles->filePath().toString();
+
+ if (s->value(Paths::bundlesDownloadPath).toString() != bundlesPath) {
+ s->setValue(Paths::bundlesDownloadPath, bundlesPath);
+ emit bundlesDownloadPathChanged(bundlesPath);
+
+ const QString restartText = tr("Changing bundle path will take effect after restart.");
+ Core::RestartDialog restartDialog(Core::ICore::dialogParent(), restartText);
+ restartDialog.exec();
+ }
+}
+
+StudioConfigSettingsPage::StudioConfigSettingsPage()
+{
+ setId("Z.StudioConfig.Settings");
+ setDisplayName(tr("Qt Design Studio Configuration"));
+ setCategory(Core::Constants::SETTINGS_CATEGORY_CORE);
+ setWidgetCreator([&] {
+ auto page = new StudioSettingsPage;
+ QObject::connect(page,
+ &StudioSettingsPage::examplesDownloadPathChanged,
+ this,
+ &StudioConfigSettingsPage::examplesDownloadPathChanged);
+ QObject::connect(page,
+ &StudioSettingsPage::bundlesDownloadPathChanged,
+ this,
+ &StudioConfigSettingsPage::bundlesDownloadPathChanged);
+ return page;
+ });
+}
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesignerbase/studio/studiosettingspage.h b/src/plugins/qmldesignerbase/studio/studiosettingspage.h
new file mode 100644
index 00000000000..075367e4bb1
--- /dev/null
+++ b/src/plugins/qmldesignerbase/studio/studiosettingspage.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "../qmldesignerbase_global.h"
+
+#include <coreplugin/dialogs/ioptionspage.h>
+#include <utils/pathchooser.h>
+
+QT_FORWARD_DECLARE_CLASS(QCheckBox)
+
+namespace QmlDesigner {
+
+class StudioSettingsPage : public Core::IOptionsPageWidget
+{
+ Q_OBJECT
+
+public:
+ void apply() final;
+
+ StudioSettingsPage();
+
+signals:
+ void examplesDownloadPathChanged(const QString &path);
+ void bundlesDownloadPathChanged(const QString &path);
+
+private:
+ QCheckBox *m_buildCheckBox;
+ QCheckBox *m_debugCheckBox;
+ QCheckBox *m_analyzeCheckBox;
+ QCheckBox *m_toolsCheckBox;
+ Utils::PathChooser *m_pathChooserExamples;
+ Utils::PathChooser *m_pathChooserBundles;
+};
+
+class QMLDESIGNERBASE_EXPORT StudioConfigSettingsPage : public QObject, Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ StudioConfigSettingsPage();
+
+signals:
+ void examplesDownloadPathChanged(const QString &path);
+ void bundlesDownloadPathChanged(const QString &path);
+};
+
+} // namespace QmlDesigner
diff --git a/src/plugins/qmldesignerbase/studio/studiostyle.cpp b/src/plugins/qmldesignerbase/studio/studiostyle.cpp
new file mode 100644
index 00000000000..ffe652e363e
--- /dev/null
+++ b/src/plugins/qmldesignerbase/studio/studiostyle.cpp
@@ -0,0 +1,992 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+#include "studiostyle.h"
+
+#include <utils/stylehelper.h>
+#include <utils/theme/theme.h>
+
+#include <QMenu>
+#include <QPainter>
+#include <QStyleOption>
+
+using namespace Utils;
+
+namespace {
+
+inline QColor studioTextColor(bool enabled,
+ bool active,
+ bool checked)
+{
+ Theme::Color themePenColorId =
+ enabled ? (active
+ ? (checked ? Theme::DSsubPanelBackground
+ : Theme::DSpanelBackground)
+ : Theme::DStextColor)
+ : Theme::DStextColorDisabled;
+
+ return creatorTheme()->color(themePenColorId);
+}
+
+inline QColor studioButtonBgColor(bool enabled,
+ bool hovered,
+ bool pressed,
+ bool checked)
+{
+ Theme::Color themePenColorId =
+ enabled
+ ? (pressed
+ ? (checked
+ ? Theme::DSinteractionHover
+ : Theme::DScontrolBackgroundGlobalHover)
+ : (hovered
+ ? (checked
+ ? Theme::DSinteractionHover
+ : Theme::DScontrolBackgroundHover)
+ : Theme::DScontrolBackground)
+ )
+ : Theme::DScontrolBackgroundDisabled;
+
+ return creatorTheme()->color(themePenColorId);
+}
+
+inline QColor studioButtonOutlineColor(bool enabled,
+ [[maybe_unused]] bool hovered,
+ bool pressed,
+ [[maybe_unused]] bool checked)
+{
+
+ Theme::Color themePenColorId =
+ enabled
+ ? (pressed
+ ? Theme::DScontrolOutlineInteraction
+ : Theme::DScontrolOutline)
+ : Theme::DScontrolOutlineDisabled;
+
+ return creatorTheme()->color(themePenColorId);
+}
+
+bool styleEnabled(const QWidget *widget)
+{
+ const QWidget *p = widget;
+ while (p) {
+ if (p->property("_q_custom_style_disabled").toBool())
+ return false;
+ p = p->parentWidget();
+ }
+ return true;
+}
+
+// Consider making this a QStyle state
+bool isQmlEditorMenu(const QWidget *widget)
+{
+ const QMenu *menu = qobject_cast<const QMenu *> (widget);
+ if (!menu)
+ return false;
+
+ const QWidget *p = widget;
+ while (p) {
+ if (p->property("qmlEditorMenu").toBool())
+ return styleEnabled(widget);
+ p = p->parentWidget();
+ }
+
+ return false;
+}
+
+QPixmap getPixmapFromIcon(const QIcon &icon, const QSize &size, bool enabled, bool active, bool checked)
+{
+ QIcon::Mode mode = enabled ? ((active) ? QIcon::Active : QIcon::Normal) : QIcon::Disabled;
+ QIcon::State state = (checked) ? QIcon::On : QIcon::Off;
+ return icon.pixmap(size, mode, state);
+}
+
+struct StudioShortcut {
+ StudioShortcut(const QStyleOptionMenuItem *option,
+ const QString &shortcutText)
+ : shortcutText(shortcutText)
+ , enabled(option->state & QStyle::State_Enabled)
+ , active(option->state & QStyle::State_Selected)
+ , font(option->font)
+ , fm(font)
+ , defaultHeight(fm.height())
+ , spaceConst(fm.boundingRect(".").width())
+ {
+ reset();
+
+ if (backspaceMatch(shortcutText).hasMatch())
+ backspaceIcon = option->styleObject->property("backspaceIcon").value<QIcon>();
+ }
+
+ QSize getSize()
+ {
+ if (isFirstParticle)
+ calcResult();
+ return _size;
+ }
+
+ QPixmap getPixmap()
+ {
+ if (!isFirstParticle && !_pixmap.isNull())
+ return _pixmap;
+
+ _pixmap = QPixmap(getSize());
+ _pixmap.fill(Qt::transparent);
+ QPainter painter(&_pixmap);
+ painter.setFont(font);
+ QPen pPen = painter.pen();
+ pPen.setColor(studioTextColor(enabled, active, false));
+ painter.setPen(pPen);
+ calcResult(&painter);
+ painter.end();
+
+ return _pixmap;
+ }
+
+private:
+ void applySize(const QSize &itemSize) {
+ width += itemSize.width();
+ height = std::max(height, itemSize.height());
+ if (isFirstParticle)
+ isFirstParticle = false;
+ else
+ width += spaceConst;
+ };
+
+ void addText(const QString &txt, QPainter *painter = nullptr)
+ {
+ if (txt.size()) {
+ int textWidth = fm.horizontalAdvance(txt);
+ QSize itemSize = {textWidth, defaultHeight};
+ if (painter) {
+ static const QTextOption textOption(Qt::AlignLeft | Qt::AlignVCenter);
+ QRect placeRect({width, 0}, itemSize);
+ painter->drawText(placeRect, txt, textOption);
+ }
+ applySize(itemSize);
+ }
+ };
+
+ void addPixmap(const QPixmap &pixmap, QPainter *painter = nullptr)
+ {
+ if (painter)
+ painter->drawPixmap(QRect({width, 0}, pixmap.size()), pixmap);
+
+ applySize(pixmap.size());
+ };
+
+ void calcResult(QPainter *painter = nullptr)
+ {
+ reset();
+#ifndef QT_NO_SHORTCUT
+ if (!shortcutText.isEmpty()) {
+ int fwdIndex = 0;
+
+ QRegularExpressionMatch mMatch = backspaceMatch(shortcutText);
+ int matchCount = mMatch.lastCapturedIndex();
+
+ for (int i = 0; i <= matchCount; ++i) {
+ QString mStr = mMatch.captured(i);
+ QSize iconSize(defaultHeight * 3, defaultHeight);
+ const QList<QSize> iconSizes = backspaceIcon.availableSizes();
+ if (iconSizes.size())
+ iconSize = iconSizes.last();
+ double aspectRatio = (defaultHeight + .0) / iconSize.height();
+ int newWidth = iconSize.width() * aspectRatio;
+
+ QPixmap pixmap = getPixmapFromIcon(backspaceIcon,
+ {newWidth, defaultHeight},
+ enabled, active, false);
+
+ int lIndex = shortcutText.indexOf(mStr, fwdIndex);
+ int diffChars = lIndex - fwdIndex;
+ addText(shortcutText.mid(fwdIndex, diffChars), painter);
+ addPixmap(pixmap, painter);
+ fwdIndex = lIndex + mStr.size();
+ }
+ addText(shortcutText.mid(fwdIndex), painter);
+ }
+#endif
+ _size = {width, height};
+ }
+
+ void reset()
+ {
+ isFirstParticle = true;
+ width = 0;
+ height = 0;
+ }
+
+ inline QRegularExpressionMatch backspaceMatch(const QString &str) const
+ {
+ static const QRegularExpression backspaceDetect(
+ "\\+*backspace\\+*",
+ QRegularExpression::CaseInsensitiveOption);
+ return backspaceDetect.match(str);
+ }
+
+ const QString shortcutText;
+ const bool enabled;
+ const bool active;
+ const QFont font;
+ const QFontMetrics fm;
+ const int defaultHeight;
+ const int spaceConst;
+ QIcon backspaceIcon;
+ bool isFirstParticle = true;
+
+ int width = 0;
+ int height = 0;
+ QSize _size;
+ QPixmap _pixmap;
+};
+
+} // blank namespace
+
+class StudioStylePrivate
+{
+public:
+ explicit StudioStylePrivate();
+
+public:
+ QPalette stdPalette;
+};
+
+StudioStylePrivate::StudioStylePrivate()
+{
+ auto color = [] (Theme::Color c) {
+ return creatorTheme()->color(c);
+ };
+
+ {
+ stdPalette.setColorGroup(
+ QPalette::Disabled, // group
+ color(Theme::DStextColorDisabled), // windowText
+ color(Theme::DScontrolBackgroundDisabled), // button
+ color(Theme::DScontrolOutlineDisabled), // light
+ color(Theme::DStextSelectedTextColor), // dark
+ color(Theme::DSstatusbarBackground), // mid
+ color(Theme::DStextColorDisabled), // text
+ color(Theme::DStextColorDisabled), // brightText
+ color(Theme::DStoolbarIcon_blocked), // base
+ color(Theme::DStoolbarIcon_blocked) // window
+ );
+
+ stdPalette.setColorGroup(
+ QPalette::Inactive, // group
+ color(Theme::DStextColor), // windowText
+ color(Theme::DScontrolBackground), // button
+ color(Theme::DStoolbarBackground), // light
+ color(Theme::DSstatusbarBackground), // dark
+ color(Theme::DScontrolBackground), // mid
+ color(Theme::DStextColor), // text
+ color(Theme::DStextColor), // brightText
+ color(Theme::DStoolbarBackground), // base
+ color(Theme::DStoolbarBackground) // window
+ );
+
+ stdPalette.setColorGroup(
+ QPalette::Active, // group
+ color(Theme::DStextSelectedTextColor), // windowText
+ color(Theme::DSnavigatorItemBackgroundHover), // button
+ color(Theme::DSstateBackgroundColor_hover), // light
+ color(Theme::DSpanelBackground), // dark
+ color(Theme::DSnavigatorItemBackgroundHover), // mid
+ color(Theme::DStextSelectedTextColor), // text
+ color(Theme::DStextSelectedTextColor), // brightText
+ color(Theme::DStoolbarBackground), // base
+ color(Theme::DStoolbarBackground) // window
+ );
+ }
+}
+
+StudioStyle::StudioStyle(QStyle *style)
+ : QProxyStyle(style)
+ , d(new StudioStylePrivate)
+{
+}
+
+StudioStyle::StudioStyle(const QString &key)
+ : QProxyStyle(key)
+ , d(new StudioStylePrivate)
+{
+}
+
+StudioStyle::~StudioStyle()
+{
+ delete d;
+}
+
+void StudioStyle::drawPrimitive(
+ PrimitiveElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget) const
+{
+ switch (element) {
+ case PE_IndicatorArrowUp:
+ case PE_IndicatorArrowDown:
+ if (const auto mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ QStyleOptionMenuItem item = *mbi;
+ item.palette = QPalette(Qt::white);
+ StyleHelper::drawMinimalArrow(element, painter, &item);
+ } else {
+ Super::drawPrimitive(element, option, painter, widget);
+ }
+ break;
+
+ case PE_IndicatorArrowRight:
+ drawQmlEditorIcon(element, option, "cascadeIconRight", painter, widget);
+ break;
+
+ case PE_IndicatorArrowLeft:
+ drawQmlEditorIcon(element, option, "cascadeIconLeft", painter, widget);
+ break;
+
+ case PE_IndicatorMenuCheckMark:
+ drawQmlEditorIcon(element, option, "tickIcon", painter, widget);
+ break;
+
+ case PE_FrameMenu:
+ case PE_PanelMenu:
+ if (isQmlEditorMenu(widget))
+ painter->fillRect(option->rect, creatorTheme()->color(Theme::DSsubPanelBackground));
+ else
+ Super::drawPrimitive(element, option, painter, widget);
+ break;
+
+ case PE_PanelButtonCommand:
+ if (!isQmlEditorMenu(widget))
+ Super::drawPrimitive(element, option, painter, widget);
+ break;
+ case PE_FrameDefaultButton:
+ {
+ if (const auto button = qstyleoption_cast<const QStyleOptionButton *>(option)) {
+ bool enabled = button->state & QStyle::State_Enabled;
+ bool hovered = enabled && button->state & QStyle::State_MouseOver;
+ bool checked = button->state & QStyle::State_On;
+ bool pressed = enabled && button->state & QStyle::State_Sunken;
+ QColor btnColor = studioButtonBgColor(enabled, hovered, pressed, checked);
+ QColor penColor = studioButtonOutlineColor(enabled, hovered, pressed, checked);
+ penColor.setAlpha(50);
+
+ painter->save();
+ painter->setPen(QPen(penColor, 1));
+ if (pressed) {
+ painter->setBrush(Qt::NoBrush);
+ painter->drawRoundedRect(option->rect.adjusted(0, 0, -1, -1), 5, 5);
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(btnColor);
+ painter->drawRoundedRect(option->rect.adjusted(1, 1, 0, 0), 5, 5);
+ } else {
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(btnColor);
+ painter->drawRoundedRect(option->rect, 5, 5);
+ }
+
+ painter->restore();
+ }
+ }
+ break;
+
+ case PE_IndicatorToolBarSeparator:
+ {
+ bool horizontal = option->state & State_Horizontal;
+ int thickness = pixelMetric(PM_ToolBarSeparatorExtent, option, widget);
+ QRect colorRect;
+ if (horizontal) {
+ colorRect = {option->rect.center().x() - thickness / 2 , option->rect.top() + 2,
+ thickness , option->rect.height() - 4};
+ } else {
+ colorRect = {option->rect.left() + 2, option->rect.center().y() - thickness / 2,
+ option->rect.width() - 4, thickness};
+ }
+
+ // The separator color is currently the same as toolbar bg
+ painter->fillRect(colorRect,
+ creatorTheme()->color(Theme::DStoolbarBackground));
+ }
+ break;
+
+ default:
+ {
+ Super::drawPrimitive(element, option, painter, widget);
+ break;
+ }
+ }
+}
+
+void StudioStyle::drawControl(
+ ControlElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget) const
+{
+ switch (element) {
+ case CE_MenuItem:
+ if (const auto mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ if (!isQmlEditorMenu(widget)) {
+ Super::drawControl(element, option, painter, widget);
+ break;
+ }
+ painter->save();
+ const int iconHeight = pixelMetric(QStyle::PM_SmallIconSize, option, widget);
+ const int horizontalSpacing = pixelMetric(QStyle::PM_LayoutHorizontalSpacing, option, widget);
+ const int iconWidth = iconHeight;
+ const bool isActive = mbi->state & State_Selected;
+ const bool isDisabled = !(mbi->state & State_Enabled);
+ const bool isCheckable = mbi->checkType != QStyleOptionMenuItem::NotCheckable;
+ const bool isChecked = isCheckable ? mbi->checked : false;
+ int startMargin = pixelMetric(QStyle::PM_LayoutLeftMargin, option, widget);
+ int endMargin = pixelMetric(QStyle::PM_LayoutRightMargin, option, widget);
+ int forwardX = 0;
+
+ if (option->direction == Qt::RightToLeft)
+ std::swap(startMargin, endMargin);
+
+ QStyleOptionMenuItem item = *mbi;
+
+ if (isActive) {
+ painter->fillRect(item.rect, creatorTheme()->color(Theme::DSinteraction));
+ }
+ forwardX += startMargin;
+
+ if (item.menuItemType == QStyleOptionMenuItem::Separator) {
+ int commonHeight = item.rect.center().y();
+ int additionalMargin = forwardX /*hmargin*/;
+ QLineF separatorLine (item.rect.left() + additionalMargin,
+ commonHeight,
+ item.rect.right() - additionalMargin,
+ commonHeight);
+
+ painter->setPen(creatorTheme()->color(Theme::DSstateSeparatorColor));
+ painter->drawLine(separatorLine);
+ item.text.clear();
+ painter->restore();
+ return;
+ }
+
+ QPixmap iconPixmap;
+ QIcon::Mode mode = isDisabled ? QIcon::Disabled : ((isActive) ? QIcon::Active : QIcon::Normal);
+ QIcon::State state = isChecked ? QIcon::On : QIcon::Off;
+ QColor themePenColor = studioTextColor(!isDisabled, isActive, isChecked);
+
+ if (!item.icon.isNull()) {
+ iconPixmap = item.icon.pixmap(QSize(iconHeight, iconHeight), mode, state);
+ } else if (isCheckable) {
+ iconPixmap = QPixmap(iconHeight, iconHeight);
+ iconPixmap.fill(Qt::transparent);
+
+ if (item.checked) {
+ QStyleOptionMenuItem so = item;
+ so.rect = iconPixmap.rect();
+ QPainter dPainter(&iconPixmap);
+ dPainter.setPen(themePenColor);
+ drawPrimitive(PE_IndicatorMenuCheckMark, &so, &dPainter, widget);
+ }
+ }
+
+ if (!iconPixmap.isNull()) {
+ QRect vCheckRect = visualRect(item.direction,
+ item.rect,
+ QRect(item.rect.x() + forwardX,
+ item.rect.y(),
+ iconWidth,
+ item.rect.height()));
+
+ QRect pmr(QPoint(0, 0), iconPixmap.deviceIndependentSize().toSize());
+ pmr.moveCenter(vCheckRect.center());
+ painter->setPen(themePenColor);
+ painter->drawPixmap(pmr.topLeft(), iconPixmap);
+
+ item.checkType = QStyleOptionMenuItem::NotCheckable;
+ item.checked = false;
+ item.icon = {};
+ }
+ if (item.menuHasCheckableItems || item.maxIconWidth > 0) {
+ forwardX += iconWidth + horizontalSpacing;
+ }
+
+ QString shortcutText;
+ int tabIndex = item.text.indexOf("\t");
+ if (tabIndex > -1) {
+ shortcutText = item.text.mid(tabIndex + 1);
+ item.text = item.text.left(tabIndex);
+ }
+
+ if (item.text.size()) {
+ painter->save();
+
+ QRect vTextRect = visualRect(item.direction,
+ item.rect,
+ item.rect.adjusted(forwardX, 0 , 0 , 0));
+
+ Qt::Alignment alignmentFlags = item.direction == Qt::LeftToRight ? Qt::AlignLeft
+ : Qt::AlignRight;
+ alignmentFlags |= Qt::AlignVCenter;
+
+ int textFlags = Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine;
+ if (!proxy()->styleHint(SH_UnderlineShortcut, &item, widget))
+ textFlags |= Qt::TextHideMnemonic;
+ textFlags |= alignmentFlags;
+
+ painter->setPen(themePenColor);
+ painter->drawText(vTextRect, textFlags, item.text);
+ painter->restore();
+ }
+
+ if (item.menuItemType == QStyleOptionMenuItem::SubMenu) {
+ PrimitiveElement dropDirElement = item.direction == Qt::LeftToRight
+ ? PE_IndicatorArrowRight
+ : PE_IndicatorArrowLeft;
+
+ QSize elSize(iconHeight, iconHeight);
+ int xOffset = iconHeight + endMargin;
+ int yOffset = (item.rect.height() - iconHeight) / 2;
+ QRect dropRect(item.rect.topRight(), elSize);
+ dropRect.adjust(-xOffset, yOffset, -xOffset, yOffset);
+
+ QStyleOptionMenuItem so = item;
+ so.rect = visualRect(item.direction,
+ item.rect,
+ dropRect);
+
+ drawPrimitive(dropDirElement, &so, painter, widget);
+ } else if (!shortcutText.isEmpty()) {
+ QPixmap pix = StudioShortcut(&item, shortcutText).getPixmap();
+
+ if (pix.width()) {
+ int xOffset = pix.width() + (iconHeight / 2) + endMargin;
+ QRect shortcutRect = item.rect.translated({item.rect.width() - xOffset, 0});
+ shortcutRect.setSize({pix.width(), item.rect.height()});
+ shortcutRect = visualRect(item.direction,
+ item.rect,
+ shortcutRect);
+ drawItemPixmap(painter,
+ shortcutRect,
+ Qt::AlignRight | Qt::AlignVCenter,
+ pix);
+ }
+ }
+ painter->restore();
+ }
+ break;
+
+ case CE_MenuEmptyArea:
+ if (isQmlEditorMenu(widget))
+ drawPrimitive(PE_PanelMenu, option, painter, widget);
+ else
+ Super::drawControl(element, option, painter, widget);
+ break;
+
+ default:
+ Super::drawControl(element, option, painter, widget);
+ break;
+ }
+}
+
+void StudioStyle::drawComplexControl(
+ ComplexControl control,
+ const QStyleOptionComplex *option,
+ QPainter *painter,
+ const QWidget *widget) const
+{
+ switch (control) {
+
+ case CC_Slider:
+ if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ QRect groove = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget);
+ QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget);
+
+ bool horizontal = slider->orientation == Qt::Horizontal;
+ bool ticksAbove = slider->tickPosition & QSlider::TicksAbove;
+ bool ticksBelow = slider->tickPosition & QSlider::TicksBelow;
+ bool enabled = option->state & QStyle::State_Enabled;
+ bool grooveHover = slider->activeSubControls & SC_SliderGroove;
+ bool handleHover = slider->activeSubControls & SC_SliderHandle;
+ bool interaction = option->state & State_Sunken;
+ bool activeFocus = option->state & State_HasFocus && option->state & State_KeyboardFocusChange;
+
+ int sliderPaintingOffset = horizontal
+ ? handle.center().x()
+ : handle.center().y();
+
+ int borderRadius = 4;
+
+ painter->save();
+ painter->setRenderHint(QPainter::RenderHint::Antialiasing);
+
+ Theme::Color themeframeColor = enabled
+ ? interaction
+ ? Theme::DSstateControlBackgroundColor_hover // Pressed
+ : grooveHover
+ ? Theme::DSstateSeparatorColor // GrooveHover
+ : Theme::DSpopupBackground // Idle
+ : Theme::DSpopupBackground; // Disabled
+
+ QColor frameColor = creatorTheme()->color(themeframeColor);
+
+ if ((option->subControls & SC_SliderGroove) && groove.isValid()) {
+ Theme::Color themeBgPlusColor = enabled
+ ? interaction
+ ? Theme::DSstateControlBackgroundColor_hover // Pressed
+ : grooveHover
+ ? Theme::DSstateSeparatorColor // GrooveHover
+ : Theme::DSstateControlBackgroundColor_hover // Idle should be the same as pressed
+ : Theme::DStoolbarBackground; // Disabled
+
+ Theme::Color themeBgMinusColor = Theme::DSpopupBackground;
+
+ QRect minusRect(groove);
+ QRect plusRect(groove);
+
+ if (horizontal) {
+ if (slider->upsideDown) {
+ minusRect.setLeft(sliderPaintingOffset);
+ plusRect.setRight(sliderPaintingOffset);
+ } else {
+ minusRect.setRight(sliderPaintingOffset);
+ plusRect.setLeft(sliderPaintingOffset);
+ }
+ } else {
+ if (slider->upsideDown) {
+ minusRect.setBottom(sliderPaintingOffset);
+ plusRect.setTop(sliderPaintingOffset);
+ } else {
+ minusRect.setTop(sliderPaintingOffset);
+ plusRect.setBottom(sliderPaintingOffset);
+ }
+ }
+
+ painter->save();
+ painter->setPen(Qt::NoPen);
+ painter->setBrush(creatorTheme()->color(themeBgPlusColor));
+ painter->drawRoundedRect(plusRect, borderRadius, borderRadius);
+ painter->setBrush(creatorTheme()->color(themeBgMinusColor));
+ painter->drawRoundedRect(minusRect, borderRadius, borderRadius);
+ painter->restore();
+ }
+
+ if (option->subControls & SC_SliderTickmarks) {
+ Theme::Color tickPen = enabled
+ ? activeFocus
+ ? Theme::DSstateBackgroundColor_hover
+ : Theme::DSBackgroundColorAlternate
+ : Theme::DScontrolBackgroundDisabled;
+
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(creatorTheme()->color(tickPen));
+ int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget);
+ int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget);
+ int interval = slider->tickInterval;
+ if (interval <= 0) {
+ interval = slider->singleStep;
+ if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval,
+ available)
+ - QStyle::sliderPositionFromValue(slider->minimum, slider->maximum,
+ 0, available) < 3)
+ interval = slider->pageStep;
+ }
+ if (interval <= 0)
+ interval = 1;
+
+ int v = slider->minimum;
+ int len = proxy()->pixelMetric(PM_SliderLength, slider, widget);
+ while (v <= slider->maximum + 1) {
+ if (v == slider->maximum + 1 && interval == 1)
+ break;
+ const int v_ = qMin(v, slider->maximum);
+ int pos = sliderPositionFromValue(slider->minimum, slider->maximum,
+ v_, (horizontal
+ ? slider->rect.width()
+ : slider->rect.height()) - len,
+ slider->upsideDown) + len / 2;
+ int extra = 2 - ((v_ == slider->minimum || v_ == slider->maximum) ? 1 : 0);
+
+ if (horizontal) {
+ if (ticksAbove) {
+ painter->drawLine(pos, slider->rect.top() + extra,
+ pos, slider->rect.top() + tickSize);
+ }
+ if (ticksBelow) {
+ painter->drawLine(pos, slider->rect.bottom() - extra,
+ pos, slider->rect.bottom() - tickSize);
+ }
+ } else {
+ if (ticksAbove) {
+ painter->drawLine(slider->rect.left() + extra, pos,
+ slider->rect.left() + tickSize, pos);
+ }
+ if (ticksBelow) {
+ painter->drawLine(slider->rect.right() - extra, pos,
+ slider->rect.right() - tickSize, pos);
+ }
+ }
+ // in the case where maximum is max int
+ int nextInterval = v + interval;
+ if (nextInterval < v)
+ break;
+ v = nextInterval;
+ }
+ }
+
+ // draw handle
+ if (option->subControls & SC_SliderHandle) {
+ Theme::Color handleColor = enabled
+ ? interaction
+ ? Theme::DSinteraction // Interaction
+ : grooveHover || handleHover
+ ? Theme::DStabActiveText // Hover
+ : Theme::PalettePlaceholderText // Idle
+ : Theme::DStoolbarIcon_blocked; // Disabled
+
+ int halfSliderThickness = horizontal
+ ? handle.width() / 2
+ : handle.height() / 2;
+ painter->setBrush(creatorTheme()->color(handleColor));
+ painter->setPen(Qt::NoPen);
+ painter->drawRoundedRect(handle,
+ halfSliderThickness,
+ halfSliderThickness);
+ }
+
+ if (groove.isValid()) {
+ int borderWidth = pixelMetric(QStyle::PM_DefaultFrameWidth, option, widget);
+ painter->setBrush(Qt::NoBrush);
+ painter->setPen(QPen(frameColor, borderWidth));
+ painter->drawRoundedRect(groove, borderRadius, borderRadius);
+ }
+ painter->restore();
+ }
+ break;
+
+ default:
+ Super::drawComplexControl(control, option, painter, widget);
+ break;
+ }
+}
+
+QSize StudioStyle::sizeFromContents(
+ ContentsType type,
+ const QStyleOption *option,
+ const QSize &size,
+ const QWidget *widget) const
+{
+ QSize newSize;
+
+ switch (type) {
+ case CT_MenuItem:
+ if (const auto mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option)) {
+ if (!isQmlEditorMenu(widget)) {
+ newSize = Super::sizeFromContents(type, option, size, widget);
+ break;
+ }
+
+ const int leftMargin = pixelMetric(
+ QStyle::PM_LayoutLeftMargin,
+ option, widget);
+ const int rightMargin = pixelMetric(
+ QStyle::PM_LayoutRightMargin,
+ option, widget);
+ const int horizontalSpacing = pixelMetric(
+ QStyle::PM_LayoutHorizontalSpacing,
+ option, widget);
+ const int iconHeight = pixelMetric(
+ QStyle::PM_SmallIconSize, option, widget) + horizontalSpacing;
+ int width = leftMargin + rightMargin;
+ if (mbi->menuHasCheckableItems || mbi->maxIconWidth)
+ width += iconHeight + horizontalSpacing;
+
+ if (!mbi->text.isEmpty()) {
+ QString itemText = mbi->text;
+ QString shortcutText;
+ int tabIndex = itemText.indexOf("\t");
+ if (tabIndex > -1) {
+ shortcutText = itemText.mid(tabIndex + 1);
+ itemText = itemText.left(tabIndex);
+ }
+
+ if (itemText.size())
+ width += option->fontMetrics.boundingRect(itemText).width() + horizontalSpacing;
+
+ if (shortcutText.size()) {
+ QSize shortcutSize = StudioShortcut(mbi, shortcutText).getSize();
+ width += shortcutSize.width() + 2 * horizontalSpacing;
+ }
+ }
+
+ if (mbi->menuItemType == QStyleOptionMenuItem::SubMenu)
+ width += iconHeight + horizontalSpacing;
+
+ newSize.setWidth(width);
+
+ switch (mbi->menuItemType) {
+ case QStyleOptionMenuItem::Normal:
+ case QStyleOptionMenuItem::DefaultItem:
+ case QStyleOptionMenuItem::SubMenu:
+ newSize.setHeight(19);
+ break;
+ default:
+ newSize.setHeight(9);
+ break;
+ }
+ }
+ break;
+
+ default:
+ newSize = Super::sizeFromContents(type, option, size, widget);
+ break;
+ }
+
+ return newSize;
+}
+
+QRect StudioStyle::subControlRect(
+ ComplexControl control,
+ const QStyleOptionComplex *option,
+ SubControl subControl,
+ const QWidget *widget) const
+{
+#if QT_VERSION < QT_VERSION_CHECK(6, 2, 5)
+ // Workaround for QTBUG-101581, can be removed when building with Qt 6.2.5 or higher
+ if (control == CC_ScrollBar) {
+ const auto scrollbar = qstyleoption_cast<const QStyleOptionSlider *>(option);
+ if (scrollbar && qint64(scrollbar->maximum) - scrollbar->minimum > INT_MAX)
+ return QRect(); // breaks the scrollbar, but avoids the crash
+ }
+#endif
+
+ switch (control)
+ {
+ case CC_Slider:
+ if (const auto slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ switch (subControl) {
+ case SubControl::SC_SliderGroove:
+ return slider->rect;
+ case SubControl::SC_SliderHandle:
+ {
+ QRect retval = Super::subControlRect(control, option, subControl, widget);
+ return (slider->orientation == Qt::Horizontal)
+ ? retval.adjusted(0, 1, 0, 0)
+ : retval.adjusted(1, 0, 0, 0);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return Super::subControlRect(control, option, subControl, widget);
+}
+
+int StudioStyle::styleHint(
+ StyleHint hint,
+ const QStyleOption *option,
+ const QWidget *widget,
+ QStyleHintReturn *returnData) const
+{
+ return Super::styleHint(hint, option, widget, returnData);
+}
+
+int StudioStyle::pixelMetric(
+ PixelMetric metric,
+ const QStyleOption *option,
+ const QWidget *widget) const
+{
+ switch (metric) {
+ case PM_SmallIconSize:
+ case PM_LayoutLeftMargin:
+ case PM_LayoutRightMargin:
+ case PM_LayoutHorizontalSpacing:
+ case PM_MenuHMargin:
+ case PM_SubMenuOverlap:
+ case PM_MenuPanelWidth:
+ case PM_MenuBarHMargin:
+ case PM_MenuBarVMargin:
+ case PM_ToolBarSeparatorExtent:
+ case PM_ToolBarFrameWidth:
+ if (isQmlEditorMenu(widget)) {
+ switch (metric) {
+ case PM_SmallIconSize:
+ return 10;
+ case PM_LayoutLeftMargin:
+ case PM_LayoutRightMargin:
+ return 7;
+ case PM_LayoutHorizontalSpacing:
+ return 12;
+ case PM_MenuHMargin:
+ return 5;
+ case PM_SubMenuOverlap:
+ return 0;
+ case PM_MenuPanelWidth:
+ case PM_MenuBarHMargin:
+ case PM_MenuBarVMargin:
+ case PM_ToolBarSeparatorExtent:
+ case PM_ToolBarFrameWidth:
+ return 1;
+ default:
+ return 0;
+ }
+ }
+ break;
+ case PM_ButtonShiftVertical:
+ case PM_ButtonShiftHorizontal:
+ case PM_MenuBarPanelWidth:
+ case PM_ToolBarItemMargin:
+ return 0;
+ case PM_ToolBarItemSpacing:
+ return 4;
+ case PM_ToolBarExtensionExtent:
+ return 29;
+ case PM_ScrollBarExtent:
+ return 20;
+ case PM_ScrollBarSliderMin:
+ return 30;
+ case PM_SliderLength:
+ return 5;
+ case PM_SliderThickness:
+ if (const auto *slider = qstyleoption_cast<const QStyleOptionSlider *>(option)) {
+ return (slider->orientation == Qt::Horizontal
+ ? slider->rect.height()
+ : slider->rect.width()) - 1;
+ }
+ break;
+ case PM_SliderControlThickness:
+ return 2;
+ default:
+ break;
+ }
+ return Super::pixelMetric(metric, option, widget);
+}
+
+QPalette StudioStyle::standardPalette() const
+{
+ return d->stdPalette;
+}
+
+void StudioStyle::drawQmlEditorIcon(
+ PrimitiveElement element,
+ const QStyleOption *option,
+ const char *propertyName,
+ QPainter *painter,
+ const QWidget *widget) const
+{
+ if (option->styleObject && option->styleObject->property(propertyName).isValid()) {
+ const auto mbi = qstyleoption_cast<const QStyleOptionMenuItem *>(option);
+ if (mbi) {
+ const bool isCheckable = mbi->checkType != QStyleOptionMenuItem::NotCheckable;
+ const bool isEnabled = mbi->state & State_Enabled;
+ const bool isActive = mbi->state & State_Selected;
+ const bool isChecked = isCheckable && mbi->checked;
+ QIcon icon = mbi->styleObject->property(propertyName).value<QIcon>();
+ QPixmap pix = getPixmapFromIcon(icon, mbi->rect.size(),
+ isEnabled, isActive, isChecked);
+ drawItemPixmap(painter, mbi->rect, Qt::AlignCenter, pix);
+ return;
+ }
+ }
+ Super::drawPrimitive(element, option, painter, widget);
+}
diff --git a/src/plugins/qmldesignerbase/studio/studiostyle.h b/src/plugins/qmldesignerbase/studio/studiostyle.h
new file mode 100644
index 00000000000..4d6424cbef1
--- /dev/null
+++ b/src/plugins/qmldesignerbase/studio/studiostyle.h
@@ -0,0 +1,76 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "qmldesignerbase_global.h"
+
+#include <QProxyStyle>
+
+class StudioStylePrivate;
+
+class QMLDESIGNERBASE_EXPORT StudioStyle : public QProxyStyle
+{
+ Q_OBJECT
+
+public:
+ using Super = QProxyStyle;
+ StudioStyle(QStyle *style = nullptr);
+ StudioStyle(const QString &key);
+ virtual ~StudioStyle() override;
+
+ // Drawing Methods
+ void drawPrimitive(
+ PrimitiveElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget = nullptr) const override;
+
+ void drawControl(
+ ControlElement element,
+ const QStyleOption *option,
+ QPainter *painter,
+ const QWidget *widget = nullptr) const override;
+
+ void drawComplexControl(
+ ComplexControl control,
+ const QStyleOptionComplex *option,
+ QPainter *painter,
+ const QWidget *widget = nullptr) const override;
+
+ // Topology
+ QSize sizeFromContents(
+ ContentsType type,
+ const QStyleOption *option,
+ const QSize &size,
+ const QWidget *widget) const override;
+
+ QRect subControlRect(
+ ComplexControl control,
+ const QStyleOptionComplex *option,
+ SubControl subControl,
+ const QWidget *widget) const override;
+
+ int styleHint(
+ StyleHint hint,
+ const QStyleOption *option,
+ const QWidget *widget,
+ QStyleHintReturn *returnData) const override;
+
+ int pixelMetric(
+ PixelMetric metric,
+ const QStyleOption *option = nullptr,
+ const QWidget *widget = nullptr) const override;
+
+ QPalette standardPalette() const override;
+
+private:
+ void drawQmlEditorIcon(
+ PrimitiveElement element,
+ const QStyleOption *option,
+ const char *propertyName,
+ QPainter *painter,
+ const QWidget *widget = nullptr) const;
+
+ StudioStylePrivate *d = nullptr;
+};
diff --git a/src/plugins/qmldesignerbase/utils/designerpaths.cpp b/src/plugins/qmldesignerbase/utils/designerpaths.cpp
new file mode 100644
index 00000000000..d4ae2a46456
--- /dev/null
+++ b/src/plugins/qmldesignerbase/utils/designerpaths.cpp
@@ -0,0 +1,45 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "designerpaths.h"
+
+#include <coreplugin/icore.h>
+#include <utils/hostosinfo.h>
+
+#include <QStandardPaths>
+
+namespace QmlDesigner::Paths {
+
+Utils::FilePath defaultExamplesPath()
+{
+ QStandardPaths::StandardLocation location = QStandardPaths::DocumentsLocation;
+
+ return Utils::FilePath::fromString(QStandardPaths::writableLocation(location))
+ .pathAppended("QtDesignStudio/examples");
+}
+
+Utils::FilePath defaultBundlesPath()
+{
+ QStandardPaths::StandardLocation location = Utils::HostOsInfo::isMacHost()
+ ? QStandardPaths::HomeLocation
+ : QStandardPaths::DocumentsLocation;
+
+ return Utils::FilePath::fromString(QStandardPaths::writableLocation(location))
+ .pathAppended("QtDesignStudio/bundles");
+}
+
+QString examplesPathSetting()
+{
+ return Core::ICore::settings()
+ ->value(exampleDownloadPath, defaultExamplesPath().toString())
+ .toString();
+}
+
+QString bundlesPathSetting()
+{
+ return Core::ICore::settings()
+ ->value(bundlesDownloadPath, defaultBundlesPath().toString())
+ .toString();
+}
+
+} // namespace QmlDesigner::Paths
diff --git a/src/plugins/qmldesignerbase/utils/designerpaths.h b/src/plugins/qmldesignerbase/utils/designerpaths.h
new file mode 100644
index 00000000000..df53997457f
--- /dev/null
+++ b/src/plugins/qmldesignerbase/utils/designerpaths.h
@@ -0,0 +1,20 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "../qmldesignerbase_global.h"
+
+#include <utils/filepath.h>
+
+namespace QmlDesigner::Paths {
+
+inline constexpr QStringView exampleDownloadPath = u"StudioConfig/ExamplesDownloadPath";
+inline constexpr QStringView bundlesDownloadPath = u"StudioConfig/BundlesDownloadPath";
+
+QMLDESIGNERBASE_EXPORT Utils::FilePath defaultExamplesPath();
+QMLDESIGNERBASE_EXPORT Utils::FilePath defaultBundlesPath();
+QMLDESIGNERBASE_EXPORT QString examplesPathSetting();
+QMLDESIGNERBASE_EXPORT QString bundlesPathSetting();
+
+} // namespace QmlDesigner::Paths
diff --git a/src/plugins/qmlprojectmanager/CMakeLists.txt b/src/plugins/qmlprojectmanager/CMakeLists.txt
index 4119bae7347..ad71e3fbffb 100644
--- a/src/plugins/qmlprojectmanager/CMakeLists.txt
+++ b/src/plugins/qmlprojectmanager/CMakeLists.txt
@@ -1,21 +1,9 @@
add_qtc_plugin(QmlProjectManager
CONDITION TARGET Qt::QuickWidgets
- PROPERTIES COMPILE_WARNING_AS_ERROR ON
PLUGIN_CLASS QmlProjectPlugin
- DEPENDS QmlJS Qt::QuickWidgets
+ DEPENDS QmlJS Qt::QuickWidgets Utils
PLUGIN_DEPENDS Core ProjectExplorer QtSupport QmlDesignerBase
SOURCES
- fileformat/filefilteritems.cpp fileformat/filefilteritems.h
- fileformat/qmlprojectfileformat.cpp fileformat/qmlprojectfileformat.h
- fileformat/qmlprojectitem.cpp fileformat/qmlprojectitem.h
- cmakegen/checkablefiletreeitem.cpp cmakegen/checkablefiletreeitem.h
- cmakegen/cmakegeneratordialog.cpp cmakegen/cmakegeneratordialog.h
- cmakegen/cmakegeneratordialogtreemodel.cpp cmakegen/cmakegeneratordialogtreemodel.h
- cmakegen/cmakeprojectconverter.cpp cmakegen/cmakeprojectconverter.h
- cmakegen/cmakeprojectconverterdialog.cpp cmakegen/cmakeprojectconverterdialog.h
- cmakegen/generatecmakelists.cpp cmakegen/generatecmakelists.h
- cmakegen/generatecmakelistsconstants.h
- cmakegen/boilerplate.qrc
qmlprojectgen/qmlprojectgenerator.cpp qmlprojectgen/qmlprojectgenerator.h
qmlprojectgen/templates.qrc
projectfilecontenttools.cpp projectfilecontenttools.h
@@ -29,8 +17,52 @@ add_qtc_plugin(QmlProjectManager
qmlprojectmanager_global.h
qmlprojectmanagertr.h
qmlprojectmanagerconstants.h
- qmlprojectnodes.cpp qmlprojectnodes.h
qmlprojectplugin.cpp qmlprojectplugin.h
qmlprojectrunconfiguration.cpp qmlprojectrunconfiguration.h
+ buildsystem/qmlbuildsystem.cpp buildsystem/qmlbuildsystem.h
+
"${PROJECT_SOURCE_DIR}/src/share/3rdparty/studiofonts/studiofonts.qrc"
)
+
+extend_qtc_plugin(QmlProjectManager
+ CONDITION NOT DISABLE_COMPILE_WARNING_AS_ERROR
+ PROPERTIES COMPILE_WARNING_AS_ERROR ON
+)
+
+extend_qtc_plugin(QmlProjectManager
+ PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/buildsystem
+ SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/buildsystem
+ SOURCES
+ projectitem/filefilteritems.cpp projectitem/filefilteritems.h
+ projectitem/qmlprojectitem.cpp projectitem/qmlprojectitem.h
+ projectitem/converters.h projectitem/converters.cpp
+ projectnode/qmlprojectnodes.cpp projectnode/qmlprojectnodes.h
+)
+
+extend_qtc_plugin(QmlProjectManager
+ PUBLIC_INCLUDES ${CMAKE_CURRENT_LIST_DIR}/cmakegen
+ SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/cmakegen
+ SOURCES
+ checkablefiletreeitem.cpp checkablefiletreeitem.h
+ cmakegeneratordialog.cpp cmakegeneratordialog.h
+ cmakegeneratordialogtreemodel.cpp cmakegeneratordialogtreemodel.h
+ cmakeprojectconverter.cpp cmakeprojectconverter.h
+ cmakeprojectconverterdialog.cpp cmakeprojectconverterdialog.h
+ generatecmakelists.cpp generatecmakelists.h
+ generatecmakelistsconstants.h
+ boilerplate.qrc
+)
+
+add_qtc_library(QmlProjectManagerLib OBJECT
+ CONDITION Qt6_VERSION VERSION_GREATER_EQUAL 6.4.3
+ EXCLUDE_FROM_INSTALL
+ DEPENDS
+ QmlJS Utils
+ INCLUDES
+ ${CMAKE_CURRENT_LIST_DIR}
+ SOURCES_PREFIX ${CMAKE_CURRENT_LIST_DIR}/buildsystem
+ SOURCES
+ projectitem/filefilteritems.cpp projectitem/filefilteritems.h
+ projectitem/qmlprojectitem.cpp projectitem/qmlprojectitem.h
+ projectitem/converters.cpp projectitem/converters.h
+)
diff --git a/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp b/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp
new file mode 100644
index 00000000000..0097611a4dd
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.cpp
@@ -0,0 +1,368 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "converters.h"
+
+#include <QJsonArray>
+
+namespace QmlProjectManager::Converters {
+
+using PropsPair = QPair<QString, QStringList>;
+struct FileProps
+{
+ const PropsPair image{"image", QStringList{"*.jpeg", "*.jpg", "*.png", "*.svg", "*.hdr", ".ktx"}};
+ const PropsPair qml{"qml", QStringList{"*.qml"}};
+ const PropsPair qmlDir{"qmldir", QStringList{"qmldir"}};
+ const PropsPair javaScr{"javaScript", QStringList{"*.js", "*.ts"}};
+ const PropsPair video{"video", QStringList{"*.mp4"}};
+ const PropsPair sound{"sound", QStringList{"*.mp3", "*.wav"}};
+ const PropsPair font{"font", QStringList{"*.ttf", "*.otf"}};
+ const PropsPair config{"config", QStringList{"*.conf"}};
+ const PropsPair styling{"styling", QStringList{"*.css"}};
+ const PropsPair mesh{"meshes", QStringList{"*.mesh"}};
+ const PropsPair
+ shader{"shader",
+ QStringList{"*.glsl", "*.glslv", "*.glslf", "*.vsh", "*.fsh", "*.vert", "*.frag"}};
+};
+
+QString jsonToQmlProject(const QJsonObject &rootObject)
+{
+ QString qmlProjectString;
+ QTextStream ts{&qmlProjectString};
+
+ QJsonObject runConfig = rootObject["runConfig"].toObject();
+ QJsonObject languageConfig = rootObject["language"].toObject();
+ QJsonObject shaderConfig = rootObject["shaderTool"].toObject();
+ QJsonObject versionConfig = rootObject["versions"].toObject();
+ QJsonObject environmentConfig = rootObject["environment"].toObject();
+ QJsonObject deploymentConfig = rootObject["deployment"].toObject();
+ QJsonObject filesConfig = rootObject["fileGroups"].toObject();
+
+ int indentationLevel = 0;
+
+ auto appendBreak = [&ts]() { ts << Qt::endl; };
+
+ auto appendComment = [&ts, &indentationLevel](const QString &comment) {
+ ts << QString(" ").repeated(indentationLevel * 4) << "\\\\ " << comment << Qt::endl;
+ };
+
+ auto appendItem =
+ [&ts, &indentationLevel](const QString &key, const QString &value, const bool isEnclosed) {
+ ts << QString(" ").repeated(indentationLevel * 4) << key << ": "
+ << (isEnclosed ? "\"" : "") << value << (isEnclosed ? "\"" : "") << Qt::endl;
+ };
+
+ auto appendString = [&appendItem](const QString &key, const QString &val) {
+ appendItem(key, val, true);
+ };
+
+ auto appendBool = [&appendItem](const QString &key, const bool &val) {
+ appendItem(key, QString::fromStdString(val ? "true" : "false"), false);
+ };
+
+ auto appendArray = [&appendItem](const QString &key, const QStringList &vals) {
+ QString finalString;
+ foreach (const QString &value, vals) {
+ finalString.append("\"").append(value).append("\"").append(",");
+ }
+ finalString.remove(finalString.length() - 1, 1);
+ finalString.prepend("[ ").append(" ]");
+ appendItem(key, finalString, false);
+ };
+
+ auto startObject = [&ts, &indentationLevel](const QString &objectName) {
+ ts << Qt::endl
+ << QString(" ").repeated(indentationLevel * 4) << objectName << " {" << Qt::endl;
+ indentationLevel++;
+ };
+
+ auto endObject = [&ts, &indentationLevel]() {
+ indentationLevel--;
+ ts << QString(" ").repeated(indentationLevel * 4) << "}" << Qt::endl;
+ };
+
+ auto appendDirectories =
+ [&startObject, &endObject, &appendString, &filesConfig](const QString &jsonKey,
+ const QString &qmlKey) {
+ QJsonValue dirsObj = filesConfig[jsonKey].toObject()["directories"];
+ QStringList dirs = dirsObj.toVariant().toStringList();
+ foreach (const QString &directory, dirs) {
+ startObject(qmlKey);
+ appendString("directory", directory);
+ endObject();
+ }
+ };
+
+ auto appendFiles = [&startObject,
+ &endObject,
+ &appendString,
+ &appendArray,
+ &filesConfig](const QString &jsonKey, const QString &qmlKey) {
+ QJsonValue dirsObj = filesConfig[jsonKey].toObject()["directories"];
+ QJsonValue filesObj = filesConfig[jsonKey].toObject()["files"];
+ QJsonValue filtersObj = filesConfig[jsonKey].toObject()["filters"];
+
+ foreach (const QString &directory, dirsObj.toVariant().toStringList()) {
+ startObject(qmlKey);
+ appendString("directory", directory);
+ appendString("filters", filtersObj.toVariant().toStringList().join(";"));
+
+ if (!filesObj.toArray().isEmpty()) {
+ QStringList fileList;
+ foreach (const QJsonValue &file, filesObj.toArray()) {
+ fileList.append(file.toObject()["name"].toString());
+ }
+ appendArray("files", fileList);
+ }
+ endObject();
+ }
+ };
+
+ // start creating the file content
+ appendComment("prop: json-converted");
+ appendComment("prop: auto-generated");
+
+ ts << Qt::endl << "import QmlProject" << Qt::endl;
+ {
+ startObject("Project");
+
+ { // append non-object props
+ appendString("mainFile", runConfig["mainFile"].toString());
+ appendString("mainUiFile", runConfig["mainUiFile"].toString());
+ appendString("targetDirectory", deploymentConfig["targetDirectory"].toString());
+ appendBool("widgetApp", runConfig["widgetApp"].toBool());
+ appendArray("importPaths", rootObject["importPaths"].toVariant().toStringList());
+ appendBreak();
+ appendString("qdsVersion", versionConfig["designStudio"].toString());
+ appendString("quickVersion", versionConfig["qtQuick"].toString());
+ appendBool("qt6Project", versionConfig["qt"].toString() == "6");
+ appendBool("qtForMCUs", rootObject["mcuConfig"].toObject().isEmpty());
+ appendBreak();
+ appendBool("multilanguageSupport", languageConfig["multiLanguageSupport"].toBool());
+ appendString("primaryLanguage", languageConfig["primaryLanguage"].toString());
+ appendArray("supportedLanguages",
+ languageConfig["supportedLanguages"].toVariant().toStringList());
+ }
+
+ { // append Environment object
+ startObject("Environment");
+ foreach (const QString &key, environmentConfig.keys()) {
+ appendItem(key, environmentConfig[key].toString(), true);
+ }
+ endObject();
+ }
+
+ { // append ShaderTool object
+ startObject("ShaderTool");
+ appendString("args", shaderConfig["args"].toVariant().toStringList().join(" "));
+ appendArray("files", shaderConfig["files"].toVariant().toStringList());
+ endObject();
+ }
+
+ { // append files objects
+ appendDirectories("qml", "QmlFiles");
+ appendDirectories("javaScript", "JavaScriptFiles");
+ appendDirectories("image", "ImageFiles");
+ appendFiles("config", "Files");
+ appendFiles("font", "Files");
+ appendFiles("meshes", "Files");
+ appendFiles("qmldir", "Files");
+ appendFiles("shader", "Files");
+ appendFiles("sound", "Files");
+ appendFiles("video", "Files");
+ }
+
+ endObject(); // Closing 'Project'
+ }
+ return qmlProjectString;
+}
+
+QJsonObject qmlProjectTojson(const Utils::FilePath &projectFile)
+{
+ QmlJS::SimpleReader simpleQmlJSReader;
+
+ const QmlJS::SimpleReaderNode::Ptr rootNode = simpleQmlJSReader.readFile(projectFile.toString());
+
+ if (!simpleQmlJSReader.errors().isEmpty() || !rootNode->isValid()) {
+ qCritical() << "Unable to parse:" << projectFile;
+ qCritical() << simpleQmlJSReader.errors();
+ return {};
+ }
+
+ if (rootNode->name() != QLatin1String("Project")) {
+ qCritical() << "Cannot find root 'Proejct' item in the project file: " << projectFile;
+ return {};
+ }
+
+ auto nodeToJsonObject = [](const QmlJS::SimpleReaderNode::Ptr &node) {
+ QJsonObject tObj;
+ foreach (const QString &childPropName, node->propertyNames()) {
+ tObj.insert(childPropName, node->property(childPropName).value.toJsonValue());
+ }
+ return tObj;
+ };
+
+ auto toCamelCase = [](const QString &s) { return QString(s).replace(0, 1, s[0].toLower()); };
+
+ QJsonObject rootObject; // root object
+ QJsonObject fileGroupsObject;
+ QJsonObject languageObject;
+ QJsonObject versionObject;
+ QJsonObject runConfigObject;
+ QJsonObject deploymentObject;
+ QJsonObject mcuObject;
+ QJsonObject shaderToolObject;
+
+ // convert the the non-object props
+ for (const QString &propName : rootNode->propertyNames()) {
+ QJsonObject *currentObj = &rootObject;
+ QString objKey = propName;
+ QJsonValue value = rootNode->property(propName).value.toJsonValue();
+
+ if (propName.contains("language", Qt::CaseInsensitive)) {
+ currentObj = &languageObject;
+ if (propName.toLower() == "multilanguagesupport") // fixing the camelcase
+ objKey = "multiLanguageSupport";
+ } else if (propName.contains("version", Qt::CaseInsensitive)) {
+ currentObj = &versionObject;
+ if (propName.toLower() == "qdsversion")
+ objKey = "designStudio";
+ else if (propName.toLower() == "quickversion")
+ objKey = "qtQuick";
+ } else if (propName.contains("widgetapp", Qt::CaseInsensitive)
+ || propName.contains("fileselector", Qt::CaseInsensitive)
+ || propName.contains("mainfile", Qt::CaseInsensitive)
+ || propName.contains("mainuifile", Qt::CaseInsensitive)
+ || propName.contains("forcefreetype", Qt::CaseInsensitive)) {
+ currentObj = &runConfigObject;
+ } else if (propName.contains("targetdirectory", Qt::CaseInsensitive)) {
+ currentObj = &deploymentObject;
+ } else if (propName.contains("qtformcus", Qt::CaseInsensitive)) {
+ currentObj = &mcuObject;
+ objKey = "mcuEnabled";
+ } else if (propName.contains("qt6project", Qt::CaseInsensitive)) {
+ currentObj = &versionObject;
+ objKey = "qt";
+ value = rootNode->property(propName).value.toBool() ? "6" : "5";
+ }
+
+ currentObj->insert(objKey, value);
+ }
+
+ // add missing non-object props if any
+ if (!runConfigObject.contains("fileSelectors")) {
+ runConfigObject.insert("fileSelectors", QJsonArray{});
+ }
+
+ if (!versionObject.contains("qt")) {
+ versionObject.insert("qt", "5");
+ }
+
+ // convert the the object props
+ for (const QmlJS::SimpleReaderNode::Ptr &childNode : rootNode->children()) {
+ if (childNode->name().contains("files", Qt::CaseInsensitive)) {
+ PropsPair propsPair;
+ FileProps fileProps;
+ const QString childNodeName = childNode->name().toLower();
+ const QmlJS::SimpleReaderNode::Property childNodeFilter = childNode->property("filter");
+ const QmlJS::SimpleReaderNode::Property childNodeDirectory = childNode->property("directory");
+ const QmlJS::SimpleReaderNode::Property childNodeFiles = childNode->property("files");
+ const QString childNodeFilterValue = childNodeFilter.value.toString();
+
+ if (childNodeName == "qmlfiles" || childNodeFilterValue.contains("*.qml")) {
+ propsPair = fileProps.qml;
+ } else if (childNodeName == "javascriptfiles") {
+ propsPair = fileProps.javaScr;
+ } else if (childNodeName == "imagefiles") {
+ propsPair = fileProps.image;
+ } else {
+ if (childNodeFilter.isValid()) {
+ if (childNodeFilterValue.contains(".conf"))
+ propsPair = fileProps.config;
+ else if (childNodeFilterValue.contains(".ttf"))
+ propsPair = fileProps.font;
+ else if (childNodeFilterValue.contains("qmldir"))
+ propsPair = fileProps.qmlDir;
+ else if (childNodeFilterValue.contains(".wav"))
+ propsPair = fileProps.sound;
+ else if (childNodeFilterValue.contains(".mp4"))
+ propsPair = fileProps.video;
+ else if (childNodeFilterValue.contains(".mesh"))
+ propsPair = fileProps.mesh;
+ else if (childNodeFilterValue.contains(".glsl"))
+ propsPair = fileProps.shader;
+ else if (childNodeFilterValue.contains(".css"))
+ propsPair = fileProps.styling;
+ }
+ }
+
+ // get all objects we'll work on
+ QJsonObject targetObject = fileGroupsObject[propsPair.first].toObject();
+ QJsonArray directories = targetObject["directories"].toArray();
+ QJsonArray filters = targetObject["filters"].toArray();
+ QJsonArray files = targetObject["files"].toArray();
+
+ // populate & update filters
+ if (filters.isEmpty()) {
+ filters = QJsonArray::fromStringList(propsPair.second); // populate the filters with the predefined ones
+ }
+
+ if (childNodeFilter.isValid()) { // append filters from qmlproject (merge)
+ const QStringList filtersFromProjectFile = childNodeFilterValue.split(
+ ";");
+ for (const QString &filter : filtersFromProjectFile) {
+ if (!filters.contains(QJsonValue(filter))) {
+ filters.append(QJsonValue(filter));
+ }
+ }
+ }
+
+ // populate & update directories
+ if (childNodeDirectory.isValid()) {
+ directories.append(childNodeDirectory.value.toJsonValue());
+ }
+ if (directories.isEmpty())
+ directories.append(".");
+
+ // populate & update files
+ if (childNodeFiles.isValid()) {
+ foreach (const QJsonValue &file, childNodeFiles.value.toJsonArray()) {
+ files.append(QJsonObject{{"name", file.toString()}});
+ }
+ }
+
+ // put everything back into the root object
+ targetObject.insert("directories", directories);
+ targetObject.insert("filters", filters);
+ targetObject.insert("files", files);
+ fileGroupsObject.insert(propsPair.first, targetObject);
+ } else if (childNode->name().contains("shadertool", Qt::CaseInsensitive)) {
+ QStringList quotedArgs = childNode->property("args").value.toString().split('\"', Qt::SkipEmptyParts);
+ QStringList args;
+ for (int i = 0; i < quotedArgs.size(); ++i) {
+ // Each odd arg in this list is a single quoted argument, which we should
+ // not be split further
+ if (i % 2 == 0)
+ args.append(quotedArgs[i].trimmed().split(' '));
+ else
+ args.append(quotedArgs[i].prepend("\"").append("\""));
+ }
+
+ shaderToolObject.insert("args", QJsonArray::fromStringList(args));
+ shaderToolObject.insert("files", childNode->property("files").value.toJsonValue());
+ } else {
+ rootObject.insert(toCamelCase(childNode->name()), nodeToJsonObject(childNode));
+ }
+ }
+
+ rootObject.insert("fileGroups", fileGroupsObject);
+ rootObject.insert("language", languageObject);
+ rootObject.insert("versions", versionObject);
+ rootObject.insert("runConfig", runConfigObject);
+ rootObject.insert("deployment", deploymentObject);
+ rootObject.insert("mcuConfig", mcuObject);
+ rootObject.insert("shaderTool", shaderToolObject);
+ rootObject.insert("fileVersion", 1);
+ return rootObject;
+}
+} // namespace QmlProjectManager::Converters
diff --git a/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.h b/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.h
new file mode 100644
index 00000000000..b0bb98895e8
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/converters.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include <QJsonObject>
+#include <QString>
+
+#include <utils/environment.h>
+#include <qmljs/qmljssimplereader.h>
+
+#include <QJsonArray>
+
+namespace QmlProjectManager::Converters {
+
+QString jsonToQmlProject(const QJsonObject &rootObject);
+QJsonObject qmlProjectTojson(const Utils::FilePath &projectFile);
+
+} // namespace QmlProjectManager::Converters
diff --git a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp b/src/plugins/qmlprojectmanager/buildsystem/projectitem/filefilteritems.cpp
index 79b490887e5..9e834891949 100644
--- a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.cpp
+++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/filefilteritems.cpp
@@ -15,36 +15,46 @@
namespace QmlProjectManager {
-FileFilterBaseItem::FileFilterBaseItem()
+FileFilterItem::FileFilterItem(){
+ initTimer();
+}
+
+FileFilterItem::FileFilterItem(const QString &directory, const QStringList &filters)
{
+ setDirectory(directory);
+ setFilters(filters);
+ initTimer();
+}
+
+void FileFilterItem::initTimer(){
m_updateFileListTimer.setSingleShot(true);
m_updateFileListTimer.setInterval(50);
- connect(&m_updateFileListTimer, &QTimer::timeout, this, &FileFilterBaseItem::updateFileListNow);
+ connect(&m_updateFileListTimer, &QTimer::timeout, this, &FileFilterItem::updateFileListNow);
}
-Utils::FileSystemWatcher *FileFilterBaseItem::dirWatcher()
+Utils::FileSystemWatcher *FileFilterItem::dirWatcher()
{
if (!m_dirWatcher) {
m_dirWatcher = new Utils::FileSystemWatcher(1, this); // Separate id, might exceed OS limits.
m_dirWatcher->setObjectName(QLatin1String("FileFilterBaseItemWatcher"));
connect(m_dirWatcher, &Utils::FileSystemWatcher::directoryChanged,
- this, &FileFilterBaseItem::updateFileList);
+ this, &FileFilterItem::updateFileList);
}
return m_dirWatcher;
}
-QStringList FileFilterBaseItem::watchedDirectories() const
+QStringList FileFilterItem::watchedDirectories() const
{
return m_dirWatcher ? m_dirWatcher->directories() : QStringList();
}
-QString FileFilterBaseItem::directory() const
+QString FileFilterItem::directory() const
{
return m_rootDir;
}
-void FileFilterBaseItem::setDirectory(const QString &dirPath)
+void FileFilterItem::setDirectory(const QString &dirPath)
{
if (m_rootDir == dirPath)
return;
@@ -54,7 +64,7 @@ void FileFilterBaseItem::setDirectory(const QString &dirPath)
updateFileList();
}
-void FileFilterBaseItem::setDefaultDirectory(const QString &dirPath)
+void FileFilterItem::setDefaultDirectory(const QString &dirPath)
{
if (m_defaultDir == dirPath)
return;
@@ -63,12 +73,12 @@ void FileFilterBaseItem::setDefaultDirectory(const QString &dirPath)
updateFileListNow();
}
-QString FileFilterBaseItem::filter() const
+QStringList FileFilterItem::filters() const
{
return m_filter;
}
-void FileFilterBaseItem::setFilter(const QString &filter)
+void FileFilterItem::setFilters(const QStringList &filter)
{
if (filter == m_filter)
return;
@@ -77,7 +87,7 @@ void FileFilterBaseItem::setFilter(const QString &filter)
m_regExpList.clear();
m_fileSuffixes.clear();
- for (const QString &pattern : filter.split(QLatin1Char(';'))) {
+ for (const QString &pattern : filter) {
if (pattern.isEmpty())
continue;
// decide if it's a canonical pattern like *.x
@@ -96,7 +106,7 @@ void FileFilterBaseItem::setFilter(const QString &filter)
updateFileList();
}
-bool FileFilterBaseItem::recursive() const
+bool FileFilterItem::recursive() const
{
bool recursive;
if (m_recurse == Recurse) {
@@ -112,7 +122,7 @@ bool FileFilterBaseItem::recursive() const
return recursive;
}
-void FileFilterBaseItem::setRecursive(bool recurse)
+void FileFilterItem::setRecursive(bool recurse)
{
bool oldRecursive = recursive();
@@ -125,18 +135,18 @@ void FileFilterBaseItem::setRecursive(bool recurse)
updateFileList();
}
-QStringList FileFilterBaseItem::pathsProperty() const
+QStringList FileFilterItem::pathsProperty() const
{
return m_explicitFiles;
}
-void FileFilterBaseItem::setPathsProperty(const QStringList &path)
+void FileFilterItem::setPathsProperty(const QStringList &path)
{
m_explicitFiles = path;
updateFileList();
}
-QStringList FileFilterBaseItem::files() const
+QStringList FileFilterItem::files() const
{
return Utils::toList(m_files);
}
@@ -146,7 +156,7 @@ QStringList FileFilterBaseItem::files() const
@param filePath: absolute file path
*/
-bool FileFilterBaseItem::matchesFile(const QString &filePath) const
+bool FileFilterItem::matchesFile(const QString &filePath) const
{
for (const QString &explicitFile : m_explicitFiles) {
if (absolutePath(explicitFile) == filePath)
@@ -167,14 +177,14 @@ bool FileFilterBaseItem::matchesFile(const QString &filePath) const
return false;
}
-QString FileFilterBaseItem::absolutePath(const QString &path) const
+QString FileFilterItem::absolutePath(const QString &path) const
{
if (QFileInfo(path).isAbsolute())
return path;
return QDir(absoluteDir()).absoluteFilePath(path);
}
-QString FileFilterBaseItem::absoluteDir() const
+QString FileFilterItem::absoluteDir() const
{
QString absoluteDir;
if (QFileInfo(m_rootDir).isAbsolute())
@@ -185,13 +195,15 @@ QString FileFilterBaseItem::absoluteDir() const
return QDir::cleanPath(absoluteDir);
}
-void FileFilterBaseItem::updateFileList()
+void FileFilterItem::updateFileList()
{
+#ifndef TESTS_ENABLED_QMLPROJECTITEM
if (!m_updateFileListTimer.isActive())
m_updateFileListTimer.start();
+#endif
}
-void FileFilterBaseItem::updateFileListNow()
+void FileFilterItem::updateFileListNow()
{
if (m_updateFileListTimer.isActive())
m_updateFileListTimer.stop();
@@ -233,7 +245,7 @@ void FileFilterBaseItem::updateFileListNow()
dirWatcher()->addDirectories(Utils::toList(watchDirs), Utils::FileSystemWatcher::WatchAllChanges);
}
-bool FileFilterBaseItem::fileMatches(const QString &fileName) const
+bool FileFilterItem::fileMatches(const QString &fileName) const
{
for (const QString &suffix : std::as_const(m_fileSuffixes)) {
if (fileName.endsWith(suffix, Qt::CaseInsensitive))
@@ -248,7 +260,7 @@ bool FileFilterBaseItem::fileMatches(const QString &fileName) const
return false;
}
-QSet<QString> FileFilterBaseItem::filesInSubTree(const QDir &rootDir, const QDir &dir, QSet<QString> *parsedDirs)
+QSet<QString> FileFilterItem::filesInSubTree(const QDir &rootDir, const QDir &dir, QSet<QString> *parsedDirs)
{
QSet<QString> fileSet;
@@ -270,22 +282,5 @@ QSet<QString> FileFilterBaseItem::filesInSubTree(const QDir &rootDir, const QDir
return fileSet;
}
-ImageFileFilterItem::ImageFileFilterItem()
-{
- QString filter;
- // supported image formats according to
- QList<QByteArray> extensions = QImageReader::supportedImageFormats();
- extensions.append("hdr");
- extensions.append("ktx");
- for (const QByteArray &extension : std::as_const(extensions))
- filter.append(QString::fromLatin1("*.%1;").arg(QString::fromLatin1(extension)));
- setFilter(filter);
-}
-
-FileFilterItem::FileFilterItem(const QString &fileFilter)
-{
- setFilter(fileFilter);
-}
-
} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.h b/src/plugins/qmlprojectmanager/buildsystem/projectitem/filefilteritems.h
index 20f6e83718c..e5e3edb2a32 100644
--- a/src/plugins/qmlprojectmanager/fileformat/filefilteritems.h
+++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/filefilteritems.h
@@ -7,6 +7,7 @@
#include <QRegularExpression>
#include <QSet>
#include <QTimer>
+#include <QJsonArray>
QT_FORWARD_DECLARE_CLASS(QDir)
@@ -14,16 +15,10 @@ namespace Utils { class FileSystemWatcher; }
namespace QmlProjectManager {
-class QmlProjectContentItem : public QObject
-{
- // base class for all elements that should be direct children of Project element
- Q_OBJECT
+using FileFilterItemPtr = std::unique_ptr<class FileFilterItem>;
+using FileFilterItems = std::vector<FileFilterItemPtr>;
-public:
- QmlProjectContentItem() {}
-};
-
-class FileFilterBaseItem : public QmlProjectContentItem {
+class FileFilterItem : public QObject {
Q_OBJECT
Q_PROPERTY(QString directory READ directory WRITE setDirectory NOTIFY directoryChanged)
@@ -33,15 +28,16 @@ class FileFilterBaseItem : public QmlProjectContentItem {
Q_PROPERTY(QStringList files READ files NOTIFY filesChanged DESIGNABLE false)
public:
- FileFilterBaseItem();
+ FileFilterItem();
+ FileFilterItem(const QString &directory, const QStringList &filters);
QString directory() const;
void setDirectory(const QString &directoryPath);
void setDefaultDirectory(const QString &directoryPath);
- QString filter() const;
- void setFilter(const QString &filter);
+ QStringList filters() const;
+ void setFilters(const QStringList &filter);
bool recursive() const;
void setRecursive(bool recursive);
@@ -73,7 +69,7 @@ private:
QString m_rootDir;
QString m_defaultDir;
- QString m_filter;
+ QStringList m_filter;
// simple "*.png" patterns are stored in m_fileSuffixes, otherwise store in m_regExpList
QList<QString> m_fileSuffixes;
QList<QRegularExpression> m_regExpList;
@@ -93,16 +89,7 @@ private:
QTimer m_updateFileListTimer;
friend class ProjectItem;
-};
-
-class FileFilterItem : public FileFilterBaseItem {
-public:
- FileFilterItem(const QString &fileFilter);
-};
-
-class ImageFileFilterItem : public FileFilterBaseItem {
-public:
- ImageFileFilterItem();
+ void initTimer();
};
} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp
new file mode 100644
index 00000000000..5b56c8f37ca
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.cpp
@@ -0,0 +1,402 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "qmlprojectitem.h"
+
+#include <QDir>
+#include <QJsonDocument>
+
+#include "converters.h"
+
+#include <utils/algorithm.h>
+#include <utils/qtcassert.h>
+#include <qmljs/qmljssimplereader.h>
+
+#include <QJsonArray>
+
+namespace QmlProjectManager {
+
+//#define REWRITE_PROJECT_FILE_IN_JSON_FORMAT
+
+QmlProjectItem::QmlProjectItem(const Utils::FilePath &filePath, const bool skipRewrite)
+ : m_projectFile(filePath)
+ , m_skipRewrite(skipRewrite)
+{
+ if (initProjectObject())
+ setupFileFilters();
+}
+
+bool QmlProjectItem::initProjectObject()
+{
+ auto contents = m_projectFile.fileContents();
+ if (!contents) {
+ qWarning() << "Cannot open project file. Path:" << m_projectFile.fileName();
+ return false;
+ }
+
+ QString fileContent{QString::fromUtf8(contents.value())};
+ QJsonObject rootObj;
+ QJsonParseError parseError;
+
+ if (fileContent.contains("import qmlproject", Qt::CaseInsensitive)) {
+ rootObj = Converters::qmlProjectTojson(m_projectFile);
+#ifdef REWRITE_PROJECT_FILE_IN_JSON_FORMAT
+ m_projectFile.writeFileContents(QJsonDocument(rootObj).toJson());
+#endif
+ } else {
+ rootObj
+ = QJsonDocument::fromJson(m_projectFile.fileContents()->data(), &parseError).object();
+ }
+
+ if (rootObj.isEmpty()) {
+ if (parseError.error != QJsonParseError::NoError) {
+ qWarning() << "Cannot parse the json formatted project file. Error:"
+ << parseError.errorString();
+ } else {
+ qWarning() << "Cannot convert QmlProject to Json.";
+ }
+ return false;
+ }
+
+ m_project = rootObj;
+ return true;
+}
+
+void QmlProjectItem::setupFileFilters()
+{
+ auto setupFileFilterItem = [this](const QJsonObject &fileGroup) {
+ for (const QString &directory : fileGroup["directories"].toVariant().toStringList()) {
+ std::unique_ptr<FileFilterItem> fileFilterItem{new FileFilterItem};
+
+ QStringList filesArr;
+ for (const QJsonValue &file : fileGroup["files"].toArray()) {
+ filesArr.append(file["name"].toString());
+ }
+
+ fileFilterItem->setDirectory(directory);
+ fileFilterItem->setFilters(fileGroup["filters"].toVariant().toStringList());
+ fileFilterItem->setRecursive(fileGroup["recursive"].toBool(true));
+ fileFilterItem->setPathsProperty(fileGroup["directories"].toVariant().toStringList());
+ fileFilterItem->setPathsProperty(filesArr);
+ fileFilterItem->setDefaultDirectory(m_projectFile.parentDir().toString());
+#ifndef TESTS_ENABLED_QMLPROJECTITEM
+ connect(fileFilterItem.get(),
+ &FileFilterItem::filesChanged,
+ this,
+ &QmlProjectItem::qmlFilesChanged);
+#endif
+ m_content.push_back(std::move(fileFilterItem));
+ };
+ };
+
+ QJsonObject fileGroups = m_project["fileGroups"].toObject();
+ for (const QString &groupName : fileGroups.keys()) {
+ setupFileFilterItem(fileGroups[groupName].toObject());
+ }
+}
+
+Utils::FilePath QmlProjectItem::sourceDirectory() const
+{
+ return m_projectFile.parentDir();
+}
+
+QString QmlProjectItem::targetDirectory() const
+{
+ return m_project["deployment"].toObject()["targetDirectory"].toString();
+}
+
+bool QmlProjectItem::isQt4McuProject() const
+{
+ return m_project["mcuConfig"].toObject()["mcuEnabled"].toBool();
+}
+
+Utils::EnvironmentItems QmlProjectItem::environment() const
+{
+ Utils::EnvironmentItems envItems;
+ QJsonObject envVariables = m_project["environment"].toObject();
+ foreach (const QString &variableName, envVariables.keys()) {
+ envItems.append(Utils::EnvironmentItem(variableName, envVariables[variableName].toString()));
+ }
+ return envItems;
+}
+
+void QmlProjectItem::addToEnviroment(const QString &key, const QString &value)
+{
+ QJsonObject envVariables = m_project["environment"].toObject();
+ envVariables.insert(key, value);
+ insertAndUpdateProjectFile("environment", envVariables);
+}
+
+QJsonObject QmlProjectItem::project() const
+{
+ return m_project;
+}
+
+QString QmlProjectItem::versionQt() const
+{
+ return m_project["versions"].toObject()["qt"].toString();
+}
+
+void QmlProjectItem::setVersionQt(const QString &version)
+{
+ QJsonObject targetObj = m_project["versions"].toObject();
+ targetObj["qt"] = version;
+ insertAndUpdateProjectFile("versions", targetObj);
+}
+
+QString QmlProjectItem::versionQtQuick() const
+{
+ return m_project["versions"].toObject()["qtQuick"].toString();
+}
+
+void QmlProjectItem::setVersionQtQuick(const QString &version)
+{
+ QJsonObject targetObj = m_project["versions"].toObject();
+ targetObj["qtQuick"] = version;
+ insertAndUpdateProjectFile("versions", targetObj);
+}
+
+QString QmlProjectItem::versionDesignStudio() const
+{
+ return m_project["versions"].toObject()["designStudio"].toString();
+}
+
+void QmlProjectItem::setVersionDesignStudio(const QString &version)
+{
+ QJsonObject targetObj = m_project["versions"].toObject();
+ targetObj["designStudio"] = version;
+ insertAndUpdateProjectFile("versions", targetObj);
+}
+
+QStringList QmlProjectItem::importPaths() const
+{
+ return m_project["importPaths"].toVariant().toStringList();
+}
+
+void QmlProjectItem::setImportPaths(const QStringList &importPaths)
+{
+ insertAndUpdateProjectFile("importPaths", QJsonArray::fromStringList(importPaths));
+}
+
+void QmlProjectItem::addImportPath(const QString &importPath)
+{
+ QJsonArray importPaths = m_project["importPaths"].toArray();
+
+ if (importPaths.contains(importPath))
+ return;
+
+ importPaths.append(importPath);
+ insertAndUpdateProjectFile("importPaths", importPaths);
+}
+
+QStringList QmlProjectItem::fileSelectors() const
+{
+ return m_project["runConfig"].toObject()["fileSelectors"].toVariant().toStringList();
+}
+
+void QmlProjectItem::setFileSelectors(const QStringList &selectors)
+{
+ QJsonObject targetObj = m_project["runConfig"].toObject();
+ targetObj["fileSelectors"] = QJsonArray::fromStringList(selectors);
+ insertAndUpdateProjectFile("runConfig", targetObj);
+}
+
+void QmlProjectItem::addFileSelector(const QString &selector)
+{
+ QJsonObject targetObj = m_project["runConfig"].toObject();
+ QJsonArray fileSelectors = targetObj["fileSelectors"].toArray();
+
+ if (fileSelectors.contains(selector))
+ return;
+
+ fileSelectors.append(selector);
+ targetObj["fileSelectors"] = fileSelectors;
+ insertAndUpdateProjectFile("runConfig", targetObj);
+}
+
+bool QmlProjectItem::multilanguageSupport() const
+{
+ return m_project["language"].toObject()["multiLanguageSupport"].toBool();
+}
+
+void QmlProjectItem::setMultilanguageSupport(const bool &isEnabled)
+{
+ QJsonObject targetObj = m_project["language"].toObject();
+ targetObj["multiLanguageSupport"] = isEnabled;
+ insertAndUpdateProjectFile("language", targetObj);
+}
+
+QStringList QmlProjectItem::supportedLanguages() const
+{
+ return m_project["language"].toObject()["supportedLanguages"].toVariant().toStringList();
+}
+
+void QmlProjectItem::setSupportedLanguages(const QStringList &languages)
+{
+ QJsonObject targetObj = m_project["language"].toObject();
+ targetObj["supportedLanguages"] = QJsonArray::fromStringList(languages);
+ insertAndUpdateProjectFile("language", targetObj);
+}
+
+void QmlProjectItem::addSupportedLanguage(const QString &language)
+{
+ QJsonObject targetObj = m_project["language"].toObject();
+ QJsonArray suppLangs = targetObj["supportedLanguages"].toArray();
+
+ if (suppLangs.contains(language))
+ return;
+
+ suppLangs.append(language);
+ targetObj["supportedLanguages"] = suppLangs;
+ insertAndUpdateProjectFile("language", targetObj);
+}
+
+QString QmlProjectItem::primaryLanguage() const
+{
+ return m_project["language"].toObject()["primaryLanguage"].toString();
+}
+
+void QmlProjectItem::setPrimaryLanguage(const QString &language)
+{
+ QJsonObject targetObj = m_project["language"].toObject();
+ targetObj["primaryLanguage"] = language;
+ insertAndUpdateProjectFile("language", targetObj);
+}
+
+Utils::FilePaths QmlProjectItem::files() const
+{
+ QSet<QString> filesSet;
+ for (const auto &fileFilter : m_content) {
+ const QStringList fileList = fileFilter->files();
+ for (const QString &file : fileList) {
+ filesSet.insert(file);
+ }
+ }
+
+ Utils::FilePaths files;
+ for (const auto &fileName : filesSet) {
+ files.append(Utils::FilePath::fromString(fileName));
+ }
+
+ return files;
+}
+
+/**
+ Check whether the project would include a file path
+ - regardless whether the file already exists or not.
+
+ @param filePath: absolute file path to check
+ */
+bool QmlProjectItem::matchesFile(const QString &filePath) const
+{
+ return Utils::contains(m_content, [&filePath](const auto &fileFilter) {
+ return fileFilter->matchesFile(filePath);
+ });
+}
+
+bool QmlProjectItem::forceFreeType() const
+{
+ return m_project["runConfig"].toObject()["forceFreeType"].toBool();
+}
+
+void QmlProjectItem::setForceFreeType(const bool &isForced)
+{
+ QJsonObject runConfig = m_project["runConfig"].toObject();
+ runConfig["forceFreeType"] = isForced;
+ insertAndUpdateProjectFile("runConfig", runConfig);
+}
+
+void QmlProjectItem::setMainFile(const QString &mainFile)
+{
+ QJsonObject runConfig = m_project["runConfig"].toObject();
+ runConfig["mainFile"] = mainFile;
+ insertAndUpdateProjectFile("runConfig", runConfig);
+}
+
+QString QmlProjectItem::mainFile() const
+{
+ return m_project["runConfig"].toObject()["mainFile"].toString();
+}
+
+void QmlProjectItem::setMainUiFile(const QString &mainUiFile)
+{
+ QJsonObject runConfig = m_project["runConfig"].toObject();
+ runConfig["mainUiFile"] = mainUiFile;
+ insertAndUpdateProjectFile("runConfig", runConfig);
+}
+
+QString QmlProjectItem::mainUiFile() const
+{
+ return m_project["runConfig"].toObject()["mainUiFile"].toString();
+}
+
+bool QmlProjectItem::widgetApp() const
+{
+ return m_project["runConfig"].toObject()["widgetApp"].toBool();
+}
+
+void QmlProjectItem::setWidgetApp(const bool &widgetApp)
+{
+ QJsonObject runConfig = m_project["runConfig"].toObject();
+ runConfig["widgetApp"] = widgetApp;
+ insertAndUpdateProjectFile("runConfig", runConfig);
+}
+
+QStringList QmlProjectItem::shaderToolArgs() const
+{
+ return m_project["shaderTool"].toObject()["args"].toVariant().toStringList();
+}
+
+void QmlProjectItem::setShaderToolArgs(const QStringList &args)
+{
+ QJsonObject shaderTool = m_project["shaderTool"].toObject();
+ shaderTool["args"] = QJsonArray::fromStringList(args);
+ insertAndUpdateProjectFile("shaderTool", shaderTool);
+}
+
+void QmlProjectItem::addShaderToolArg(const QString &arg)
+{
+ QJsonObject targetObj = m_project["shaderTool"].toObject();
+ QJsonArray toolArgs = targetObj["args"].toArray();
+
+ if (toolArgs.contains(arg))
+ return;
+
+ toolArgs.append(arg);
+ targetObj["args"] = toolArgs;
+ insertAndUpdateProjectFile("shaderTool", targetObj);
+}
+
+QStringList QmlProjectItem::shaderToolFiles() const
+{
+ return m_project.value("shaderTool").toObject().value("files").toVariant().toStringList();
+}
+
+void QmlProjectItem::setShaderToolFiles(const QStringList &files)
+{
+ QJsonObject shaderTool = m_project["shaderTool"].toObject();
+ shaderTool["files"] = QJsonArray::fromStringList(files);
+ insertAndUpdateProjectFile("shaderTool", shaderTool);
+}
+
+void QmlProjectItem::addShaderToolFile(const QString &file)
+{
+ QJsonObject targetObj = m_project["shaderTool"].toObject();
+ QJsonArray toolArgs = targetObj["files"].toArray();
+
+ if (toolArgs.contains(file))
+ return;
+
+ toolArgs.append(file);
+ targetObj["files"] = toolArgs;
+ insertAndUpdateProjectFile("shaderTool", targetObj);
+}
+
+void QmlProjectItem::insertAndUpdateProjectFile(const QString &key, const QJsonValue &value)
+{
+ m_project[key] = value;
+ if (!m_skipRewrite)
+ m_projectFile.writeFileContents(Converters::jsonToQmlProject(m_project).toUtf8());
+}
+
+} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h
new file mode 100644
index 00000000000..83ef5ca0000
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h
@@ -0,0 +1,116 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "filefilteritems.h"
+
+#include <utils/environment.h>
+
+#include <QObject>
+#include <QSet>
+#include <QStringList>
+#include <QSharedPointer>
+#include <QJsonObject>
+
+#include <memory>
+#include <vector>
+
+namespace QmlJS {
+class SimpleReaderNode;
+}
+
+namespace QmlProjectManager {
+
+class QmlProjectItem : public QObject
+{
+ Q_OBJECT
+public:
+ explicit QmlProjectItem(const Utils::FilePath &filePath, const bool skipRewrite = false);
+
+ bool isQt4McuProject() const;
+
+
+ QString versionQt() const;
+ void setVersionQt(const QString &version);
+
+ QString versionQtQuick() const;
+ void setVersionQtQuick(const QString &version);
+
+ QString versionDesignStudio() const;
+ void setVersionDesignStudio(const QString &version);
+
+ Utils::FilePath sourceDirectory() const;
+ QString targetDirectory() const;
+
+ QStringList importPaths() const;
+ void setImportPaths(const QStringList &paths);
+ void addImportPath(const QString &importPath);
+
+ QStringList fileSelectors() const;
+ void setFileSelectors(const QStringList &selectors);
+ void addFileSelector(const QString &selector);
+
+ bool multilanguageSupport() const;
+ void setMultilanguageSupport(const bool &isEnabled);
+
+ QStringList supportedLanguages() const;
+ void setSupportedLanguages(const QStringList &languages);
+ void addSupportedLanguage(const QString &language);
+
+ QString primaryLanguage() const;
+ void setPrimaryLanguage(const QString &language);
+
+ Utils::FilePaths files() const;
+ bool matchesFile(const QString &filePath) const;
+
+ bool forceFreeType() const;
+ void setForceFreeType(const bool &isForced);
+
+ void setMainFile(const QString &mainFile);
+ QString mainFile() const;
+
+ void setMainUiFile(const QString &mainUiFile);
+ QString mainUiFile() const;
+
+ bool widgetApp() const;
+ void setWidgetApp(const bool &widgetApp);
+
+ QStringList shaderToolArgs() const;
+ void setShaderToolArgs(const QStringList &args);
+ void addShaderToolArg(const QString &arg);
+
+ QStringList shaderToolFiles() const;
+ void setShaderToolFiles(const QStringList &files);
+ void addShaderToolFile(const QString &file);
+
+ Utils::EnvironmentItems environment() const;
+ void addToEnviroment(const QString &key, const QString &value);
+
+ QJsonObject project() const;
+
+signals:
+ void qmlFilesChanged(const QSet<QString> &, const QSet<QString> &);
+
+private:
+ typedef QSharedPointer<QmlProjectItem> ShrdPtrQPI;
+ typedef std::unique_ptr<FileFilterItem> UnqPtrFFBI;
+ typedef std::unique_ptr<FileFilterItem> UnqPtrFFI;
+
+ // files & props
+ std::vector<std::unique_ptr<FileFilterItem>> m_content; // content property
+
+ // runtime variables
+ Utils::FilePath m_projectFile; // design studio project file
+ QJsonObject m_project; // root project object
+ const bool m_skipRewrite;
+
+ // initializing functions
+ bool initProjectObject();
+ void setupFileFilters();
+
+ // file update functions
+ void insertAndUpdateProjectFile(const QString &key, const QJsonValue &value);
+};
+
+} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp b/src/plugins/qmlprojectmanager/buildsystem/projectnode/qmlprojectnodes.cpp
index a561758acfa..78b03ea7bbd 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectnodes.cpp
+++ b/src/plugins/qmlprojectmanager/buildsystem/projectnode/qmlprojectnodes.cpp
@@ -10,8 +10,7 @@
using namespace ProjectExplorer;
-namespace QmlProjectManager {
-namespace Internal {
+namespace QmlProjectManager::Internal {
QmlProjectNode::QmlProjectNode(Project *project)
: ProjectNode(project->projectDirectory())
@@ -21,5 +20,4 @@ QmlProjectNode::QmlProjectNode(Project *project)
setIcon(DirectoryIcon(":/projectexplorer/images/fileoverlay_qml.png"));
}
-} // namespace Internal
} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/qmlprojectnodes.h b/src/plugins/qmlprojectmanager/buildsystem/projectnode/qmlprojectnodes.h
index 5f676cf432b..5f676cf432b 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectnodes.h
+++ b/src/plugins/qmlprojectmanager/buildsystem/projectnode/qmlprojectnodes.h
diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp
new file mode 100644
index 00000000000..86645dc8c50
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.cpp
@@ -0,0 +1,598 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "qmlbuildsystem.h"
+#include "qmlprojectconstants.h"
+
+#include <QtCore5Compat/qtextcodec.h>
+#include <qmljs/qmljsmodelmanagerinterface.h>
+
+#include <coreplugin/actionmanager/actioncontainer.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/documentmanager.h>
+#include <coreplugin/editormanager/documentmodel.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/editormanager/ieditor.h>
+#include <coreplugin/icontext.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/messagemanager.h>
+
+#include <extensionsystem/iplugin.h>
+#include <extensionsystem/pluginmanager.h>
+#include <extensionsystem/pluginspec.h>
+
+#include <projectexplorer/deploymentdata.h>
+#include <projectexplorer/devicesupport/idevice.h>
+#include <projectexplorer/kitinformation.h>
+#include <projectexplorer/kitmanager.h>
+#include <projectexplorer/projectexplorerconstants.h>
+#include <projectexplorer/session.h>
+#include <projectexplorer/target.h>
+
+#include "projectitem/qmlprojectitem.h"
+#include "projectnode/qmlprojectnodes.h"
+
+#include "utils/algorithm.h"
+#include "utils/qtcassert.h"
+
+#include "texteditor/textdocument.h"
+
+using namespace ProjectExplorer;
+namespace QmlProjectManager {
+
+namespace {
+Q_LOGGING_CATEGORY(infoLogger, "QmlProjectManager.QmlBuildSystem", QtInfoMsg)
+}
+
+ExtensionSystem::IPlugin *findMcuSupportPlugin()
+{
+ const ExtensionSystem::PluginSpec *pluginSpec = Utils::findOrDefault(
+ ExtensionSystem::PluginManager::plugins(),
+ Utils::equal(&ExtensionSystem::PluginSpec::name, QString("McuSupport")));
+
+ if (pluginSpec)
+ return pluginSpec->plugin();
+ return nullptr;
+}
+
+void updateMcuBuildStep(Target *target, bool mcuEnabled)
+{
+ if (auto plugin = findMcuSupportPlugin()) {
+ QMetaObject::invokeMethod(
+ plugin,
+ "updateDeployStep",
+ Qt::DirectConnection,
+ Q_ARG(ProjectExplorer::Target*, target),
+ Q_ARG(bool, mcuEnabled));
+ } else if (mcuEnabled) {
+ qWarning() << "Failed to find McuSupport plugin but qtForMCUs is enabled in the project";
+ }
+}
+
+QmlBuildSystem::QmlBuildSystem(Target *target)
+ : BuildSystem(target)
+{
+ // refresh first - project information is used e.g. to decide the default RC's
+ refresh(RefreshOptions::Project);
+
+ updateDeploymentData();
+ registerMenuButtons();
+
+ connect(target->project(), &Project::activeTargetChanged, [this](Target *target) {
+ refresh(RefreshOptions::NoFileRefresh);
+ updateMcuBuildStep(target, qtForMCUs());
+ });
+ connect(target->project(), &Project::projectFileIsDirty, [this]() {
+ refresh(RefreshOptions::Project);
+ updateMcuBuildStep(project()->activeTarget(), qtForMCUs());
+ });
+
+ // FIXME: Check. Probably bogus after the BuildSystem move.
+ // // addedTarget calls updateEnabled on the runconfigurations
+ // // which needs to happen after refresh
+ // foreach (Target *t, targets())
+ // addedTarget(t);
+}
+
+void QmlBuildSystem::updateDeploymentData()
+{
+ if (!m_projectItem)
+ return;
+
+ if (DeviceTypeKitAspect::deviceTypeId(kit())
+ == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
+ return;
+ }
+
+ ProjectExplorer::DeploymentData deploymentData;
+ for (const auto &file : m_projectItem->files()) {
+ deploymentData.addFile(file, targetFile(file).parentDir().toString());
+ }
+
+ setDeploymentData(deploymentData);
+}
+
+void QmlBuildSystem::registerMenuButtons()
+{
+ Core::ActionContainer *menu = Core::ActionManager::actionContainer(Core::Constants::M_FILE);
+
+ // QML Project file update button
+ // This button saves the current configuration into the .qmlproject file
+ auto action = new QAction("Update QmlProject File", this);
+ Core::Command *cmd = Core::ActionManager::registerAction(action, "QmlProject.ProjectManager");
+ menu->addAction(cmd, Core::Constants::G_FILE_SAVE);
+ QObject::connect(action, &QAction::triggered, this, &QmlBuildSystem::updateProjectFile);
+}
+
+bool QmlBuildSystem::updateProjectFile()
+{
+ qDebug() << "debug#1-mainfilepath" << mainFilePath();
+
+ QFile file(mainFilePath().fileName().append("project-test"));
+ if (file.open(QIODevice::ReadWrite | QIODevice::Truncate)) {
+ qCritical() << "Cannot open Qml Project file for editing!";
+ return false;
+ }
+
+ QTextStream ts(&file);
+ // License
+ ts << "/* "
+ "File generated by Qt Creator"
+ "Copyright (C) 2016 The Qt Company Ltd."
+ "SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH "
+ "Qt-GPL-exception-1.0"
+ "*/"
+ << Qt::endl
+ << Qt::endl;
+
+ // Components
+ ts << "import QmlProject 1.1" << Qt::endl << Qt::endl;
+
+ return true;
+}
+
+void QmlBuildSystem::triggerParsing()
+{
+ refresh(RefreshOptions::Project);
+}
+
+Utils::FilePath QmlBuildSystem::canonicalProjectDir() const
+{
+ return BuildSystem::target()
+ ->project()
+ ->projectFilePath()
+ .canonicalPath()
+ .normalizedPathName()
+ .parentDir();
+}
+
+void QmlBuildSystem::refresh(RefreshOptions options)
+{
+ ParseGuard guard = guardParsingRun();
+ switch (options) {
+ case RefreshOptions::NoFileRefresh:
+ break;
+ case RefreshOptions::Project:
+ initProjectItem();
+ [[fallthrough]];
+ case RefreshOptions::Files:
+ parseProjectFiles();
+ }
+
+ auto modelManager = QmlJS::ModelManagerInterface::instance();
+ if (!modelManager)
+ return;
+
+ QmlJS::ModelManagerInterface::ProjectInfo projectInfo
+ = modelManager->defaultProjectInfoForProject(project(),
+ project()->files(Project::HiddenRccFolders));
+ const QStringList searchPaths = makeAbsolute(canonicalProjectDir(), customImportPaths());
+ for (const QString &searchPath : searchPaths)
+ projectInfo.importPaths.maybeInsert(Utils::FilePath::fromString(searchPath),
+ QmlJS::Dialect::Qml);
+
+ modelManager->updateProjectInfo(projectInfo, project());
+
+ guard.markAsSuccess();
+
+ emit projectChanged();
+}
+
+void QmlBuildSystem::initProjectItem()
+{
+ m_projectItem.reset(new QmlProjectItem{projectFilePath()});
+ connect(m_projectItem.get(),
+ &QmlProjectItem::qmlFilesChanged,
+ this,
+ &QmlBuildSystem::refreshFiles);
+}
+
+void QmlBuildSystem::parseProjectFiles()
+{
+ if (auto modelManager = QmlJS::ModelManagerInterface::instance()) {
+ modelManager->updateSourceFiles(m_projectItem->files(), true);
+ }
+
+
+ Utils::FilePath mainFilePath{Utils::FilePath::fromString(m_projectItem->mainFile())};
+ if (!mainFilePath.isEmpty()) {
+ mainFilePath = canonicalProjectDir().resolvePath(m_projectItem->mainFile());
+ Utils::FileReader reader;
+ QString errorMessage;
+ if (!reader.fetch(mainFilePath, &errorMessage)) {
+ Core::MessageManager::writeFlashing(
+ tr("Warning while loading project file %1.").arg(projectFilePath().toUserOutput()));
+ Core::MessageManager::writeSilently(errorMessage);
+ }
+ }
+
+ generateProjectTree();
+}
+
+void QmlBuildSystem::generateProjectTree()
+{
+ auto newRoot = std::make_unique<Internal::QmlProjectNode>(project());
+
+ for (const auto &file : m_projectItem->files()) {
+ const FileType fileType = (file == projectFilePath())
+ ? FileType::Project
+ : FileNode::fileTypeForFileName(file);
+ newRoot->addNestedNode(std::make_unique<FileNode>(file, fileType));
+ }
+ newRoot->addNestedNode(std::make_unique<FileNode>(projectFilePath(), FileType::Project));
+
+ setRootProjectNode(std::move(newRoot));
+ updateDeploymentData();
+}
+
+bool QmlBuildSystem::setFileSettingInProjectFile(const QString &setting,
+ const Utils::FilePath &mainFilePath,
+ const QString &oldFile)
+{
+ // make sure to change it also in the qmlproject file
+ const Utils::FilePath qmlProjectFilePath = project()->projectFilePath();
+ Core::FileChangeBlocker fileChangeBlocker(qmlProjectFilePath);
+ const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(
+ qmlProjectFilePath);
+ TextEditor::TextDocument *document = nullptr;
+ if (!editors.isEmpty()) {
+ document = qobject_cast<TextEditor::TextDocument *>(editors.first()->document());
+ if (document && document->isModified())
+ if (!Core::DocumentManager::saveDocument(document))
+ return false;
+ }
+
+ QString fileContent;
+ QString error;
+ Utils::TextFileFormat textFileFormat;
+ const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8
+ Utils::TextFileFormat::ReadResult readResult = Utils::TextFileFormat::readFile(qmlProjectFilePath,
+ codec,
+ &fileContent,
+ &textFileFormat,
+ &error);
+ if (readResult != Utils::TextFileFormat::ReadSuccess) {
+ qWarning() << "Failed to read file" << qmlProjectFilePath << ":" << error;
+ }
+
+ const QString settingQmlCode = setting + ":";
+
+ const Utils::FilePath projectDir = project()->projectFilePath().parentDir();
+ const QString relativePath = mainFilePath.relativeChildPath(projectDir).path();
+
+ if (fileContent.indexOf(settingQmlCode) < 0) {
+ QString addedText = QString("\n %1 \"%2\"\n").arg(settingQmlCode).arg(relativePath);
+ auto index = fileContent.lastIndexOf("}");
+ fileContent.insert(index, addedText);
+ } else {
+ QString originalFileName = oldFile;
+ originalFileName.replace(".", "\\.");
+ const QRegularExpression expression(
+ QString("%1\\s*\"(%2)\"").arg(settingQmlCode).arg(originalFileName));
+
+ const QRegularExpressionMatch match = expression.match(fileContent);
+
+ fileContent.replace(match.capturedStart(1), match.capturedLength(1), relativePath);
+ }
+
+ if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error))
+ qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error;
+
+ refresh(RefreshOptions::Project);
+ return true;
+}
+
+bool QmlBuildSystem::blockFilesUpdate() const
+{
+ return m_blockFilesUpdate;
+}
+
+void QmlBuildSystem::setBlockFilesUpdate(bool newBlockFilesUpdate)
+{
+ m_blockFilesUpdate = newBlockFilesUpdate;
+}
+
+Utils::FilePath QmlBuildSystem::mainFilePath() const
+{
+ return projectDirectory().pathAppended(mainFile());
+}
+
+Utils::FilePath QmlBuildSystem::mainUiFilePath() const
+{
+ return projectDirectory().pathAppended(mainUiFile());
+}
+
+bool QmlBuildSystem::setMainFileInProjectFile(const Utils::FilePath &newMainFilePath)
+{
+ return setFileSettingInProjectFile("mainFile", newMainFilePath, mainFile());
+}
+
+bool QmlBuildSystem::setMainUiFileInProjectFile(const Utils::FilePath &newMainUiFilePath)
+{
+ return setMainUiFileInMainFile(newMainUiFilePath)
+ && setFileSettingInProjectFile("mainUiFile", newMainUiFilePath, m_projectItem->mainUiFile());
+}
+
+bool QmlBuildSystem::setMainUiFileInMainFile(const Utils::FilePath &newMainUiFilePath)
+{
+ Core::FileChangeBlocker fileChangeBlocker(mainFilePath());
+ const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(mainFilePath());
+ TextEditor::TextDocument *document = nullptr;
+ if (!editors.isEmpty()) {
+ document = qobject_cast<TextEditor::TextDocument *>(editors.first()->document());
+ if (document && document->isModified())
+ if (!Core::DocumentManager::saveDocument(document))
+ return false;
+ }
+
+ QString fileContent;
+ QString error;
+ Utils::TextFileFormat textFileFormat;
+ const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8
+ if (Utils::TextFileFormat::readFile(mainFilePath(), codec, &fileContent, &textFileFormat, &error)
+ != Utils::TextFileFormat::ReadSuccess) {
+ qWarning() << "Failed to read file" << mainFilePath() << ":" << error;
+ }
+
+ const QString currentMain = QString("%1 {").arg(mainUiFilePath().baseName());
+ const QString newMain = QString("%1 {").arg(newMainUiFilePath.baseName());
+
+ if (fileContent.contains(currentMain))
+ fileContent.replace(currentMain, newMain);
+
+ if (!textFileFormat.writeFile(mainFilePath(), fileContent, &error))
+ qWarning() << "Failed to write file" << mainFilePath() << ":" << error;
+
+ return true;
+}
+
+Utils::FilePath QmlBuildSystem::targetDirectory() const
+{
+ if (DeviceTypeKitAspect::deviceTypeId(kit()) == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)
+ return canonicalProjectDir();
+
+ return m_projectItem ? Utils::FilePath::fromString(m_projectItem->targetDirectory())
+ : Utils::FilePath();
+}
+
+Utils::FilePath QmlBuildSystem::targetFile(const Utils::FilePath &sourceFile) const
+{
+ const QDir sourceDir(m_projectItem ? m_projectItem->sourceDirectory().path()
+ : canonicalProjectDir().toString());
+ const QDir targetDir(targetDirectory().toString());
+ const QString relative = sourceDir.relativeFilePath(sourceFile.toString());
+ return Utils::FilePath::fromString(QDir::cleanPath(targetDir.absoluteFilePath(relative)));
+}
+
+void QmlBuildSystem::setSupportedLanguages(QStringList languages)
+{
+ m_projectItem->setSupportedLanguages(languages);
+}
+
+void QmlBuildSystem::setPrimaryLanguage(QString language)
+{
+ m_projectItem->setPrimaryLanguage(language);
+}
+
+QStringList QmlBuildSystem::makeAbsolute(const Utils::FilePath &path,
+ const QStringList &relativePaths)
+{
+ if (path.isEmpty())
+ return relativePaths;
+
+ const QDir baseDir(path.toString());
+ return Utils::transform(relativePaths, [&baseDir](const QString &path) {
+ return QDir::cleanPath(baseDir.absoluteFilePath(path));
+ });
+}
+
+void QmlBuildSystem::refreshFiles(const QSet<QString> & /*added*/, const QSet<QString> &removed)
+{
+ if (m_blockFilesUpdate) {
+ qCDebug(infoLogger) << "Auto files refresh blocked.";
+ return;
+ }
+ refresh(RefreshOptions::Files);
+ if (!removed.isEmpty()) {
+ if (auto modelManager = QmlJS::ModelManagerInterface::instance()) {
+ modelManager->removeFiles(
+ Utils::transform<QList<Utils::FilePath>>(removed, [](const QString &s) {
+ return Utils::FilePath::fromString(s);
+ }));
+ }
+ }
+ updateDeploymentData();
+}
+
+QVariant QmlBuildSystem::additionalData(Utils::Id id) const
+{
+ if (id == Constants::customFileSelectorsData)
+ return customFileSelectors();
+ if (id == Constants::supportedLanguagesData)
+ return supportedLanguages();
+ if (id == Constants::primaryLanguageData)
+ return primaryLanguage();
+ if (id == Constants::customForceFreeTypeData)
+ return forceFreeType();
+ if (id == Constants::customQtForMCUs)
+ return qtForMCUs();
+ if (id == Constants::customQt6Project)
+ return qt6Project();
+ if (id == Constants::mainFilePath)
+ return mainFilePath().toString();
+ if (id == Constants::customImportPaths)
+ return customImportPaths();
+ if (id == Constants::canonicalProjectDir)
+ return canonicalProjectDir().toString();
+ return {};
+}
+
+bool QmlBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const
+{
+ if (dynamic_cast<Internal::QmlProjectNode *>(context)) {
+ if (action == AddNewFile || action == EraseFile)
+ return true;
+ QTC_ASSERT(node, return false);
+
+ if (action == Rename && node->asFileNode()) {
+ const FileNode *fileNode = node->asFileNode();
+ QTC_ASSERT(fileNode, return false);
+ return fileNode->fileType() != FileType::Project;
+ }
+ return false;
+ }
+ return BuildSystem::supportsAction(context, action, node);
+}
+
+bool QmlBuildSystem::addFiles(Node *context, const Utils::FilePaths &filePaths, Utils::FilePaths *)
+{
+ if (!dynamic_cast<Internal::QmlProjectNode *>(context))
+ return false;
+
+ Utils::FilePaths toAdd;
+ for (const Utils::FilePath &filePath : filePaths) {
+ if (!m_projectItem->matchesFile(filePath.toString()))
+ toAdd << filePaths;
+ }
+ return toAdd.isEmpty();
+}
+
+bool QmlBuildSystem::deleteFiles(Node *context, const Utils::FilePaths &filePaths)
+{
+ if (dynamic_cast<Internal::QmlProjectNode *>(context))
+ return true;
+
+ return BuildSystem::deleteFiles(context, filePaths);
+}
+
+bool QmlBuildSystem::renameFile(Node *context,
+ const Utils::FilePath &oldFilePath,
+ const Utils::FilePath &newFilePath)
+{
+ if (dynamic_cast<Internal::QmlProjectNode *>(context)) {
+ if (oldFilePath.endsWith(mainFile()))
+ return setMainFileInProjectFile(newFilePath);
+ if (oldFilePath.endsWith(m_projectItem->mainUiFile()))
+ return setMainUiFileInProjectFile(newFilePath);
+ return true;
+ }
+
+ return BuildSystem::renameFile(context, oldFilePath, newFilePath);
+}
+
+QString QmlBuildSystem::mainFile() const
+{
+ return m_projectItem->mainFile();
+}
+
+QString QmlBuildSystem::mainUiFile() const
+{
+ return m_projectItem->mainUiFile();
+}
+
+bool QmlBuildSystem::qtForMCUs() const
+{
+ return m_projectItem->isQt4McuProject();
+}
+
+bool QmlBuildSystem::qt6Project() const
+{
+ return m_projectItem->versionQt() == "6";
+}
+
+Utils::EnvironmentItems QmlBuildSystem::environment() const
+{
+ return m_projectItem->environment();
+}
+
+QStringList QmlBuildSystem::customImportPaths() const
+{
+ return m_projectItem->importPaths();
+}
+
+QStringList QmlBuildSystem::customFileSelectors() const
+{
+ return m_projectItem->fileSelectors();
+}
+
+bool QmlBuildSystem::multilanguageSupport() const
+{
+ return m_projectItem->multilanguageSupport();
+}
+
+QStringList QmlBuildSystem::supportedLanguages() const
+{
+ return m_projectItem->supportedLanguages();
+}
+
+QString QmlBuildSystem::primaryLanguage() const
+{
+ return m_projectItem->primaryLanguage();
+}
+
+bool QmlBuildSystem::forceFreeType() const
+{
+ return m_projectItem->forceFreeType();
+}
+
+bool QmlBuildSystem::widgetApp() const
+{
+ return m_projectItem->widgetApp();
+}
+
+QStringList QmlBuildSystem::shaderToolArgs() const
+{
+ return m_projectItem->shaderToolArgs();
+}
+
+QStringList QmlBuildSystem::shaderToolFiles() const
+{
+ return m_projectItem->shaderToolFiles();
+}
+
+QStringList QmlBuildSystem::importPaths() const
+{
+ return m_projectItem->importPaths();
+}
+
+Utils::FilePaths QmlBuildSystem::files() const
+{
+ return m_projectItem->files();
+}
+
+QString QmlBuildSystem::versionQt() const
+{
+ return m_projectItem->versionQt();
+}
+
+QString QmlBuildSystem::versionQtQuick() const
+{
+ return m_projectItem->versionQtQuick();
+}
+
+QString QmlBuildSystem::versionDesignStudio() const
+{
+ return m_projectItem->versionDesignStudio();
+}
+
+} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.h b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.h
new file mode 100644
index 00000000000..d275481f537
--- /dev/null
+++ b/src/plugins/qmlprojectmanager/buildsystem/qmlbuildsystem.h
@@ -0,0 +1,120 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "../qmlprojectmanager_global.h"
+#include <projectexplorer/buildsystem.h>
+
+namespace QmlProjectManager {
+
+class QmlProject;
+class QmlProjectItem;
+class QmlProjectFile;
+
+class QMLPROJECTMANAGER_EXPORT QmlBuildSystem : public ProjectExplorer::BuildSystem
+{
+ Q_OBJECT
+
+public:
+ explicit QmlBuildSystem(ProjectExplorer::Target *target);
+ ~QmlBuildSystem() = default;
+
+ void triggerParsing() final;
+
+ bool supportsAction(ProjectExplorer::Node *context,
+ ProjectExplorer::ProjectAction action,
+ const ProjectExplorer::Node *node) const override;
+ bool addFiles(ProjectExplorer::Node *context,
+ const Utils::FilePaths &filePaths,
+ Utils::FilePaths *notAdded = nullptr) override;
+ bool deleteFiles(ProjectExplorer::Node *context, const Utils::FilePaths &filePaths) override;
+ bool renameFile(ProjectExplorer::Node *context,
+ const Utils::FilePath &oldFilePath,
+ const Utils::FilePath &newFilePath) override;
+
+ bool updateProjectFile();
+
+ QString name() const override { return QLatin1String("qml"); }
+
+ QmlProject *qmlProject() const;
+
+ QVariant additionalData(Utils::Id id) const override;
+
+ enum class RefreshOptions {
+ NoFileRefresh,
+ Files,
+ Project,
+ };
+
+ void refresh(RefreshOptions options);
+
+ bool setMainFileInProjectFile(const Utils::FilePath &newMainFilePath);
+ bool setMainUiFileInProjectFile(const Utils::FilePath &newMainUiFilePath);
+ bool setMainUiFileInMainFile(const Utils::FilePath &newMainUiFilePath);
+
+ Utils::FilePath canonicalProjectDir() const;
+ QString mainFile() const;
+ QString mainUiFile() const;
+ Utils::FilePath mainFilePath() const;
+ Utils::FilePath mainUiFilePath() const;
+
+ bool qtForMCUs() const;
+ bool qt6Project() const;
+
+ Utils::FilePath targetDirectory() const;
+ Utils::FilePath targetFile(const Utils::FilePath &sourceFile) const;
+
+ Utils::EnvironmentItems environment() const;
+ QStringList customImportPaths() const;
+ QStringList customFileSelectors() const;
+ bool multilanguageSupport() const;
+ QStringList supportedLanguages() const;
+ void setSupportedLanguages(QStringList languages);
+ QString primaryLanguage() const;
+ void setPrimaryLanguage(QString language);
+ bool forceFreeType() const;
+ bool widgetApp() const;
+ QStringList shaderToolArgs() const;
+ QStringList shaderToolFiles() const;
+ QStringList importPaths() const;
+ Utils::FilePaths files() const;
+
+ QString versionQt() const;
+ QString versionQtQuick() const;
+ QString versionDesignStudio() const;
+
+ bool addFiles(const QStringList &filePaths);
+ void refreshProjectFile();
+
+ static Utils::FilePath activeMainFilePath();
+ static QStringList makeAbsolute(const Utils::FilePath &path, const QStringList &relativePaths);
+
+ void refreshFiles(const QSet<QString> &added, const QSet<QString> &removed);
+
+ bool blockFilesUpdate() const;
+ void setBlockFilesUpdate(bool newBlockFilesUpdate);
+
+signals:
+ void projectChanged();
+
+private:
+ bool setFileSettingInProjectFile(const QString &setting,
+ const Utils::FilePath &mainFilePath,
+ const QString &oldFile);
+
+ QSharedPointer<QmlProjectItem> m_projectItem;
+ bool m_blockFilesUpdate = false;
+
+ void initProjectItem();
+ void parseProjectFiles();
+ void generateProjectTree();
+
+ void registerMenuButtons();
+ void updateDeploymentData();
+ friend class FilesUpdateBlocker;
+};
+
+} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp
deleted file mode 100644
index 27e5809f943..00000000000
--- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.cpp
+++ /dev/null
@@ -1,198 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "qmlprojectfileformat.h"
-
-#include "filefilteritems.h"
-#include "qmlprojectitem.h"
-#include "../qmlprojectmanagertr.h"
-
-#include <qmljs/qmljssimplereader.h>
-
-#include <utils/filepath.h>
-
-#include <QDebug>
-#include <QVariant>
-
-#include <memory>
-
-using namespace Utils;
-
-enum {
- debug = false
-};
-
-namespace {
-
-std::unique_ptr<QmlProjectManager::FileFilterBaseItem> setupFileFilterItem(
- std::unique_ptr<QmlProjectManager::FileFilterBaseItem> fileFilterItem,
- const QmlJS::SimpleReaderNode::Ptr &node)
-{
- const auto directoryProperty = node->property(QLatin1String("directory"));
- if (directoryProperty.isValid())
- fileFilterItem->setDirectory(directoryProperty.value.toString());
-
- const auto recursiveProperty = node->property(QLatin1String("recursive"));
- if (recursiveProperty.isValid())
- fileFilterItem->setRecursive(recursiveProperty.value.toBool());
-
- const auto pathsProperty = node->property(QLatin1String("paths"));
- if (pathsProperty.isValid())
- fileFilterItem->setPathsProperty(pathsProperty.value.toStringList());
-
- // "paths" and "files" have the same functionality
- const auto filesProperty = node->property(QLatin1String("files"));
- if (filesProperty.isValid())
- fileFilterItem->setPathsProperty(filesProperty.value.toStringList());
-
- const auto filterProperty = node->property(QLatin1String("filter"));
- if (filterProperty.isValid())
- fileFilterItem->setFilter(filterProperty.value.toString());
-
- if (debug)
- qDebug() << "directory:" << directoryProperty.value << "recursive" << recursiveProperty.value
- << "paths" << pathsProperty.value << "files" << filesProperty.value;
- return fileFilterItem;
-}
-
-} //namespace
-
-namespace QmlProjectManager {
-
-std::unique_ptr<QmlProjectItem> QmlProjectFileFormat::parseProjectFile(const Utils::FilePath &fileName,
- QString *errorMessage)
-{
- QmlJS::SimpleReader simpleQmlJSReader;
-
- const QmlJS::SimpleReaderNode::Ptr rootNode = simpleQmlJSReader.readFile(fileName.toString());
-
- if (!simpleQmlJSReader.errors().isEmpty() || !rootNode->isValid()) {
- qWarning() << "unable to parse:" << fileName;
- qWarning() << simpleQmlJSReader.errors();
- if (errorMessage)
- *errorMessage = simpleQmlJSReader.errors().join(QLatin1String(", "));
- return nullptr;
- }
-
- if (rootNode->name() == QLatin1String("Project")) {
- auto projectItem = std::make_unique<QmlProjectItem>();
-
- const auto mainFileProperty = rootNode->property(QLatin1String("mainFile"));
- if (mainFileProperty.isValid())
- projectItem->setMainFile(mainFileProperty.value.toString());
-
- const auto mainUiFileProperty = rootNode->property(QLatin1String("mainUiFile"));
- if (mainUiFileProperty.isValid())
- projectItem->setMainUiFile(mainUiFileProperty.value.toString());
-
- const auto importPathsProperty = rootNode->property(QLatin1String("importPaths"));
- if (importPathsProperty.isValid()) {
- QStringList list = importPathsProperty.value.toStringList();
- list.removeAll(".");
- projectItem->setImportPaths(list);
- }
-
- const auto fileSelectorsProperty = rootNode->property(QLatin1String("fileSelectors"));
- if (fileSelectorsProperty.isValid())
- projectItem->setFileSelectors(fileSelectorsProperty.value.toStringList());
-
- const auto multilanguageSupportProperty = rootNode->property(
- QLatin1String("multilanguageSupport"));
- if (multilanguageSupportProperty.isValid())
- projectItem->setMultilanguageSupport(multilanguageSupportProperty.value.toBool());
-
- const auto languagesProperty = rootNode->property(QLatin1String("supportedLanguages"));
- if (languagesProperty.isValid())
- projectItem->setSupportedLanguages(languagesProperty.value.toStringList());
-
- const auto primaryLanguageProperty = rootNode->property(QLatin1String("primaryLanguage"));
- if (primaryLanguageProperty.isValid())
- projectItem->setPrimaryLanguage(primaryLanguageProperty.value.toString());
-
- const auto forceFreeTypeProperty = rootNode->property("forceFreeType");
- if (forceFreeTypeProperty.isValid())
- projectItem->setForceFreeType(forceFreeTypeProperty.value.toBool());
-
- const auto targetDirectoryPropery = rootNode->property("targetDirectory");
- if (targetDirectoryPropery.isValid())
- projectItem->setTargetDirectory(FilePath::fromSettings(targetDirectoryPropery.value));
-
- const auto qtForMCUProperty = rootNode->property("qtForMCUs");
- if (qtForMCUProperty.isValid() && qtForMCUProperty.value.toBool())
- projectItem->setQtForMCUs(qtForMCUProperty.value.toBool());
-
- const auto qt6ProjectProperty = rootNode->property("qt6Project");
- if (qt6ProjectProperty.isValid() && qt6ProjectProperty.value.toBool())
- projectItem->setQt6Project(qt6ProjectProperty.value.toBool());
-
- const auto widgetAppProperty = rootNode->property("widgetApp");
- if (widgetAppProperty.isValid())
- projectItem->setWidgetApp(widgetAppProperty.value.toBool());
-
- if (debug)
- qDebug() << "importPath:" << importPathsProperty.value << "mainFile:" << mainFileProperty.value;
-
- const QList<QmlJS::SimpleReaderNode::Ptr> childNodes = rootNode->children();
- for (const QmlJS::SimpleReaderNode::Ptr &childNode : childNodes) {
- if (debug)
- qDebug() << "reading type:" << childNode->name();
-
- if (childNode->name() == QLatin1String("QmlFiles")) {
- projectItem->appendContent(
- setupFileFilterItem(std::make_unique<FileFilterItem>("*.qml"), childNode));
- } else if (childNode->name() == QLatin1String("JavaScriptFiles")) {
- projectItem->appendContent(
- setupFileFilterItem(std::make_unique<FileFilterItem>("*.js"), childNode));
- } else if (childNode->name() == QLatin1String("ImageFiles")) {
- projectItem->appendContent(
- setupFileFilterItem(std::make_unique<ImageFileFilterItem>(), childNode));
- } else if (childNode->name() == QLatin1String("CssFiles")) {
- projectItem->appendContent(
- setupFileFilterItem(std::make_unique<FileFilterItem>("*.css"), childNode));
- } else if (childNode->name() == QLatin1String("FontFiles")) {
- projectItem->appendContent(
- setupFileFilterItem(std::make_unique<FileFilterItem>("*.ttf;*.otf"), childNode));
- } else if (childNode->name() == QLatin1String("Files")) {
- projectItem->appendContent(
- setupFileFilterItem(std::make_unique<FileFilterBaseItem>(), childNode));
- } else if (childNode->name() == "Environment") {
- const auto properties = childNode->properties();
- auto i = properties.constBegin();
- while (i != properties.constEnd()) {
- projectItem->addToEnviroment(i.key(), i.value().value.toString());
- ++i;
- }
- } else if (childNode->name() == "ShaderTool") {
- QmlJS::SimpleReaderNode::Property commandLine = childNode->property("args");
- if (commandLine.isValid()) {
- const QStringList quotedArgs = commandLine.value.toString().split('\"');
- QStringList args;
- for (int i = 0; i < quotedArgs.size(); ++i) {
- // Each odd arg in this list is a single quoted argument, which we should
- // not be split further
- if (i % 2 == 0)
- args.append(quotedArgs[i].trimmed().split(' '));
- else
- args.append(quotedArgs[i]);
- }
- args.removeAll({});
- args.append("-o"); // Prepare for adding output file as next arg
- projectItem->setShaderToolArgs(args);
- }
- QmlJS::SimpleReaderNode::Property files = childNode->property("files");
- if (files.isValid())
- projectItem->setShaderToolFiles(files.value.toStringList());
- } else {
- qWarning() << "Unknown type:" << childNode->name();
- }
- }
- return projectItem;
- }
-
- if (errorMessage)
- *errorMessage = Tr::tr("Invalid root element: %1").arg(rootNode->name());
-
- return nullptr;
-}
-
-} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.h b/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.h
deleted file mode 100644
index 72c77999711..00000000000
--- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectfileformat.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include <utils/fileutils.h>
-
-#include <QCoreApplication>
-#include <QString>
-
-namespace QmlProjectManager {
-
-class QmlProjectItem;
-
-class QmlProjectFileFormat
-{
-public:
- static std::unique_ptr<QmlProjectItem> parseProjectFile(const Utils::FilePath &fileName,
- QString *errorMessage = nullptr);
-};
-
-} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp
deleted file mode 100644
index 3cd7c28af24..00000000000
--- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.cpp
+++ /dev/null
@@ -1,118 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#include "qmlprojectitem.h"
-#include "filefilteritems.h"
-
-#include <utils/algorithm.h>
-
-#include <QDir>
-
-using namespace Utils;
-
-namespace QmlProjectManager {
-
-// kind of initialization
-void QmlProjectItem::setSourceDirectory(const FilePath &directoryPath)
-{
- if (m_sourceDirectory == directoryPath)
- return;
-
- m_sourceDirectory = directoryPath;
-
- for (auto &fileFilter : m_content) {
- fileFilter->setDefaultDirectory(directoryPath.toFSPathString());
- connect(fileFilter.get(),
- &FileFilterBaseItem::filesChanged,
- this,
- &QmlProjectItem::qmlFilesChanged);
- }
-}
-
-void QmlProjectItem::setTargetDirectory(const FilePath &directoryPath)
-{
- m_targetDirectory = directoryPath;
-}
-
-void QmlProjectItem::setQtForMCUs(bool b)
-{
- m_qtForMCUs = b;
-}
-
-void QmlProjectItem::setQt6Project(bool qt6Project)
-{
- m_qt6Project = qt6Project;
-}
-
-void QmlProjectItem::setImportPaths(const QStringList &importPaths)
-{
- if (m_importPaths != importPaths)
- m_importPaths = importPaths;
-}
-
-void QmlProjectItem::setFileSelectors(const QStringList &selectors)
-{
- if (m_fileSelectors != selectors)
- m_fileSelectors = selectors;
-}
-
-void QmlProjectItem::setMultilanguageSupport(const bool isEnabled)
-{
- m_multilanguageSupport = isEnabled;
-}
-
-void QmlProjectItem::setSupportedLanguages(const QStringList &languages)
-{
- if (m_supportedLanguages != languages)
- m_supportedLanguages = languages;
-}
-
-void QmlProjectItem::setPrimaryLanguage(const QString &language)
-{
- if (m_primaryLanguage != language)
- m_primaryLanguage = language;
-}
-
-/* Returns list of absolute paths */
-QStringList QmlProjectItem::files() const
-{
- QSet<QString> files;
-
- for (const auto &fileFilter : m_content) {
- const QStringList fileList = fileFilter->files();
- for (const QString &file : fileList) {
- files.insert(file);
- }
- }
- return Utils::toList(files);
-}
-
-/**
- Check whether the project would include a file path
- - regardless whether the file already exists or not.
-
- @param filePath: absolute file path to check
- */
-bool QmlProjectItem::matchesFile(const QString &filePath) const
-{
- return Utils::contains(m_content, [&filePath](const auto &fileFilter) {
- return fileFilter->matchesFile(filePath);
- });
-}
-
-void QmlProjectItem::setForceFreeType(bool b)
-{
- m_forceFreeType = b;
-}
-
-Utils::EnvironmentItems QmlProjectItem::environment() const
-{
- return m_environment;
-}
-
-void QmlProjectItem::addToEnviroment(const QString &key, const QString &value)
-{
- m_environment.append(Utils::EnvironmentItem(key, value));
-}
-
-} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h b/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h
deleted file mode 100644
index f5ac618bf62..00000000000
--- a/src/plugins/qmlprojectmanager/fileformat/qmlprojectitem.h
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "filefilteritems.h"
-
-#include <utils/environment.h>
-#include <utils/filepath.h>
-
-#include <QObject>
-#include <QSet>
-#include <QStringList>
-
-#include <memory>
-#include <vector>
-
-namespace QmlProjectManager {
-
-class QmlProjectItem : public QObject
-{
- Q_OBJECT
-
-public:
- const Utils::FilePath &sourceDirectory() const { return m_sourceDirectory; }
- void setSourceDirectory(const Utils::FilePath &directoryPath);
- const Utils::FilePath &targetDirectory() const { return m_targetDirectory; }
- void setTargetDirectory(const Utils::FilePath &directoryPath);
-
- bool qtForMCUs() const { return m_qtForMCUs; }
- void setQtForMCUs(bool qtForMCUs);
-
- bool qt6Project() const { return m_qt6Project; }
- void setQt6Project(bool qt6Project);
-
- QStringList importPaths() const { return m_importPaths; }
- void setImportPaths(const QStringList &paths);
-
- QStringList fileSelectors() const { return m_fileSelectors; }
- void setFileSelectors(const QStringList &selectors);
-
- bool multilanguageSupport() const { return m_multilanguageSupport; }
- void setMultilanguageSupport(const bool isEnabled);
-
- QStringList supportedLanguages() const { return m_supportedLanguages; }
- void setSupportedLanguages(const QStringList &languages);
-
- QString primaryLanguage() const { return m_primaryLanguage; }
- void setPrimaryLanguage(const QString &language);
-
- QStringList files() const;
- bool matchesFile(const QString &filePath) const;
-
- bool forceFreeType() const { return m_forceFreeType; };
- void setForceFreeType(bool);
-
- QString mainFile() const { return m_mainFile; }
- void setMainFile(const QString &mainFilePath) { m_mainFile = mainFilePath; }
-
- QString mainUiFile() const { return m_mainUiFile; }
- void setMainUiFile(const QString &mainUiFilePath) { m_mainUiFile = mainUiFilePath; }
-
- bool widgetApp() const { return m_widgetApp; }
- void setWidgetApp(bool widgetApp) { m_widgetApp = widgetApp; }
-
- QStringList shaderToolArgs() const { return m_shaderToolArgs; }
- void setShaderToolArgs(const QStringList &args) {m_shaderToolArgs = args; }
-
- QStringList shaderToolFiles() const { return m_shaderToolFiles; }
- void setShaderToolFiles(const QStringList &files) { m_shaderToolFiles = files; }
-
- void appendContent(std::unique_ptr<FileFilterBaseItem> item)
- {
- m_content.push_back(std::move(item));
- }
-
- Utils::EnvironmentItems environment() const;
- void addToEnviroment(const QString &key, const QString &value);
-
-signals:
- void qmlFilesChanged(const QSet<QString> &, const QSet<QString> &);
-
-protected:
- Utils::FilePath m_sourceDirectory;
- Utils::FilePath m_targetDirectory;
- QStringList m_importPaths;
- QStringList m_fileSelectors;
- bool m_multilanguageSupport;
- QStringList m_supportedLanguages;
- QString m_primaryLanguage;
- QString m_mainFile;
- QString m_mainUiFile;
- Utils::EnvironmentItems m_environment;
- std::vector<std::unique_ptr<FileFilterBaseItem>> m_content; // content property
- bool m_forceFreeType = false;
- bool m_qtForMCUs = false;
- bool m_qt6Project = false;
- bool m_widgetApp = false;
- QStringList m_shaderToolArgs;
- QStringList m_shaderToolFiles;
-};
-
-} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/qmlmainfileaspect.cpp b/src/plugins/qmlprojectmanager/qmlmainfileaspect.cpp
index 405e63965fe..5d328fd934a 100644
--- a/src/plugins/qmlprojectmanager/qmlmainfileaspect.cpp
+++ b/src/plugins/qmlprojectmanager/qmlmainfileaspect.cpp
@@ -181,7 +181,7 @@ void QmlMainFileAspect::setScriptSource(MainScriptSource source, const QString &
FilePath QmlMainFileAspect::mainScript() const
{
if (!qmlBuildSystem()->mainFile().isEmpty()) {
- const FilePath pathInProject = qmlBuildSystem()->mainFile();
+ const FilePath pathInProject = qmlBuildSystem()->mainFilePath();
return qmlBuildSystem()->canonicalProjectDir().resolvePath(pathInProject);
}
diff --git a/src/plugins/qmlprojectmanager/qmlproject.cpp b/src/plugins/qmlprojectmanager/qmlproject.cpp
index 77e3cc82d40..ce2f363cd41 100644
--- a/src/plugins/qmlprojectmanager/qmlproject.cpp
+++ b/src/plugins/qmlprojectmanager/qmlproject.cpp
@@ -1,37 +1,27 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#include "qmlproject.h"
-#include "fileformat/qmlprojectfileformat.h"
-#include "fileformat/qmlprojectitem.h"
-#include "qmlprojectconstants.h"
-#include "qmlprojectmanagerconstants.h"
-#include "qmlprojectmanagertr.h"
-#include "qmlprojectnodes.h"
+#include <qtsupport/baseqtversion.h>
+#include <qtsupport/qtkitinformation.h>
+#include <qtsupport/qtsupportconstants.h>
-#include <coreplugin/coreconstants.h>
-#include <coreplugin/documentmanager.h>
-#include <coreplugin/editormanager/documentmodel.h>
-#include <coreplugin/editormanager/editormanager.h>
-#include <coreplugin/editormanager/ieditor.h>
-#include <coreplugin/icontext.h>
-#include <coreplugin/icore.h>
-#include <coreplugin/messagemanager.h>
-#include <coreplugin/modemanager.h>
+#include <QTimer>
-#include <projectexplorer/deploymentdata.h>
-#include <projectexplorer/devicesupport/idevice.h>
-#include <projectexplorer/kitinformation.h>
-#include <projectexplorer/kitmanager.h>
#include <projectexplorer/projectexplorerconstants.h>
#include <projectexplorer/projectmanager.h>
#include <projectexplorer/target.h>
-#include <qtsupport/baseqtversion.h>
-#include <qtsupport/qtkitinformation.h>
-#include <qtsupport/qtsupportconstants.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <coreplugin/icontext.h>
+#include <coreplugin/icore.h>
+#include "projectexplorer/devicesupport/idevice.h"
+#include "qmlprojectconstants.h"
+#include "qmlprojectmanagerconstants.h"
+#include "qmlprojectmanagertr.h"
+#include "utils/algorithm.h"
#include <qmljs/qmljsmodelmanagerinterface.h>
#include <texteditor/textdocument.h>
@@ -50,52 +40,13 @@
using namespace Core;
using namespace ProjectExplorer;
-using namespace QmlProjectManager::Internal;
-using namespace Utils;
-
-namespace {
-Q_LOGGING_CATEGORY(infoLogger, "QmlProjectManager.QmlBuildSystem", QtInfoMsg)
-}
namespace QmlProjectManager {
-
-static int preferedQtTarget(Target *target)
-{
- if (target) {
- const QmlBuildSystem *buildSystem = qobject_cast<QmlBuildSystem *>(target->buildSystem());
- if (buildSystem && buildSystem->qt6Project())
- return 6;
- }
- return 5;
-}
-
-static bool allowOnlySingleProject()
-{
- QSettings *settings = Core::ICore::settings();
- const QString qdsAllowMultipleProjects = "QML/Designer/AllowMultipleProjects";
-
- return !settings->value(qdsAllowMultipleProjects, false).toBool();
-}
-
-Utils::FilePaths QmlProject::collectUiQmlFilesForFolder(const Utils::FilePath &folder) const
-{
- const Utils::FilePaths uiFiles = files([&](const ProjectExplorer::Node *node) {
- return node->filePath().completeSuffix() == "ui.qml"
- && node->filePath().parentDir() == folder;
- });
- return uiFiles;
-}
-
-FilePaths QmlProject::collectQmlFiles() const
-{
- return files([](const Node *node) { return node->filePath().suffix() == "qml"; });
-}
-
QmlProject::QmlProject(const Utils::FilePath &fileName)
: Project(QString::fromLatin1(Constants::QMLPROJECT_MIMETYPE), fileName)
{
setId(QmlProjectManager::Constants::QML_PROJECT_ID);
- setProjectLanguages(Context(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID));
+ setProjectLanguages(Core::Context(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID));
setDisplayName(fileName.completeBaseName());
setNeedsBuildConfigurations(false);
@@ -106,449 +57,122 @@ QmlProject::QmlProject(const Utils::FilePath &fileName)
EditorManager::closeAllDocuments();
ProjectManager::closeAllProjects();
}
-
- m_openFileConnection
- = connect(this,
- &QmlProject::anyParsingFinished,
- this,
- [this](Target *target, bool success) {
- if (m_openFileConnection)
- disconnect(m_openFileConnection);
-
- if (target && success) {
-
- auto target = activeTarget();
- if (!target)
- return;
-
- auto qmlBuildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>(
- target->buildSystem());
-
- const Utils::FilePath mainUiFile = qmlBuildSystem->mainUiFilePath();
-
- if (mainUiFile.completeSuffix() == "ui.qml" && mainUiFile.exists()) {
- QTimer::singleShot(1000, [mainUiFile]() {
- Core::EditorManager::openEditor(mainUiFile,
- Utils::Id());
- });
- } else {
- Utils::FilePaths uiFiles = collectUiQmlFilesForFolder(
- projectDirectory().pathAppended("content"));
- if (uiFiles.isEmpty())
- uiFiles = collectUiQmlFilesForFolder(projectDirectory());
-
- if (uiFiles.isEmpty())
- uiFiles = collectQmlFiles();
-
- if (!uiFiles.isEmpty()) {
- Utils::FilePath currentFile;
- if (auto cd = Core::EditorManager::currentDocument())
- currentFile = cd->filePath();
-
- if (currentFile.isEmpty() || !isKnownFile(currentFile))
- QTimer::singleShot(1000, [uiFiles]() {
- Core::EditorManager::openEditor(uiFiles.first(),
- Utils::Id());
- Core::ModeManager::activateMode(
- Core::Constants::MODE_DESIGN);
- });
- }
- }
- }
- });
}
-}
-
-QmlBuildSystem::QmlBuildSystem(Target *target)
- : BuildSystem(target)
-{
- m_canonicalProjectDir =
- target->project()->projectFilePath().canonicalPath().normalizedPathName().parentDir();
-
- connect(target->project(), &Project::projectFileIsDirty,
- this, &QmlBuildSystem::refreshProjectFile);
-
- // refresh first - project information is used e.g. to decide the default RC's
- refresh(Everything);
-// FIXME: Check. Probably bogus after the BuildSystem move.
-// // addedTarget calls updateEnabled on the runconfigurations
-// // which needs to happen after refresh
-// const QLis<Target> targetList = targets();
-// for (Target *t : targetList)
-// addedTarget(t);
-
- connect(target->project(), &Project::activeTargetChanged,
- this, &QmlBuildSystem::onActiveTargetChanged);
- updateDeploymentData();
+ connect(this, &QmlProject::anyParsingFinished, this, &QmlProject::parsingFinished);
}
-QmlBuildSystem::~QmlBuildSystem() = default;
-
-void QmlBuildSystem::triggerParsing()
+void QmlProject::parsingFinished(const Target *target, bool success)
{
- refresh(Everything);
-}
+ // trigger only once
+ disconnect(this, &QmlProject::anyParsingFinished, this, &QmlProject::parsingFinished);
-void QmlBuildSystem::onActiveTargetChanged(Target *)
-{
- // make sure e.g. the default qml imports are adapted
- refresh(Configuration);
-}
+ // FIXME: what to do in this case?
+ if (!target || !success || !activeTarget())
+ return;
-void QmlBuildSystem::onKitChanged()
-{
- // make sure e.g. the default qml imports are adapted
- refresh(Configuration);
-}
+ auto targetActive = activeTarget();
+ auto qmlBuildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>(
+ targetActive->buildSystem());
-Utils::FilePath QmlBuildSystem::canonicalProjectDir() const
-{
- return m_canonicalProjectDir;
-}
+ const Utils::FilePath mainUiFile = qmlBuildSystem->mainUiFilePath();
-void QmlBuildSystem::parseProject(RefreshOptions options)
-{
- if (options & Files) {
- if (options & ProjectFile)
- m_projectItem.reset();
- if (!m_projectItem) {
- QString errorMessage;
- m_projectItem = QmlProjectFileFormat::parseProjectFile(projectFilePath(), &errorMessage);
- if (m_projectItem) {
- connect(m_projectItem.get(),
- &QmlProjectItem::qmlFilesChanged,
- this,
- &QmlBuildSystem::refreshFiles);
-
- } else {
- MessageManager::writeFlashing(
- Tr::tr("Error while loading project file %1.").arg(projectFilePath().toUserOutput()));
- MessageManager::writeSilently(errorMessage);
- }
- }
- if (m_projectItem) {
- m_projectItem->setSourceDirectory(canonicalProjectDir());
- if (m_projectItem->targetDirectory().isEmpty())
- m_projectItem->setTargetDirectory(canonicalProjectDir());
-
- if (auto modelManager = QmlJS::ModelManagerInterface::instance()) {
- QStringList files = m_projectItem->files();
- modelManager
- ->updateSourceFiles(Utils::transform(files,
- [](const QString &p) {
- return Utils::FilePath::fromString(p);
- }),
- true);
- }
- QString mainFilePath = m_projectItem->mainFile();
- if (!mainFilePath.isEmpty()) {
- mainFilePath
- = QDir(canonicalProjectDir().toString()).absoluteFilePath(mainFilePath);
- Utils::FileReader reader;
- QString errorMessage;
- if (!reader.fetch(Utils::FilePath::fromString(mainFilePath), &errorMessage)) {
- MessageManager::writeFlashing(Tr::tr("Warning while loading project file %1.")
- .arg(projectFilePath().toUserOutput()));
- MessageManager::writeSilently(errorMessage);
- }
- }
- }
- generateProjectTree();
- }
-
- if (options & Configuration) {
- // update configuration
- }
-}
-
-bool QmlBuildSystem::setFileSettingInProjectFile(const QString &setting,
- const FilePath &mainFilePath,
- const FilePath &oldFile)
-{
- // make sure to change it also in the qmlproject file
- const Utils::FilePath qmlProjectFilePath = project()->projectFilePath();
- Core::FileChangeBlocker fileChangeBlocker(qmlProjectFilePath);
- const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(qmlProjectFilePath);
- TextEditor::TextDocument *document = nullptr;
- if (!editors.isEmpty()) {
- document = qobject_cast<TextEditor::TextDocument*>(editors.first()->document());
- if (document && document->isModified())
- if (!Core::DocumentManager::saveDocument(document))
- return false;
+ if (mainUiFile.completeSuffix() == "ui.qml" && mainUiFile.exists()) {
+ QTimer::singleShot(1000, [mainUiFile]() {
+ Core::EditorManager::openEditor(mainUiFile, Utils::Id());
+ });
+ return;
}
- QString fileContent;
- QString error;
- Utils::TextFileFormat textFileFormat;
- const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8
- if (Utils::TextFileFormat::readFile(qmlProjectFilePath, codec, &fileContent, &textFileFormat, &error)
- != Utils::TextFileFormat::ReadSuccess) {
- qWarning() << "Failed to read file" << qmlProjectFilePath << ":" << error;
+ Utils::FilePaths uiFiles = collectUiQmlFilesForFolder(
+ projectDirectory().pathAppended("content"));
+ if (uiFiles.isEmpty()) {
+ uiFiles = collectUiQmlFilesForFolder(projectDirectory());
+ if (uiFiles.isEmpty())
+ return;
}
- const QString settingQmlCode = setting + ":";
-
- const Utils::FilePath projectDir = project()->projectFilePath().parentDir();
- const QString relativePath = mainFilePath.relativeChildPath(projectDir).path();
-
- if (fileContent.indexOf(settingQmlCode) < 0) {
- QString addedText = QString("\n %1 \"%2\"\n").arg(settingQmlCode).arg(relativePath);
- auto index = fileContent.lastIndexOf("}");
- fileContent.insert(index, addedText);
- } else {
- QString originalFileName = oldFile.path();
- originalFileName.replace(".", "\\.");
- const QRegularExpression expression(QString("%1\\s*\"(%2)\"").arg(settingQmlCode).arg(originalFileName));
-
- const QRegularExpressionMatch match = expression.match(fileContent);
+ Utils::FilePath currentFile;
+ if (auto cd = Core::EditorManager::currentDocument())
+ currentFile = cd->filePath();
- fileContent.replace(match.capturedStart(1),
- match.capturedLength(1),
- relativePath);
+ if (currentFile.isEmpty() || !isKnownFile(currentFile)) {
+ QTimer::singleShot(1000, [uiFiles]() {
+ Core::EditorManager::openEditor(uiFiles.first(), Utils::Id());
+ });
}
-
- if (!textFileFormat.writeFile(qmlProjectFilePath, fileContent, &error))
- qWarning() << "Failed to write file" << qmlProjectFilePath << ":" << error;
-
- refresh(Everything);
- return true;
}
-void QmlBuildSystem::refresh(RefreshOptions options)
+Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *errorMessage)
{
- ParseGuard guard = guardParsingRun();
- parseProject(options);
-
- if (options & Files)
- generateProjectTree();
-
- auto modelManager = QmlJS::ModelManagerInterface::instance();
- if (!modelManager)
- return;
-
- QmlJS::ModelManagerInterface::ProjectInfo projectInfo
- = modelManager->defaultProjectInfoForProject(project(),
- project()->files(Project::HiddenRccFolders));
- const QStringList searchPaths = makeAbsolute(canonicalProjectDir(), customImportPaths());
- for (const QString &searchPath : searchPaths)
- projectInfo.importPaths.maybeInsert(Utils::FilePath::fromString(searchPath),
- QmlJS::Dialect::Qml);
-
- modelManager->updateProjectInfo(projectInfo, project());
-
- guard.markAsSuccess();
+ RestoreResult result = Project::fromMap(map, errorMessage);
+ if (result != RestoreResult::Ok)
+ return result;
- emit projectChanged();
-}
+ if (activeTarget())
+ return RestoreResult::Ok;
-FilePath QmlBuildSystem::mainFile() const
-{
- if (m_projectItem)
- return FilePath::fromString(m_projectItem->mainFile());
- return {};
-}
+ // find a kit that matches prerequisites (prefer default one)
+ const QList<Kit *> kits = Utils::filtered(KitManager::kits(), [this](const Kit *k) {
+ return !containsType(projectIssues(k), Task::TaskType::Error)
+ && DeviceTypeKitAspect::deviceTypeId(k)
+ == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
+ });
-FilePath QmlBuildSystem::mainUiFile() const
-{
- if (m_projectItem)
- return FilePath::fromString(m_projectItem->mainUiFile());
- return {};
-}
+ if (!kits.isEmpty()) {
+ if (kits.contains(KitManager::defaultKit()))
+ addTargetForDefaultKit();
+ else
+ addTargetForKit(kits.first());
+ }
-FilePath QmlBuildSystem::mainFilePath() const
-{
- const auto mainFileString = mainFile();
+ // FIXME: are there any other way?
+ // What if it's not a Design Studio project? What should we do then?
+ if (QmlProject::isQtDesignStudio()) {
+ int preferedVersion = preferedQtTarget(activeTarget());
- if (mainFileString.isEmpty())
- return {};
+ setKitWithVersion(preferedVersion, kits);
+ }
- return projectDirectory().resolvePath(mainFileString);
+ return RestoreResult::Ok;
}
-FilePath QmlBuildSystem::mainUiFilePath() const
+bool QmlProject::setKitWithVersion(const int qtMajorVersion, const QList<Kit *> kits)
{
- const auto mainUiFileString = mainUiFile();
-
- if (mainUiFileString.isEmpty())
- return {};
+ const QList<Kit *> qtVersionkits = Utils::filtered(kits, [qtMajorVersion](const Kit *k) {
+ if (!k->isAutoDetected())
+ return false;
- return projectDirectory().resolvePath(mainUiFileString);
-}
+ if (k->isReplacementKit())
+ return false;
-bool QmlBuildSystem::setMainFileInProjectFile(const FilePath &newMainFilePath)
-{
- return setFileSettingInProjectFile("mainFile", newMainFilePath, mainFile());
-}
+ QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(k);
+ return (version && version->qtVersion().majorVersion() == qtMajorVersion);
+ });
-bool QmlBuildSystem::setMainUiFileInProjectFile(const FilePath &newMainUiFilePath)
-{
- return setMainUiFileInMainFile(newMainUiFilePath)
- && setFileSettingInProjectFile("mainUiFile", newMainUiFilePath, mainUiFile());
-}
-bool QmlBuildSystem::setMainUiFileInMainFile(const FilePath &newMainUiFilePath)
-{
- Core::FileChangeBlocker fileChangeBlocker(mainFilePath());
- const QList<Core::IEditor *> editors = Core::DocumentModel::editorsForFilePath(mainFilePath());
- TextEditor::TextDocument *document = nullptr;
- if (!editors.isEmpty()) {
- document = qobject_cast<TextEditor::TextDocument*>(editors.first()->document());
- if (document && document->isModified())
- if (!Core::DocumentManager::saveDocument(document))
- return false;
- }
+ Target *target = nullptr;
- QString fileContent;
- QString error;
- Utils::TextFileFormat textFileFormat;
- const QTextCodec *codec = QTextCodec::codecForName("UTF-8"); // qml files are defined to be utf-8
- if (Utils::TextFileFormat::readFile(mainFilePath(), codec, &fileContent, &textFileFormat, &error)
- != Utils::TextFileFormat::ReadSuccess) {
- qWarning() << "Failed to read file" << mainFilePath() << ":" << error;
+ if (!qtVersionkits.isEmpty()) {
+ if (qtVersionkits.contains(KitManager::defaultKit()))
+ target = addTargetForDefaultKit();
+ else
+ target = addTargetForKit(qtVersionkits.first());
}
- const QString currentMain = QString("%1 {").arg(mainUiFilePath().baseName());
- const QString newMain = QString("%1 {").arg(newMainUiFilePath.baseName());
-
- if (fileContent.contains(currentMain))
- fileContent.replace(currentMain, newMain);
-
- if (!textFileFormat.writeFile(mainFilePath(), fileContent, &error))
- qWarning() << "Failed to write file" << mainFilePath() << ":" << error;
+ if (target)
+ target->project()->setActiveTarget(target, SetActive::NoCascade);
return true;
}
-bool QmlBuildSystem::qtForMCUs() const
-{
- if (m_projectItem)
- return m_projectItem->qtForMCUs();
- return false;
-}
-
-bool QmlBuildSystem::qt6Project() const
-{
- if (m_projectItem)
- return m_projectItem->qt6Project();
- return false;
-}
-
-void QmlBuildSystem::setMainFile(const QString &mainFilePath)
-{
- if (m_projectItem)
- m_projectItem->setMainFile(mainFilePath);
-}
-
-FilePath QmlBuildSystem::targetDirectory() const
-{
- if (DeviceTypeKitAspect::deviceTypeId(kit())
- == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE)
- return canonicalProjectDir();
-
- return m_projectItem ? m_projectItem->targetDirectory() : FilePath();
-}
-
-FilePath QmlBuildSystem::targetFile(const FilePath &sourceFile) const
-{
- const FilePath sourceDir = m_projectItem ? m_projectItem->sourceDirectory()
- : canonicalProjectDir();
- const FilePath targetDir = targetDirectory();
- const FilePath relative = sourceFile.relativePathFrom(sourceDir);
- return targetDir.resolvePath(relative);
-}
-
-Utils::EnvironmentItems QmlBuildSystem::environment() const
-{
- if (m_projectItem)
- return m_projectItem->environment();
- return {};
-}
-
-QStringList QmlBuildSystem::customImportPaths() const
-{
- if (m_projectItem)
- return m_projectItem->importPaths();
- return {};
-}
-
-QStringList QmlBuildSystem::customFileSelectors() const
-{
- if (m_projectItem)
- return m_projectItem->fileSelectors();
- return {};
-}
-
-bool QmlBuildSystem::multilanguageSupport() const
-{
- if (m_projectItem)
- return m_projectItem->multilanguageSupport();
- return false;
-}
-
-QStringList QmlBuildSystem::supportedLanguages() const
-{
- if (m_projectItem)
- return m_projectItem->supportedLanguages();
- return {};
-}
-
-void QmlBuildSystem::setSupportedLanguages(QStringList languages)
-{
- if (m_projectItem)
- m_projectItem->setSupportedLanguages(languages);
-}
-
-QString QmlBuildSystem::primaryLanguage() const
-{
- if (m_projectItem)
- return m_projectItem->primaryLanguage();
- return {};
-}
-
-void QmlBuildSystem::setPrimaryLanguage(QString language)
-{
- if (m_projectItem)
- m_projectItem->setPrimaryLanguage(language);
-}
-
-void QmlBuildSystem::refreshProjectFile()
-{
- refresh(QmlBuildSystem::ProjectFile | Files);
-}
-
-QStringList QmlBuildSystem::makeAbsolute(const Utils::FilePath &path, const QStringList &relativePaths)
+Utils::FilePaths QmlProject::collectUiQmlFilesForFolder(const Utils::FilePath &folder) const
{
- if (path.isEmpty())
- return relativePaths;
-
- const QDir baseDir(path.toString());
- return Utils::transform(relativePaths, [&baseDir](const QString &path) {
- return QDir::cleanPath(baseDir.absoluteFilePath(path));
+ const Utils::FilePaths uiFiles = files([&](const Node *node) {
+ return node->filePath().completeSuffix() == "ui.qml"
+ && node->filePath().parentDir() == folder;
});
-}
-
-void QmlBuildSystem::refreshFiles(const QSet<QString> &/*added*/, const QSet<QString> &removed)
-{
- if (m_blockFilesUpdate) {
- qCDebug(infoLogger) << "Auto files refresh blocked.";
- return;
- }
- refresh(Files);
- if (!removed.isEmpty()) {
- if (auto modelManager = QmlJS::ModelManagerInterface::instance()) {
- modelManager->removeFiles(
- Utils::transform<QList<Utils::FilePath>>(removed, [](const QString &s) {
- return Utils::FilePath::fromString(s);
- }));
- }
- }
- refreshTargetDirectory();
-}
-
-void QmlBuildSystem::refreshTargetDirectory()
-{
- updateDeploymentData();
+ return uiFiles;
}
Tasks QmlProject::projectIssues(const Kit *k) const
@@ -572,8 +196,8 @@ Tasks QmlProject::projectIssues(const Kit *k) const
if (dev->type() == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
if (version->type() == QtSupport::Constants::DESKTOPQT) {
if (version->qmlRuntimeFilePath().isEmpty()) {
- result.append(createProjectTask(Task::TaskType::Error,
- Tr::tr("Qt version has no QML utility.")));
+ result.append(
+ createProjectTask(Task::TaskType::Error, tr("Qt version has no QML utility.")));
}
} else {
// Non-desktop Qt on a desktop device? We don't support that.
@@ -589,68 +213,10 @@ Tasks QmlProject::projectIssues(const Kit *k) const
return result;
}
-bool QmlProject::isEditModePreferred() const
-{
- return !isQtDesignStudio();
-}
-
-Project::RestoreResult QmlProject::fromMap(const QVariantMap &map, QString *errorMessage)
-{
- RestoreResult result = Project::fromMap(map, errorMessage);
- if (result != RestoreResult::Ok)
- return result;
-
- if (!activeTarget()) {
- // find a kit that matches prerequisites (prefer default one)
- const QList<Kit *> kits = Utils::filtered(KitManager::kits(), [this](const Kit *k) {
- return !containsType(projectIssues(k), Task::TaskType::Error)
- && DeviceTypeKitAspect::deviceTypeId(k)
- == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
- });
-
- if (!kits.isEmpty()) {
- if (kits.contains(KitManager::defaultKit()))
- addTargetForDefaultKit();
- else
- addTargetForKit(kits.first());
- }
-
- if (QmlProject::isQtDesignStudio()) {
- auto setKitWithVersion = [&](int qtMajorVersion) {
- const QList<Kit *> qtVersionkits
- = Utils::filtered(kits, [qtMajorVersion](const Kit *k) {
- if (!k->isAutoDetected())
- return false;
- if (k->isReplacementKit())
- return false;
- QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(k);
- return (version && version->qtVersion().majorVersion() == qtMajorVersion);
- });
- if (!qtVersionkits.isEmpty()) {
- if (qtVersionkits.contains(KitManager::defaultKit()))
- addTargetForDefaultKit();
- else
- addTargetForKit(qtVersionkits.first());
- }
- };
-
- int preferedVersion = preferedQtTarget(activeTarget());
-
- if (activeTarget())
- removeTarget(activeTarget());
-
- setKitWithVersion(preferedVersion);
- }
- }
-
- return RestoreResult::Ok;
-}
-
bool QmlProject::isQtDesignStudio()
{
QSettings *settings = Core::ICore::settings();
const QString qdsStandaloneEntry = "QML/Designer/StandAloneMode";
-
return settings->value(qdsStandaloneEntry, false).toBool();
}
@@ -659,172 +225,30 @@ bool QmlProject::isQtDesignStudioStartedFromQtC()
return qEnvironmentVariableIsSet(Constants::enviromentLaunchedQDS);
}
-ProjectExplorer::DeploymentKnowledge QmlProject::deploymentKnowledge() const
+DeploymentKnowledge QmlProject::deploymentKnowledge() const
{
return DeploymentKnowledge::Perfect;
}
-void QmlBuildSystem::generateProjectTree()
-{
- if (!m_projectItem)
- return;
-
- auto newRoot = std::make_unique<QmlProjectNode>(project());
-
- for (const QString &f : m_projectItem->files()) {
- const Utils::FilePath fileName = Utils::FilePath::fromString(f);
- const FileType fileType = (fileName == projectFilePath())
- ? FileType::Project : FileNode::fileTypeForFileName(fileName);
- newRoot->addNestedNode(std::make_unique<FileNode>(fileName, fileType));
- }
- newRoot->addNestedNode(std::make_unique<FileNode>(projectFilePath(), FileType::Project));
-
- setRootProjectNode(std::move(newRoot));
- refreshTargetDirectory();
-}
-
-void QmlBuildSystem::updateDeploymentData()
-{
- if (!m_projectItem)
- return;
-
- if (DeviceTypeKitAspect::deviceTypeId(kit())
- == ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE) {
- return;
- }
-
- ProjectExplorer::DeploymentData deploymentData;
- for (const QString &file : m_projectItem->files()) {
- deploymentData.addFile(
- FilePath::fromString(file),
- targetFile(Utils::FilePath::fromString(file)).parentDir().toString());
- }
-
- setDeploymentData(deploymentData);
-}
-
-QVariant QmlBuildSystem::additionalData(Id id) const
-{
- if (id == Constants::customFileSelectorsData)
- return customFileSelectors();
- if (id == Constants::supportedLanguagesData)
- return supportedLanguages();
- if (id == Constants::primaryLanguageData)
- return primaryLanguage();
- if (id == Constants::customForceFreeTypeData)
- return forceFreeType();
- if (id == Constants::customQtForMCUs)
- return qtForMCUs();
- if (id == Constants::customQt6Project)
- return qt6Project();
- if (id == Constants::mainFilePath)
- return mainFilePath().toString();
- if (id == Constants::customImportPaths)
- return customImportPaths();
- if (id == Constants::canonicalProjectDir)
- return canonicalProjectDir().toString();
- return {};
-}
-
-bool QmlBuildSystem::supportsAction(Node *context, ProjectAction action, const Node *node) const
-{
- if (dynamic_cast<QmlProjectNode *>(context)) {
- if (action == AddNewFile || action == EraseFile)
- return true;
- QTC_ASSERT(node, return false);
-
- if (action == Rename && node->asFileNode()) {
- const FileNode *fileNode = node->asFileNode();
- QTC_ASSERT(fileNode, return false);
- return fileNode->fileType() != FileType::Project;
- }
-
- return false;
- }
-
- return BuildSystem::supportsAction(context, action, node);
-}
-
-QmlProject *QmlBuildSystem::qmlProject() const
-{
- return static_cast<QmlProject *>(BuildSystem::project());
-}
-
-bool QmlBuildSystem::forceFreeType() const
-{
- if (m_projectItem)
- return m_projectItem->forceFreeType();
- return false;
-}
-
-bool QmlBuildSystem::widgetApp() const
-{
- if (m_projectItem)
- return m_projectItem->widgetApp();
- return false;
-}
-
-QStringList QmlBuildSystem::shaderToolArgs() const
-{
- if (m_projectItem)
- return m_projectItem->shaderToolArgs();
- return {};
-}
-
-QStringList QmlBuildSystem::shaderToolFiles() const
-{
- if (m_projectItem)
- return m_projectItem->shaderToolFiles();
- return {};
-}
-
-QStringList QmlBuildSystem::importPaths() const
-{
- if (m_projectItem)
- return m_projectItem->importPaths();
- return {};
-}
-
-QStringList QmlBuildSystem::files() const
-{
- if (m_projectItem)
- return m_projectItem->files();
- return {};
-}
-
-bool QmlBuildSystem::addFiles(Node *context, const FilePaths &filePaths, FilePaths *)
+bool QmlProject::isEditModePreferred() const
{
- if (!dynamic_cast<QmlProjectNode *>(context))
- return false;
-
- FilePaths toAdd;
- for (const FilePath &filePath : filePaths) {
- if (!m_projectItem->matchesFile(filePath.toString()))
- toAdd << filePaths;
- }
- return toAdd.isEmpty();
+ return !isQtDesignStudio();
}
-bool QmlBuildSystem::deleteFiles(Node *context, const FilePaths &filePaths)
+int QmlProject::preferedQtTarget(Target *target)
{
- if (dynamic_cast<QmlProjectNode *>(context))
- return true;
+ if (!target)
+ return -1;
- return BuildSystem::deleteFiles(context, filePaths);
+ auto buildSystem = qobject_cast<QmlBuildSystem *>(target->buildSystem());
+ return (buildSystem && buildSystem->qt6Project()) ? 6 : 5;
}
-bool QmlBuildSystem::renameFile(Node * context, const FilePath &oldFilePath, const FilePath &newFilePath)
+bool QmlProject::allowOnlySingleProject()
{
- if (dynamic_cast<QmlProjectNode *>(context)) {
- if (oldFilePath.endsWith(mainFile().path()))
- return setMainFileInProjectFile(newFilePath);
- if (oldFilePath.endsWith(mainUiFile().path()))
- return setMainUiFileInProjectFile(newFilePath);
-
- return true;
- }
-
- return BuildSystem::renameFile(context, oldFilePath, newFilePath);
+ QSettings *settings = Core::ICore::settings();
+ auto key = "QML/Designer/AllowMultipleProjects";
+ return !settings->value(key, false).toBool();
}
} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/qmlproject.h b/src/plugins/qmlprojectmanager/qmlproject.h
index f00a4f2b36c..3a6d5badf79 100644
--- a/src/plugins/qmlprojectmanager/qmlproject.h
+++ b/src/plugins/qmlprojectmanager/qmlproject.h
@@ -1,150 +1,28 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
#pragma once
+#include "buildsystem/qmlbuildsystem.h" // IWYU pragma: keep
#include "qmlprojectmanager_global.h"
-
-#include <projectexplorer/buildsystem.h>
#include <projectexplorer/project.h>
-#include <utils/environment.h>
-
-#include <QPointer>
-
namespace QmlProjectManager {
class QmlProject;
-class QmlProjectItem;
-
-class QMLPROJECTMANAGER_EXPORT QmlBuildSystem : public ProjectExplorer::BuildSystem
-{
- Q_OBJECT
-
-public:
- explicit QmlBuildSystem(ProjectExplorer::Target *target);
- ~QmlBuildSystem();
-
- void triggerParsing() final;
-
- bool supportsAction(ProjectExplorer::Node *context,
- ProjectExplorer::ProjectAction action,
- const ProjectExplorer::Node *node) const override;
- bool addFiles(ProjectExplorer::Node *context,
- const Utils::FilePaths &filePaths, Utils::FilePaths *notAdded = nullptr) override;
- bool deleteFiles(ProjectExplorer::Node *context,
- const Utils::FilePaths &filePaths) override;
- bool renameFile(ProjectExplorer::Node *context,
- const Utils::FilePath &oldFilePath, const Utils::FilePath &newFilePath) override;
- QString name() const override { return QLatin1String("qml"); }
-
- QmlProject *qmlProject() const;
-
- QVariant additionalData(Utils::Id id) const override;
-
- enum RefreshOption {
- ProjectFile = 0x01,
- Files = 0x02,
- Configuration = 0x04,
- Everything = ProjectFile | Files | Configuration
- };
- Q_DECLARE_FLAGS(RefreshOptions,RefreshOption)
-
- void refresh(RefreshOptions options);
-
- Utils::FilePath canonicalProjectDir() const;
- Utils::FilePath mainFile() const;
- Utils::FilePath mainUiFile() const;
- Utils::FilePath mainFilePath() const;
- Utils::FilePath mainUiFilePath() const;
-
- bool setMainFileInProjectFile(const Utils::FilePath &newMainFilePath);
- bool setMainUiFileInProjectFile(const Utils::FilePath &newMainUiFilePath);
- bool setMainUiFileInMainFile(const Utils::FilePath &newMainUiFilePath);
-
- bool qtForMCUs() const;
- bool qt6Project() const;
- void setMainFile(const QString &mainFilePath);
- Utils::FilePath targetDirectory() const;
- Utils::FilePath targetFile(const Utils::FilePath &sourceFile) const;
-
- Utils::EnvironmentItems environment() const;
- QStringList customImportPaths() const;
- QStringList customFileSelectors() const;
- bool multilanguageSupport() const;
- QStringList supportedLanguages() const;
- void setSupportedLanguages(QStringList languages);
- QString primaryLanguage() const;
- void setPrimaryLanguage(QString language);
- bool forceFreeType() const;
- bool widgetApp() const;
- QStringList shaderToolArgs() const;
- QStringList shaderToolFiles() const;
- QStringList importPaths() const;
- QStringList files() const;
-
- bool addFiles(const QStringList &filePaths);
-
- void refreshProjectFile();
-
- static Utils::FilePath activeMainFilePath();
- static QStringList makeAbsolute(const Utils::FilePath &path, const QStringList &relativePaths);
-
- void generateProjectTree();
- void updateDeploymentData();
- void refreshFiles(const QSet<QString> &added, const QSet<QString> &removed);
- void refreshTargetDirectory();
- void onActiveTargetChanged(ProjectExplorer::Target *target);
- void onKitChanged();
-
- // plain format
- void parseProject(RefreshOptions options);
-
-signals:
- void projectChanged();
-
-private:
- bool setFileSettingInProjectFile(const QString &setting,
- const Utils::FilePath &mainFilePath,
- const Utils::FilePath &oldFile);
-
- std::unique_ptr<QmlProjectItem> m_projectItem;
- Utils::FilePath m_canonicalProjectDir;
- bool m_blockFilesUpdate = false;
- friend class FilesUpdateBlocker;
-};
-
-class FilesUpdateBlocker {
-public:
- FilesUpdateBlocker(QmlBuildSystem* bs): m_bs(bs) {
- if (m_bs)
- m_bs->m_blockFilesUpdate = true;
- }
-
- ~FilesUpdateBlocker() {
- if (m_bs) {
- m_bs->m_blockFilesUpdate = false;
- m_bs->refresh(QmlBuildSystem::Everything);
- }
- }
-private:
- QPointer<QmlBuildSystem> m_bs;
-};
class QMLPROJECTMANAGER_EXPORT QmlProject : public ProjectExplorer::Project
{
Q_OBJECT
-
public:
explicit QmlProject(const Utils::FilePath &filename);
- ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final;
-
static bool isQtDesignStudio();
static bool isQtDesignStudioStartedFromQtC();
-
bool isEditModePreferred() const override;
+ ProjectExplorer::Tasks projectIssues(const ProjectExplorer::Kit *k) const final;
+
protected:
RestoreResult fromMap(const QVariantMap &map, QString *errorMessage) override;
@@ -153,9 +31,35 @@ private:
Utils::FilePaths collectUiQmlFilesForFolder(const Utils::FilePath &folder) const;
Utils::FilePaths collectQmlFiles() const;
- QMetaObject::Connection m_openFileConnection;
+ bool setKitWithVersion(const int qtMajorVersion, const QList<ProjectExplorer::Kit *> kits);
+
+ bool allowOnlySingleProject();
+ int preferedQtTarget(ProjectExplorer::Target *target);
+
+private slots:
+ void parsingFinished(const ProjectExplorer::Target *target, bool success);
};
-} // namespace QmlProjectManager
+class FilesUpdateBlocker
+{
+public:
+ FilesUpdateBlocker(QmlBuildSystem *bs)
+ : m_bs(bs)
+ {
+ if (m_bs)
+ m_bs->m_blockFilesUpdate = true;
+ }
+
+ ~FilesUpdateBlocker()
+ {
+ if (m_bs) {
+ m_bs->m_blockFilesUpdate = false;
+ m_bs->refresh(QmlBuildSystem::RefreshOptions::Project);
+ }
+ }
+
+private:
+ QPointer<QmlBuildSystem> m_bs;
+};
-Q_DECLARE_OPERATORS_FOR_FLAGS(QmlProjectManager::QmlBuildSystem::RefreshOptions)
+} // namespace QmlProjectManager
diff --git a/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs b/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs
index d4938c8d798..e4e4d0bc247 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs
+++ b/src/plugins/qmlprojectmanager/qmlprojectmanager.qbs
@@ -34,12 +34,14 @@ QtcPlugin {
}
Group {
- name: "File Format"
- prefix: "fileformat/"
+ name: "Build System"
+ prefix: "buildsystem/"
files: [
- "filefilteritems.cpp", "filefilteritems.h",
- "qmlprojectfileformat.cpp", "qmlprojectfileformat.h",
- "qmlprojectitem.cpp", "qmlprojectitem.h",
+ "qmlbuildsystem.cpp", "qmlbuildsystem.h",
+ "projectitem/filefilteritems.cpp", "projectitem/filefilteritems.h",
+ "projectitem/qmlprojectitem.cpp", "projectitem/qmlprojectitem.h",
+ "projectitem/converters.h",
+ "projectnode/qmlprojectnodes.cpp", "projectnode/qmlprojectnodes.h"
]
}
@@ -56,7 +58,7 @@ QtcPlugin {
"cmakeprojectconverterdialog.cpp", "cmakeprojectconverterdialog.h",
]
}
-
+
Group {
name: "QML Project File Generator"
prefix: "qmlprojectgen/"
diff --git a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp
index 2ead9de6da9..2876c3c366a 100644
--- a/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp
+++ b/src/plugins/qmlprojectmanager/qmlprojectplugin.cpp
@@ -10,7 +10,6 @@
#include "projectfilecontenttools.h"
#include "cmakegen/cmakeprojectconverter.h"
#include "cmakegen/generatecmakelists.h"
-#include "qmlprojectgen/qmlprojectgenerator.h"
#include <coreplugin/actionmanager/actioncontainer.h>
#include <coreplugin/actionmanager/actionmanager.h>
diff --git a/src/plugins/studiowelcome/examplecheckout.cpp b/src/plugins/studiowelcome/examplecheckout.cpp
index a0e5d07bab6..61a8e429d68 100644
--- a/src/plugins/studiowelcome/examplecheckout.cpp
+++ b/src/plugins/studiowelcome/examplecheckout.cpp
@@ -7,6 +7,8 @@
#include <coreplugin/documentmanager.h>
#include <coreplugin/icore.h>
+#include <designerpaths.h>
+#include <studiosettingspage.h>
#include <qmldesignerbase/qmldesignerbaseplugin.h>
#include <utils/archive.h>
@@ -61,7 +63,7 @@ bool DataModelDownloader::downloadEnabled() const
QString DataModelDownloader::targetPath() const
{
- return QmlDesigner::QmlDesignerBasePlugin::examplesPathSetting();
+ return QmlDesigner::Paths::examplesPathSetting();
}
static Utils::FilePath tempFilePath()
@@ -105,8 +107,8 @@ DataModelDownloader::DataModelDownloader(QObject * /* parent */)
auto studioWelcomePlugin = qobject_cast<StudioWelcome::Internal::StudioWelcomePlugin *>(plugin);
if (studioWelcomePlugin) {
- QObject::connect(QmlDesigner::QmlDesignerBasePlugin::instance(),
- &QmlDesigner::QmlDesignerBasePlugin::examplesDownloadPathChanged,
+ QObject::connect(QmlDesigner::QmlDesignerBasePlugin::studioConfigSettingsPage(),
+ &QmlDesigner::StudioConfigSettingsPage::examplesDownloadPathChanged,
this,
&DataModelDownloader::targetPathMustChange);
}
diff --git a/src/plugins/studiowelcome/qdsnewdialog.cpp b/src/plugins/studiowelcome/qdsnewdialog.cpp
index 964ae4db109..4bd6293c19a 100644
--- a/src/plugins/studiowelcome/qdsnewdialog.cpp
+++ b/src/plugins/studiowelcome/qdsnewdialog.cpp
@@ -183,6 +183,11 @@ void QdsNewDialog::onWizardCreated(QStandardItemModel *screenSizeModel, QStandar
if (styleModel)
m_styleModel->setBackendModel(styleModel);
+ if (!m_currentPreset) {
+ qWarning() << "Wizard has been created but there is no Preset selected!";
+ return;
+ }
+
auto userPreset = m_currentPreset->asUserPreset();
if (m_qmlDetailsLoaded) {
diff --git a/src/plugins/studiowelcome/studiowelcomeplugin.cpp b/src/plugins/studiowelcome/studiowelcomeplugin.cpp
index 9604c0f1ec6..b7a4725f814 100644
--- a/src/plugins/studiowelcome/studiowelcomeplugin.cpp
+++ b/src/plugins/studiowelcome/studiowelcomeplugin.cpp
@@ -113,6 +113,9 @@ static Utils::FilePath getMainUiFileWithFallback()
auto qmlBuildSystem = qobject_cast<QmlProjectManager::QmlBuildSystem *>(
project->activeTarget()->buildSystem());
+ if (!qmlBuildSystem)
+ return {};
+
auto mainUiFile = qmlBuildSystem->mainUiFilePath();
if (mainUiFile.exists())
return mainUiFile;
@@ -649,9 +652,11 @@ bool StudioWelcomePlugin::delayedInitialize()
const QList<Kit *> kits = Utils::filtered(KitManager::kits(), [](const Kit *k) {
const QtSupport::QtVersion *version = QtSupport::QtKitAspect::qtVersion(k);
- const bool isQt6 = version && version->qtVersion().majorVersion() == 6;
+ const bool valid = version && version->isValid();
+ const bool isQt6 = valid && version->qtVersion().majorVersion() == 6;
+ const bool autoDetected = valid && version->isAutodetected();
- return isQt6
+ return isQt6 && autoDetected
&& ProjectExplorer::DeviceTypeKitAspect::deviceTypeId(k)
== ProjectExplorer::Constants::DESKTOP_DEVICE_TYPE;
});
diff --git a/src/plugins/studiowelcome/stylemodel.cpp b/src/plugins/studiowelcome/stylemodel.cpp
index 1198052994e..520129f20d4 100644
--- a/src/plugins/studiowelcome/stylemodel.cpp
+++ b/src/plugins/studiowelcome/stylemodel.cpp
@@ -63,6 +63,8 @@ int StyleModel::filteredIndex(int actualIndex)
if (actualIndex < 0)
return actualIndex;
+ QTC_ASSERT(actualIndex < m_items.size(), return -1);
+
QStandardItem *item = m_items.at(actualIndex);
// TODO: perhaps should add this kind of find to utils/algorithm.h
auto it = std::find(std::cbegin(m_filteredItems), std::cend(m_filteredItems), item);
diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp
index bd50833304e..f001756bf90 100644
--- a/src/plugins/texteditor/texteditor.cpp
+++ b/src/plugins/texteditor/texteditor.cpp
@@ -9144,11 +9144,11 @@ BaseTextEditor *TextEditorFactoryPrivate::createEditorHelper(const TextDocumentP
return editor;
}
-IEditor *BaseTextEditor::duplicate()
+BaseTextEditor *BaseTextEditor::duplicate()
{
// Use new standard setup if that's available.
if (d->m_origin) {
- IEditor *dup = d->m_origin->duplicateTextEditor(this);
+ BaseTextEditor *dup = d->m_origin->duplicateTextEditor(this);
emit editorDuplicated(dup);
return dup;
}
diff --git a/src/plugins/texteditor/texteditor.h b/src/plugins/texteditor/texteditor.h
index 2f2a9f81054..e7cb5b34347 100644
--- a/src/plugins/texteditor/texteditor.h
+++ b/src/plugins/texteditor/texteditor.h
@@ -111,7 +111,7 @@ public:
// IEditor
Core::IDocument *document() const override;
- IEditor *duplicate() override;
+ BaseTextEditor *duplicate() override;
QByteArray saveState() const override;
void restoreState(const QByteArray &state) override;
diff --git a/src/tools/CMakeLists.txt b/src/tools/CMakeLists.txt
index 2204ac3c5f9..d6663680c25 100644
--- a/src/tools/CMakeLists.txt
+++ b/src/tools/CMakeLists.txt
@@ -27,7 +27,9 @@ if (APPLE)
endif()
add_subdirectory(processlauncher)
-add_subdirectory(qml2puppet)
+if (WITH_QMLDESIGNER)
+ add_subdirectory(qml2puppet)
+endif()
add_subdirectory(qtcdebugger) ## windows only
# add_subdirectory(qtcrashhandler)
add_subdirectory(qtc-askpass)
diff --git a/src/tools/qml2puppet/CMakeLists.txt b/src/tools/qml2puppet/CMakeLists.txt
index 56a05aa0004..77bde355e9f 100644
--- a/src/tools/qml2puppet/CMakeLists.txt
+++ b/src/tools/qml2puppet/CMakeLists.txt
@@ -43,7 +43,7 @@ add_qtc_executable(qml2puppet
INCLUDES
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}
SOURCES
- qml2puppet/main.cpp
+ qml2puppet/qml2puppetmain.cpp
qml2puppet/qmlbase.h
qml2puppet/appmetadata.cpp qml2puppet/appmetadata.h
qml2puppet/qmlpuppet.h qml2puppet/qmlpuppet.cpp qml2puppet/configcrashpad.h
@@ -177,6 +177,7 @@ extend_qtc_executable(qml2puppet
qmlstatenodeinstance.cpp qmlstatenodeinstance.h
qmltransitionnodeinstance.cpp qmltransitionnodeinstance.h
qt3dpresentationnodeinstance.cpp qt3dpresentationnodeinstance.h
+ qt5bakelightsnodeinstanceserver.cpp qt5bakelightsnodeinstanceserver.h
qt5informationnodeinstanceserver.cpp qt5informationnodeinstanceserver.h
qt5nodeinstanceclientproxy.cpp qt5nodeinstanceclientproxy.h
qt5nodeinstanceserver.cpp qt5nodeinstanceserver.h
@@ -237,6 +238,7 @@ if (Qt6_VERSION VERSION_GREATER_EQUAL 6.4.0)
qt_add_qml_module(qml2puppet
URI QmlRuntime.QmlConfiguration
VERSION 1.0
+ RESOURCE_PREFIX "/qt-project.org/imports"
)
if (QTC_STATIC_BUILD)
qt_import_qml_plugins(qml2puppet PATH_TO_SCAN ${SRCDIR})
diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp
index 829a6f0edbc..52a3f6d74aa 100644
--- a/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp
+++ b/src/tools/qml2puppet/qml2puppet/editor3d/generalhelper.cpp
@@ -215,6 +215,7 @@ QVector4D GeneralHelper::focusNodesToCamera(QQuick3DCamera *camera, float defaul
if (auto renderModel = static_cast<QSSGRenderModel *>(targetPriv->spatialNode)) {
QWindow *window = static_cast<QWindow *>(viewPort->window());
if (window) {
+#if QT_VERSION < QT_VERSION_CHECK(6, 5, 1)
QSSGRef<QSSGRenderContextInterface> context;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
context = QSSGRenderContextInterface::getRenderContextInterface(quintptr(window));
@@ -222,12 +223,17 @@ QVector4D GeneralHelper::focusNodesToCamera(QQuick3DCamera *camera, float defaul
context = targetPriv->sceneManager->rci;
#endif
if (!context.isNull()) {
+#else
+ const auto &sm = targetPriv->sceneManager;
+ auto context = sm->wattached ? sm->wattached->rci().get() : nullptr;
+ if (context) {
+#endif
QSSGBounds3 bounds;
auto geometry = qobject_cast<SelectionBoxGeometry *>(model->geometry());
if (geometry) {
bounds = geometry->bounds();
} else {
- auto bufferManager = context->bufferManager();
+ const auto &bufferManager(context->bufferManager());
#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
bounds = renderModel->getModelBounds(bufferManager);
#else
@@ -889,6 +895,7 @@ bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVec
if (auto renderModel = static_cast<QSSGRenderModel *>(renderNode)) {
QWindow *window = static_cast<QWindow *>(view3D->window());
if (window) {
+#if QT_VERSION < QT_VERSION_CHECK(6, 5, 1)
QSSGRef<QSSGRenderContextInterface> context;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
context = QSSGRenderContextInterface::getRenderContextInterface(quintptr(window));
@@ -896,7 +903,12 @@ bool GeneralHelper::getBounds(QQuick3DViewport *view3D, QQuick3DNode *node, QVec
context = QQuick3DObjectPrivate::get(node)->sceneManager->rci;
#endif
if (!context.isNull()) {
- auto bufferManager = context->bufferManager();
+#else
+ const auto &sm = QQuick3DObjectPrivate::get(node)->sceneManager;
+ auto context = sm->wattached ? sm->wattached->rci().get() : nullptr;
+ if (context) {
+#endif
+ const auto &bufferManager(context->bufferManager());
#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
QSSGBounds3 bounds = renderModel->getModelBounds(bufferManager);
#else
diff --git a/src/tools/qml2puppet/qml2puppet/editor3d/selectionboxgeometry.cpp b/src/tools/qml2puppet/qml2puppet/editor3d/selectionboxgeometry.cpp
index 8a2a2449968..1157b1c5f84 100644
--- a/src/tools/qml2puppet/qml2puppet/editor3d/selectionboxgeometry.cpp
+++ b/src/tools/qml2puppet/qml2puppet/editor3d/selectionboxgeometry.cpp
@@ -312,14 +312,20 @@ void SelectionBoxGeometry::getBounds(
if (auto renderModel = static_cast<QSSGRenderModel *>(renderNode)) {
QWindow *window = static_cast<QWindow *>(m_view3D->window());
if (window) {
+#if QT_VERSION < QT_VERSION_CHECK(6, 5, 1)
QSSGRef<QSSGRenderContextInterface> context;
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
context = QSSGRenderContextInterface::getRenderContextInterface(quintptr(window));
-#else
+#elif QT_VERSION < QT_VERSION_CHECK(6, 5, 1)
context = QQuick3DObjectPrivate::get(this)->sceneManager->rci;
#endif
if (!context.isNull()) {
- auto bufferManager = context->bufferManager();
+#else
+ const auto &sm = QQuick3DObjectPrivate::get(this)->sceneManager;
+ auto context = sm->wattached ? sm->wattached->rci().get() : nullptr;
+ if (context) {
+#endif
+ const auto &bufferManager(context->bufferManager());
#if QT_VERSION < QT_VERSION_CHECK(6, 3, 0)
QSSGBounds3 bounds = renderModel->getModelBounds(bufferManager);
#else
diff --git a/src/tools/qml2puppet/qml2puppet/instances/instances.pri b/src/tools/qml2puppet/qml2puppet/instances/instances.pri
index 2d3b4ceedfe..505dd748e49 100644
--- a/src/tools/qml2puppet/qml2puppet/instances/instances.pri
+++ b/src/tools/qml2puppet/qml2puppet/instances/instances.pri
@@ -25,6 +25,7 @@ HEADERS += $$PWD/qt5nodeinstanceserver.h \
$$PWD/qt5captureimagenodeinstanceserver.h \
$$PWD/qt5capturepreviewnodeinstanceserver.h \
$$PWD/qt5testnodeinstanceserver.h \
+ $$PWD/qt5bakelightsnodeinstanceserver.h \
$$PWD/qt5informationnodeinstanceserver.h \
$$PWD/qt5rendernodeinstanceserver.h \
$$PWD/qt5previewnodeinstanceserver.h \
@@ -60,6 +61,7 @@ SOURCES += $$PWD/qt5nodeinstanceserver.cpp \
$$PWD/qt5captureimagenodeinstanceserver.cpp \
$$PWD/qt5capturepreviewnodeinstanceserver.cpp \
$$PWD/qt5testnodeinstanceserver.cpp \
+ $$PWD/qt5bakelightsnodeinstanceserver.cpp \
$$PWD/qt5informationnodeinstanceserver.cpp \
$$PWD/qt5rendernodeinstanceserver.cpp \
$$PWD/qt5previewnodeinstanceserver.cpp \
diff --git a/src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserverdispatcher.cpp b/src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserverdispatcher.cpp
index 09910847a94..9815d21ac47 100644
--- a/src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserverdispatcher.cpp
+++ b/src/tools/qml2puppet/qml2puppet/instances/nodeinstanceserverdispatcher.cpp
@@ -3,6 +3,7 @@
#include "nodeinstanceserverdispatcher.h"
+#include "qt5bakelightsnodeinstanceserver.h"
#include "qt5captureimagenodeinstanceserver.h"
#include "qt5capturepreviewnodeinstanceserver.h"
#include "qt5informationnodeinstanceserver.h"
@@ -170,6 +171,8 @@ std::unique_ptr<NodeInstanceServer> createNodeInstanceServer(
return std::make_unique<Qt5InformationNodeInstanceServer>(nodeInstanceClient);
else if (serverName == "previewmode")
return std::make_unique<Qt5PreviewNodeInstanceServer>(nodeInstanceClient);
+ else if (serverName == "bakelightsmode")
+ return std::make_unique<Qt5BakeLightsNodeInstanceServer>(nodeInstanceClient);
return {};
}
diff --git a/src/tools/qml2puppet/qml2puppet/instances/objectnodeinstance.cpp b/src/tools/qml2puppet/qml2puppet/instances/objectnodeinstance.cpp
index 281e6030a05..8a982f5cdd5 100644
--- a/src/tools/qml2puppet/qml2puppet/instances/objectnodeinstance.cpp
+++ b/src/tools/qml2puppet/qml2puppet/instances/objectnodeinstance.cpp
@@ -167,6 +167,11 @@ bool ObjectNodeInstance::isRenderable() const
return false;
}
+bool ObjectNodeInstance::isPropertyChange() const
+{
+ return false;
+}
+
bool ObjectNodeInstance::equalGraphicsItem(QGraphicsItem * /*item*/) const
{
return false;
@@ -500,7 +505,33 @@ void ObjectNodeInstance::setPropertyBinding(const PropertyName &name, const QStr
if (!isSimpleExpression(expression))
return;
- QmlPrivateGate::setPropertyBinding(object(), context(), name, expression);
+ bool qmlExpressionHasError = false;
+
+ QStringList idlist;
+ for (const auto &instance : nodeInstanceServer()->nodeInstances())
+ idlist.append(instance.id());
+
+ // Always set ids using the root context, since they are defined there anyway
+ if (idlist.contains(expression)) {
+ QmlPrivateGate::setPropertyBinding(object(),
+ context()->engine()->rootContext(), name, expression);
+ return;
+ }
+
+ if (!isPropertyChange()) {
+ QQmlExpression qmlExpression(context(), object(), expression);
+ qmlExpression.evaluate();
+ qmlExpressionHasError = qmlExpression.hasError();
+ }
+
+ if (qmlExpressionHasError) {
+ QmlPrivateGate::setPropertyBinding(object(),
+ context()->engine()->rootContext(),
+ name,
+ expression);
+ } else {
+ QmlPrivateGate::setPropertyBinding(object(), context(), name, expression);
+ }
}
void ObjectNodeInstance::deleteObjectsInList(const QQmlProperty &property)
diff --git a/src/tools/qml2puppet/qml2puppet/instances/objectnodeinstance.h b/src/tools/qml2puppet/qml2puppet/instances/objectnodeinstance.h
index 36abf66494c..3fad24e661f 100644
--- a/src/tools/qml2puppet/qml2puppet/instances/objectnodeinstance.h
+++ b/src/tools/qml2puppet/qml2puppet/instances/objectnodeinstance.h
@@ -82,6 +82,7 @@ public:
virtual bool isQuickWindow() const;
virtual bool isLayoutable() const;
virtual bool isRenderable() const;
+ virtual bool isPropertyChange() const;
virtual bool equalGraphicsItem(QGraphicsItem *item) const;
diff --git a/src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.cpp b/src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.cpp
index 8fa29118d7c..cd3ea427145 100644
--- a/src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.cpp
+++ b/src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.cpp
@@ -87,5 +87,10 @@ void QmlPropertyChangesNodeInstance::reparent(const ObjectNodeInstance::Pointer
QmlPrivateGate::PropertyChanges::attachToState(object());
}
+bool QmlPropertyChangesNodeInstance::isPropertyChange() const
+{
+ return true;
+}
+
} // namespace Internal
} // namespace QmlDesigner
diff --git a/src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.h b/src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.h
index fb270b5ab28..6077fbf2fd2 100644
--- a/src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.h
+++ b/src/tools/qml2puppet/qml2puppet/instances/qmlpropertychangesnodeinstance.h
@@ -29,6 +29,8 @@ public:
void reparent(const ObjectNodeInstance::Pointer &oldParentInstance, const PropertyName &oldParentProperty, const ObjectNodeInstance::Pointer &newParentInstance, const PropertyName &newParentProperty) override;
+ bool isPropertyChange() const override;
+
protected:
QmlPropertyChangesNodeInstance(QObject *object);
};
diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5bakelightsnodeinstanceserver.cpp b/src/tools/qml2puppet/qml2puppet/instances/qt5bakelightsnodeinstanceserver.cpp
new file mode 100644
index 00000000000..4287808c8a8
--- /dev/null
+++ b/src/tools/qml2puppet/qml2puppet/instances/qt5bakelightsnodeinstanceserver.cpp
@@ -0,0 +1,235 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#include "qt5bakelightsnodeinstanceserver.h"
+
+#if BAKE_LIGHTS_SUPPORTED
+#include "createscenecommand.h"
+#include "view3dactioncommand.h"
+
+#include "nodeinstanceclientinterface.h"
+#include "puppettocreatorcommand.h"
+
+#include <QDir>
+#include <QFileInfo>
+#include <QLibraryInfo>
+#include <QProcess>
+#include <QQuickView>
+#include <QQuickItem>
+
+#include <private/qquickdesignersupport_p.h>
+#include <private/qquick3dviewport_p.h>
+#endif
+
+namespace QmlDesigner {
+
+Qt5BakeLightsNodeInstanceServer::Qt5BakeLightsNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
+ Qt5NodeInstanceServer(nodeInstanceClient)
+{
+ setSlowRenderTimerInterval(100000000);
+ setRenderTimerInterval(100);
+}
+
+#if BAKE_LIGHTS_SUPPORTED
+
+Qt5BakeLightsNodeInstanceServer::~Qt5BakeLightsNodeInstanceServer()
+{
+ cleanup();
+}
+
+void Qt5BakeLightsNodeInstanceServer::createScene(const CreateSceneCommand &command)
+{
+ initializeView();
+ registerFonts(command.resourceUrl);
+ setTranslationLanguage(command.language);
+ setupScene(command);
+ startRenderTimer();
+
+ // Set working directory to a temporary directory, as baking process creates a file there
+ if (m_workingDir.isValid())
+ QDir::setCurrent(m_workingDir.path());
+}
+
+void Qt5BakeLightsNodeInstanceServer::view3DAction(const View3DActionCommand &command)
+{
+ switch (command.type()) {
+ case View3DActionType::SetBakeLightsView3D: {
+ QString id = command.value().toString();
+ const QList<ServerNodeInstance> allViews = allView3DInstances();
+ for (const auto &view : allViews) {
+ if (view.id() == id) {
+ m_view3D = qobject_cast<QQuick3DViewport *>(view.internalObject());
+ break;
+ }
+ }
+
+ if (!m_view3D)
+ abort(tr("View3D not found: '%1'").arg(id));
+ else
+ startRenderTimer();
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+void Qt5BakeLightsNodeInstanceServer::startRenderTimer()
+{
+ if (timerId() != 0)
+ killTimer(timerId());
+
+ int timerId = startTimer(renderTimerInterval());
+
+ setTimerId(timerId);
+}
+
+void Qt5BakeLightsNodeInstanceServer::bakeLights()
+{
+ if (!m_view3D) {
+ abort(tr("Invalid View3D object set."));
+ return;
+ }
+
+ QQuick3DLightmapBaker::Callback callback = [this](QQuick3DLightmapBaker::BakingStatus status,
+ std::optional<QString> msg, QQuick3DLightmapBaker::BakingControl *) {
+ m_callbackReceived = true;
+ switch (status) {
+ case QQuick3DLightmapBaker::BakingStatus::Progress:
+ case QQuick3DLightmapBaker::BakingStatus::Warning:
+ case QQuick3DLightmapBaker::BakingStatus::Error:
+ nodeInstanceClient()->handlePuppetToCreatorCommand(
+ {PuppetToCreatorCommand::BakeLightsProgress, msg.value_or("")});
+ break;
+ case QQuick3DLightmapBaker::BakingStatus::Cancelled:
+ abort(tr("Baking cancelled."));
+ break;
+ case QQuick3DLightmapBaker::BakingStatus::Complete:
+ runDenoiser();
+ break;
+ default:
+ qWarning() << __FUNCTION__ << "Unexpected light baking status received:"
+ << int(status) << msg.value_or("");
+ break;
+ }
+ };
+
+ QQuick3DLightmapBaker *baker = m_view3D->lightmapBaker();
+ baker->bake(callback);
+
+ m_bakingStarted = true;
+}
+
+void Qt5BakeLightsNodeInstanceServer::cleanup()
+{
+ m_workingDir.remove();
+ if (m_denoiser) {
+ if (m_denoiser->state() == QProcess::Running)
+ m_denoiser->terminate();
+ m_denoiser->deleteLater();
+ }
+}
+
+void Qt5BakeLightsNodeInstanceServer::abort(const QString &msg)
+{
+ cleanup();
+ nodeInstanceClient()->handlePuppetToCreatorCommand(
+ {PuppetToCreatorCommand::BakeLightsAborted, msg});
+}
+
+void Qt5BakeLightsNodeInstanceServer::finish()
+{
+ cleanup();
+ nodeInstanceClient()->handlePuppetToCreatorCommand(
+ {PuppetToCreatorCommand::BakeLightsFinished, {}});
+}
+
+void Qt5BakeLightsNodeInstanceServer::runDenoiser()
+{
+ // Check if denoiser exists (as it is third party app)
+ QString binPath = QLibraryInfo::path(QLibraryInfo::BinariesPath);
+#if defined(Q_OS_WIN)
+ binPath += "/qlmdenoiser.exe";
+#else
+ binPath += "/qlmdenoiser";
+#endif
+
+ QFileInfo fi(binPath);
+ if (!fi.exists()) {
+ nodeInstanceClient()->handlePuppetToCreatorCommand(
+ {PuppetToCreatorCommand::BakeLightsProgress,
+ tr("Warning: Denoiser executable not found, cannot denoise baked lightmaps (%1).")
+ .arg(binPath)});
+ finish();
+ return;
+ }
+
+ m_denoiser = new QProcess();
+
+ QObject::connect(m_denoiser, &QProcess::errorOccurred, this, [this](QProcess::ProcessError) {
+ m_workingDir.remove();
+ nodeInstanceClient()->handlePuppetToCreatorCommand(
+ {PuppetToCreatorCommand::BakeLightsProgress,
+ tr("Warning: An error occurred while running denoiser process!")});
+ finish();
+ });
+
+ QObject::connect(m_denoiser, &QProcess::finished, this, [this](int exitCode,
+ QProcess::ExitStatus exitStatus) {
+ if (exitCode == 0 && exitStatus == QProcess::NormalExit) {
+ nodeInstanceClient()->handlePuppetToCreatorCommand(
+ {PuppetToCreatorCommand::BakeLightsProgress,
+ tr("Denoising finished.")});
+ } else {
+ nodeInstanceClient()->handlePuppetToCreatorCommand(
+ {PuppetToCreatorCommand::BakeLightsProgress,
+ tr("Warning: Denoiser process failed with exit code '%1'!").arg(exitCode)});
+ }
+ finish();
+ });
+
+ nodeInstanceClient()->handlePuppetToCreatorCommand(
+ {PuppetToCreatorCommand::BakeLightsProgress,
+ tr("Denoising baked lightmaps...")});
+
+ m_denoiser->setWorkingDirectory(m_workingDir.path());
+ m_denoiser->start(binPath, {"qlm_list.txt"});
+
+}
+
+void Qt5BakeLightsNodeInstanceServer::collectItemChangesAndSendChangeCommands()
+{
+ static bool inFunction = false;
+
+ if (!rootNodeInstance().holdsGraphical())
+ return;
+
+ if (!inFunction) {
+ inFunction = true;
+
+ QQuickDesignerSupport::polishItems(quickWindow());
+
+ render();
+
+ inFunction = false;
+ }
+}
+
+void Qt5BakeLightsNodeInstanceServer::render()
+{
+ // Render multiple times to make sure everything gets rendered correctly before baking
+ if (++m_renderCount == 4) {
+ bakeLights();
+ } else {
+ rootNodeInstance().updateDirtyNodeRecursive();
+ renderWindow();
+ if (m_bakingStarted) {
+ slowDownRenderTimer(); // No more renders needed
+ if (!m_callbackReceived)
+ abort(tr("No bakeable models detected."));
+ }
+ }
+}
+#endif
+
+} // namespace QmlDesigner
diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5bakelightsnodeinstanceserver.h b/src/tools/qml2puppet/qml2puppet/instances/qt5bakelightsnodeinstanceserver.h
new file mode 100644
index 00000000000..0a92ccdf8f8
--- /dev/null
+++ b/src/tools/qml2puppet/qml2puppet/instances/qt5bakelightsnodeinstanceserver.h
@@ -0,0 +1,58 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "qt5nodeinstanceserver.h"
+
+#if QUICK3D_MODULE && QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
+#include <QTemporaryDir>
+#define BAKE_LIGHTS_SUPPORTED 1
+#endif
+
+QT_BEGIN_NAMESPACE
+class QProcess;
+class QQuick3DViewport;
+QT_END_NAMESPACE
+
+namespace QmlDesigner {
+
+class Qt5BakeLightsNodeInstanceServer : public Qt5NodeInstanceServer
+{
+ Q_OBJECT
+public:
+ explicit Qt5BakeLightsNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient);
+
+#if BAKE_LIGHTS_SUPPORTED
+public:
+ virtual ~Qt5BakeLightsNodeInstanceServer();
+
+ void createScene(const CreateSceneCommand &command) override;
+ void view3DAction(const View3DActionCommand &command) override;
+
+ void render();
+
+protected:
+ void collectItemChangesAndSendChangeCommands() override;
+ void startRenderTimer() override;
+ void bakeLights();
+
+private:
+ void abort(const QString &msg);
+ void runDenoiser();
+ void finish();
+ void cleanup();
+
+ QQuick3DViewport *m_view3D = nullptr;
+ bool m_bakingStarted = false;
+ bool m_callbackReceived = false;
+ int m_renderCount = 0;
+ QProcess *m_denoiser = nullptr;
+ QTemporaryDir m_workingDir;
+#else
+protected:
+ void collectItemChangesAndSendChangeCommands() override {};
+#endif
+};
+
+} // namespace QmlDesigner
diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp b/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
index 36c24d85733..0d7b4fa215c 100644
--- a/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
+++ b/src/tools/qml2puppet/qml2puppet/instances/qt5informationnodeinstanceserver.cpp
@@ -827,9 +827,11 @@ void Qt5InformationNodeInstanceServer::handleView3DDestroyed([[maybe_unused]] QO
#ifdef QUICK3D_MODULE
auto view = qobject_cast<QQuick3DViewport *>(obj);
m_view3Ds.remove(obj);
- removeNode3D(view->scene());
- if (view && view == m_active3DView)
- m_active3DView = nullptr;
+ if (view) {
+ removeNode3D(view->scene());
+ if (view == m_active3DView)
+ m_active3DView = nullptr;
+ }
#endif
}
@@ -1071,6 +1073,13 @@ void Qt5InformationNodeInstanceServer::doRender3DEditView()
m_editView3DData.window->afterRendering();
}
#else
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 1)
+ static bool justOnce = true;
+ if (justOnce) {
+ justOnce = false;
+ renderWindow(); // Need to make sure all View3Ds have context
+ }
+#endif
renderImage = grabRenderControl(m_editView3DData);
#endif
diff --git a/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp b/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp
index c5c6f6dc965..b0726b152a0 100644
--- a/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp
+++ b/src/tools/qml2puppet/qml2puppet/instances/qt5nodeinstanceclientproxy.cpp
@@ -6,6 +6,7 @@
#include <QCoreApplication>
#include "capturenodeinstanceserverdispatcher.h"
+#include "qt5bakelightsnodeinstanceserver.h"
#include "qt5captureimagenodeinstanceserver.h"
#include "qt5capturepreviewnodeinstanceserver.h"
#include "qt5informationnodeinstanceserver.h"
@@ -74,6 +75,9 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) :
} else if (QCoreApplication::arguments().at(2) == QLatin1String("captureiconmode")) {
setNodeInstanceServer(std::make_unique<Qt5CaptureImageNodeInstanceServer>(this));
initializeSocket();
+ } else if (QCoreApplication::arguments().at(2) == QLatin1String("bakelightsmode")) {
+ setNodeInstanceServer(std::make_unique<Qt5BakeLightsNodeInstanceServer>(this));
+ initializeSocket();
}
}
diff --git a/src/tools/qml2puppet/qml2puppet/instances/servernodeinstance.h b/src/tools/qml2puppet/qml2puppet/instances/servernodeinstance.h
index b8e45491a8a..abb16d74bdf 100644
--- a/src/tools/qml2puppet/qml2puppet/instances/servernodeinstance.h
+++ b/src/tools/qml2puppet/qml2puppet/instances/servernodeinstance.h
@@ -57,6 +57,7 @@ using QHashValueType = size_t;
friend class Qt4PreviewNodeInstanceServer;
friend class Qt5InformationNodeInstanceServer;
friend class Qt5NodeInstanceServer;
+ friend class Qt5BakeLightsNodeInstanceServer;
friend class Qt5PreviewNodeInstanceServer;
friend class Qt5CapturePreviewNodeInstanceServer;
friend class Qt5TestNodeInstanceServer;
diff --git a/src/tools/qml2puppet/qml2puppet/main.cpp b/src/tools/qml2puppet/qml2puppet/qml2puppetmain.cpp
index 763bf77b5dc..5896df39e1f 100644
--- a/src/tools/qml2puppet/qml2puppet/main.cpp
+++ b/src/tools/qml2puppet/qml2puppet/qml2puppetmain.cpp
@@ -7,25 +7,24 @@
#include "runner/qmlruntime.h"
#endif
-QmlBase *getQmlRunner(int &argc, char **argv)
+auto getQmlRunner(int &argc, char **argv)
{
#ifdef ENABLE_INTERNAL_QML_RUNTIME
+ QString qmlRuntime("--qml-runtime");
for (int i = 0; i < argc; i++) {
- if (!strcmp(argv[i], "--qml-runtime")){
+ if (!qmlRuntime.compare(QString::fromLocal8Bit(argv[i]))) {
qInfo() << "Starting QML Runtime";
- return new QmlRuntime(argc, argv);
+ return std::unique_ptr<QmlBase>(new QmlRuntime(argc, argv));
}
}
#endif
qInfo() << "Starting QML Puppet";
- return new QmlPuppet(argc, argv);
+ return std::unique_ptr<QmlBase>(new QmlPuppet(argc, argv));
}
int main(int argc, char *argv[])
{
QDSMeta::Logging::registerMessageHandler();
QDSMeta::AppInfo::registerAppInfo("Qml2Puppet");
-
- QmlBase *qmlRunner = getQmlRunner(argc, argv);
- return qmlRunner->run();
+ return getQmlRunner(argc, argv)->run();
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 3e961231ca5..864ce4f416b 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -1,4 +1,6 @@
add_subdirectory(auto)
add_subdirectory(manual)
add_subdirectory(tools/qml-ast2dot)
-add_subdirectory(unit)
+if (WITH_QMLDESIGNER)
+ add_subdirectory(unit)
+endif()
diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
index 2206e24242f..12490dd1afe 100644
--- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
+++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.cpp
@@ -123,24 +123,23 @@ static void initializeMetaTypeSystem(const QString &resourcePath)
qWarning() << qPrintable(errorAndWarning);
}
-namespace {
class ExternalDependenciesFake : public QObject, public ExternalDependenciesInterface
{
public:
- ExternalDependenciesFake(Model &model)
+ ExternalDependenciesFake(Model *model)
: model{model}
{}
double formEditorDevicePixelRatio() const override { return 1.; }
QString currentProjectDirPath() const override
{
- return QFileInfo(model.fileUrl().toLocalFile()).absolutePath();
+ return QFileInfo(model->fileUrl().toLocalFile()).absolutePath();
}
QUrl currentResourcePath() const override
{
- return QUrl::fromLocalFile(QFileInfo(model.fileUrl().toLocalFile()).absolutePath());
+ return QUrl::fromLocalFile(QFileInfo(model->fileUrl().toLocalFile()).absolutePath());
}
QString defaultPuppetFallbackDirectory() const override { return {}; }
@@ -160,13 +159,20 @@ public:
PuppetStartData puppetStartData(const class Model &) const override { return {}; }
bool instantQmlTextUpdate() const override { return true; }
Utils::FilePath qmlPuppetPath() const override { return {}; }
+ QStringList modulePaths() const override { return {}; }
+ QStringList projectModulePaths() const override { return {}; }
+ bool isQt6Project() const override { return {}; }
+ QString qtQuickVersion() const override { return {}; }
+ Utils::FilePath resourcePath(const QString &) const override { return {}; }
public:
QSettings qsettings;
QmlDesigner::DesignerSettings settings{&qsettings};
- Model &model;
+ Model *model;
};
+namespace {
+
ModelPointer createModel(const QString &typeName,
int major = 2,
int minor = 1,
@@ -187,7 +193,7 @@ ModelPointer createModel(const QString &typeName,
NotIndentingTextEditModifier *modifier = new NotIndentingTextEditModifier(textEdit);
modifier->setParent(textEdit);
- auto externalDependencies = new ExternalDependenciesFake{*model};
+ auto externalDependencies = new ExternalDependenciesFake{model.get()};
externalDependencies->setParent(model.get());
auto rewriterView = new QmlDesigner::RewriterView(*externalDependencies,
@@ -204,7 +210,7 @@ ModelPointer createModel(const QString &typeName,
auto createTextRewriterView(
Model &model, RewriterView::DifferenceHandling differenceHandling = RewriterView::Amend)
{
- auto externalDependencies = new ExternalDependenciesFake{model};
+ auto externalDependencies = new ExternalDependenciesFake{&model};
auto rewriter = std::make_unique<TestRewriterView>(*externalDependencies, differenceHandling);
externalDependencies->setParent(rewriter.get());
@@ -214,13 +220,15 @@ auto createTextRewriterView(
} // namespace
tst_TestCore::tst_TestCore()
- : QObject()
+ : externalDependencies{std::make_unique<ExternalDependenciesFake>(nullptr)}
{
QLoggingCategory::setFilterRules(QStringLiteral("qtc.qmljs.imports=false"));
//QLoggingCategory::setFilterRules(QStringLiteral("*.info=false\n*.debug=false\n*.warning=false"));
QLoggingCategory::setFilterRules(QStringLiteral("*.warning=false"));
}
+tst_TestCore::~tst_TestCore() = default;
+
void tst_TestCore::initTestCase()
{
QmlModelNodeFacade::enableUglyWorkaroundForIsValidQmlModelNodeFacadeInTests();
@@ -250,7 +258,8 @@ void tst_TestCore::initTestCase()
qDebug() << pluginPath;
Q_ASSERT(QFileInfo::exists(pluginPath));
- MetaInfo::setPluginPaths(QStringList() << pluginPath);
+
+ MetaInfo::initializeGlobal({pluginPath}, *externalDependencies);
QFileInfo builtins(IDE_DATA_PATH "/qml-type-descriptions/builtins.qmltypes");
QStringList errors, warnings;
@@ -259,7 +268,6 @@ void tst_TestCore::initTestCase()
void tst_TestCore::cleanupTestCase()
{
- MetaInfo::clearGlobal();
}
void tst_TestCore::init()
@@ -1072,10 +1080,10 @@ void tst_TestCore::testRewriterChangeImports()
//
Import webkitImport = Import::createLibraryImport("QtWebKit", "1.0");
- QList<Import> importList;
+ Imports importList;
importList << webkitImport;
- model->changeImports(importList, QList<Import>());
+ model->changeImports(importList, Imports());
const QLatin1String qmlWithImport("\n"
"import QtQuick 2.1\n"
@@ -1084,7 +1092,7 @@ void tst_TestCore::testRewriterChangeImports()
"Rectangle {}\n");
QCOMPARE(textEdit.toPlainText(), qmlWithImport);
- model->changeImports(QList<Import>(), importList);
+ model->changeImports(Imports(), importList);
QCOMPARE(model->imports().size(), 1);
QCOMPARE(model->imports().first(), Import::createLibraryImport("QtQuick", "2.1"));
@@ -1098,7 +1106,7 @@ void tst_TestCore::testRewriterChangeImports()
Import webkitImportAlias = Import::createLibraryImport("QtWebKit", "1.0", "Web");
- model->changeImports(QList<Import>() << webkitImportAlias, QList<Import>() << webkitImport);
+ model->changeImports(Imports() << webkitImportAlias, Imports() << webkitImport);
const QLatin1String qmlWithAliasImport("\n"
"import QtQuick 2.1\n"
@@ -1107,7 +1115,7 @@ void tst_TestCore::testRewriterChangeImports()
"Rectangle {}\n");
QCOMPARE(textEdit.toPlainText(), qmlWithAliasImport);
- model->changeImports(QList<Import>(), QList<Import>() << webkitImportAlias);
+ model->changeImports(Imports(), Imports() << webkitImportAlias);
QCOMPARE(model->imports().first(), Import::createLibraryImport("QtQuick", "2.1"));
QCOMPARE(textEdit.toPlainText(), qmlString);
@@ -2547,7 +2555,7 @@ void tst_TestCore::testModelRemoveNode()
model->attachView(view.data());
TestConnectionManager connectionManager;
- ExternalDependenciesFake externalDependenciesFake{*model};
+ ExternalDependenciesFake externalDependenciesFake{model.get()};
NodeInstanceView nodeInstanceView{connectionManager, externalDependenciesFake};
model->attachView(&nodeInstanceView);
@@ -4522,7 +4530,7 @@ void tst_TestCore::testSubComponentManager()
auto model(createModel("QtQuick.Rectangle", 2, 15));
model->setFileUrl(QUrl::fromLocalFile(fileName));
- ExternalDependenciesFake externalDependenciesFake{*model};
+ ExternalDependenciesFake externalDependenciesFake{model.get()};
QScopedPointer<SubComponentManager> subComponentManager(
new SubComponentManager(model.get(), externalDependenciesFake));
subComponentManager->update(QUrl::fromLocalFile(fileName), model->imports());
@@ -4828,11 +4836,6 @@ void tst_TestCore::testMetaInfoSimpleType()
QCOMPARE(itemMetaInfo.superClasses().size(), 2); // Item, QtQuick.QtObject
QVERIFY(itemMetaInfo.isQtQuickItem());
QVERIFY(itemMetaInfo.isQtObject());
-
- // availableInVersion
- QVERIFY(itemMetaInfo.availableInVersion(2, 2));
- QVERIFY(itemMetaInfo.availableInVersion(2, 0));
- QVERIFY(itemMetaInfo.availableInVersion(-1, -1));
}
void tst_TestCore::testMetaInfoUncreatableType()
@@ -6714,7 +6717,7 @@ void tst_TestCore::testInstancesAttachToExistingModel()
// Attach NodeInstanceView
TestConnectionManager connectionManager;
- ExternalDependenciesFake externalDependenciesFake{*model};
+ ExternalDependenciesFake externalDependenciesFake{model.get()};
NodeInstanceView instanceView{connectionManager, externalDependenciesFake};
model->attachView(&instanceView);
diff --git a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h
index 5160cf5ca3f..1304f4aa654 100644
--- a/tests/auto/qml/qmldesigner/coretests/tst_testcore.h
+++ b/tests/auto/qml/qmldesigner/coretests/tst_testcore.h
@@ -15,7 +15,7 @@ class tst_TestCore : public QObject
Q_OBJECT
public:
tst_TestCore();
-
+ ~tst_TestCore();
private slots:
void initTestCase();
void cleanupTestCase();
@@ -225,5 +225,6 @@ private slots:
void readAnnotations();
private:
+ class std::unique_ptr<class ExternalDependenciesFake> externalDependencies;
ExtensionSystem::PluginManager pm; // FIXME remove
};
diff --git a/tests/auto/qml/qmlprojectmanager/fileformat/CMakeLists.txt b/tests/auto/qml/qmlprojectmanager/fileformat/CMakeLists.txt
index 91800cd75ee..315db12ac18 100644
--- a/tests/auto/qml/qmlprojectmanager/fileformat/CMakeLists.txt
+++ b/tests/auto/qml/qmlprojectmanager/fileformat/CMakeLists.txt
@@ -9,11 +9,12 @@ foreach(source IN LISTS QmlProjectManagerSources)
endif()
endforeach()
-add_qtc_test(tst_qml_fileformat
- DEPENDS QmlJS Utils
- INCLUDES "${PROJECT_SOURCE_DIR}/src/plugins/qmlprojectmanager/fileformat"
- DEFINES
- QT_CREATOR
- SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}"
- SOURCES tst_fileformat.cpp ${fileformat_sources}
-)
+#add_qtc_test(tst_qml_fileformat
+# DEPENDS QmlJS Utils
+# INCLUDES "${PROJECT_SOURCE_DIR}/src/plugins/qmlprojectmanager/fileformat"
+# DEFINES
+# QT_CREATOR
+# SRCDIR="${CMAKE_CURRENT_SOURCE_DIR}"
+# SOURCES tst_fileformat.cpp ${fileformat_sources}
+#)
+
diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt
index 7baf81f84bd..95353c01ea6 100644
--- a/tests/unit/CMakeLists.txt
+++ b/tests/unit/CMakeLists.txt
@@ -37,3 +37,4 @@ if (NOT QT_CREATOR_API_DEFINED)
endif()
add_subdirectory(unittest)
+add_subdirectory(tools)
diff --git a/tests/unit/README.md b/tests/unit/README.md
new file mode 100644
index 00000000000..38911b31ec2
--- /dev/null
+++ b/tests/unit/README.md
@@ -0,0 +1,49 @@
+# Contribution Guideline
+
+This document summarizes;
+
+* Best practices for writing tests
+* How to add a new test
+* How to build only specific test
+
+All tests here depend on the [GoogleTest][1] framework.
+
+## Best Practices
+
+We're following those patterns/approaches;
+
+* The Arrange, Act, and Assert (AAA) Pattern
+* Given When Then (GWT) Pattern
+
+## Adding a New Unit Test
+
+* Please add your tests under `unit/unittest`. No subfolders are needed.
+* Name your class as `foo-test.cpp`
+
+* Always include `googletest.h` header. Without that you may get the printer function can be broken because the are not anymore ODR (because of weak linking to printers for example). It is also necessary for nice printers, also adds Qt known matchers.
+
+## Building Tests
+
+> Note:
+> When you're building the application from the terminal, you can set environment variables instead of settings CMake flags.
+> The corresponding environment variable name is same with CMake variable name but with a 'QTC_' prefix.
+> CMake Variable: WITH_TESTS
+> Environment Variable: QTC_WITH_TESTS
+
+You have to enable tests with the following CMake variable otherwise the default configuration skips them.
+
+```bash
+WITH_TESTS=ON
+```
+
+## Building Specific Tests
+
+After enabling tests you can use test-specific CMake flags to customize which tests should be built instead of building all of them at once. Please check the relevant CMake file to see which variable is required to enable that specific test.
+
+```bash
+BUILD_TESTS_BY_DEFAULT=OFF
+BUILD_TEST_UNITTEST=ON
+BUILD_TEST_TST_QML_TESTCORE=ON
+```
+
+[1]: https://github.com/google/googletest
diff --git a/tests/unit/mockup/qmldesigner/designercore/include/itemlibraryinfo.h b/tests/unit/mockup/qmldesigner/designercore/include/itemlibraryinfo.h
deleted file mode 100644
index b0f80b18702..00000000000
--- a/tests/unit/mockup/qmldesigner/designercore/include/itemlibraryinfo.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "qmldesignercorelib_global.h"
-
-#include <QIcon>
-
-namespace QmlDesigner {
-
-class ItemLibraryEntry
-{
-public:
- QString name() const { return {}; }
- TypeName typeName() const { return {}; }
- QIcon typeIcon() const { return {}; }
- QString libraryEntryIconPath() const { return {}; }
-};
-
-class ItemLibraryInfo
-{
-public:
- QList<ItemLibraryEntry> entries() const { return {}; }
- QList<ItemLibraryEntry> entriesForType([[maybe_unused]] const QByteArray &typeName,
- [[maybe_unused]] int majorVersion,
- [[maybe_unused]] int minorVersion) const
- {
- return {};
- }
- ItemLibraryEntry entry([[maybe_unused]] const QString &name) const { return {}; }
-};
-
-} // namespace QmlDesigner
diff --git a/tests/unit/mockup/qmldesigner/designercore/include/metainfo.h b/tests/unit/mockup/qmldesigner/designercore/include/metainfo.h
deleted file mode 100644
index fdf16dc489b..00000000000
--- a/tests/unit/mockup/qmldesigner/designercore/include/metainfo.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "qmldesignercorelib_global.h"
-
-#include <QSharedPointer>
-#include <QStringList>
-
-#include "itemlibraryinfo.h"
-#include <nodemetainfo.h>
-
-namespace QmlDesigner {
-
-class ModelNode;
-class AbstractProperty;
-class ItemLibraryInfo;
-
-inline bool operator==([[maybe_unused]] const MetaInfo &first, [[maybe_unused]] const MetaInfo &second)
-{
- return {};
-}
-inline bool operator!=([[maybe_unused]] const MetaInfo &first, [[maybe_unused]] const MetaInfo &second)
-{
- return {};
-}
-
-class QMLDESIGNERCORE_EXPORT MetaInfo
-{
-public:
- ItemLibraryInfo *itemLibraryInfo() const { return {}; }
-
-public:
- static MetaInfo global() { return {}; }
- static void clearGlobal() {}
-
- static void setPluginPaths([[maybe_unused]] const QStringList &paths) {}
-};
-
-} //namespace QmlDesigner
diff --git a/tests/unit/mockup/qmldesigner/designercore/include/nodemetainfo.h b/tests/unit/mockup/qmldesigner/designercore/include/nodemetainfo.h
deleted file mode 100644
index ac0edfc018c..00000000000
--- a/tests/unit/mockup/qmldesigner/designercore/include/nodemetainfo.h
+++ /dev/null
@@ -1,89 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include "propertymetainfo.h"
-
-#include <projectstorage/projectstoragefwd.h>
-#include <projectstorageids.h>
-
-#include <QIcon>
-#include <QList>
-#include <QString>
-#include <QVariant>
-
-#include <qmldesignercorelib_global.h>
-
-QT_BEGIN_NAMESPACE
-class QDeclarativeContext;
-QT_END_NAMESPACE
-
-namespace QmlDesigner {
-
-class MetaInfo;
-class Model;
-class AbstractProperty;
-
-class NodeMetaInfo
-{
-public:
- NodeMetaInfo() {}
- NodeMetaInfo(Model *, const TypeName &, int, int) {}
- NodeMetaInfo(TypeId, NotNullPointer<const ProjectStorage<Sqlite::Database>>) {}
- NodeMetaInfo(NotNullPointer<const ProjectStorage<Sqlite::Database>>) {}
-
- bool isValid() const { return {}; }
- bool isFileComponent() const { return {}; }
- bool hasProperty(const PropertyName &) const { return {}; }
- PropertyMetaInfos properties() const { return {}; }
- PropertyMetaInfos localProperties() const { return {}; }
- PropertyMetaInfo property(const PropertyName &) const { return {}; }
- PropertyNameList propertyNames() const { return {}; }
- PropertyNameList signalNames() const { return {}; }
- PropertyNameList directPropertyNames() const { return {}; }
- PropertyName defaultPropertyName() const { return "data"; }
- bool hasDefaultProperty() const { return {}; }
-
- std::vector<NodeMetaInfo> classHierarchy() const { return {}; }
- std::vector<NodeMetaInfo> superClasses() const { return {}; }
-
- bool defaultPropertyIsComponent() const { return {}; }
-
- TypeName typeName() const { return {}; }
- TypeName simplifiedTypeName() const { return {}; }
- int majorVersion() const { return {}; }
- int minorVersion() const { return {}; }
-
- QString componentSource() const { return {}; }
- QString componentFileName() const { return {}; }
-
- bool hasCustomParser() const { return {}; }
-
- bool availableInVersion(int, int) const { return {}; }
- bool isBasedOn(const NodeMetaInfo &) const { return {}; }
- bool isBasedOn(const NodeMetaInfo &, const NodeMetaInfo &) const { return {}; }
- bool isBasedOn(const NodeMetaInfo &, const NodeMetaInfo &, const NodeMetaInfo &) const
- {
- return {};
- }
-
- bool isGraphicalItem() const { return {}; }
- bool isLayoutable() const { return {}; }
- bool isView() const { return {}; }
- bool isTabView() const { return {}; }
- bool isQtQuick3DNode() const { return {}; }
- bool isQtQuick3DModel() const { return {}; }
- bool isQtQuick3DMaterial() const { return {}; }
- bool isQtQuickLoader() const { return {}; }
- bool isQtQuickItem() const { return {}; }
- bool isQtQuick3DTexture() const { return {}; }
-
- QString importDirectoryPath() const { return {}; }
-
- static void clearCache() {}
-};
-
-using NodeMetaInfos = std::vector<NodeMetaInfo>;
-
-} // namespace QmlDesigner
diff --git a/tests/unit/mockup/qmldesigner/designercore/include/propertymetainfo.h b/tests/unit/mockup/qmldesigner/designercore/include/propertymetainfo.h
deleted file mode 100644
index 624f64e76ba..00000000000
--- a/tests/unit/mockup/qmldesigner/designercore/include/propertymetainfo.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-
-#pragma once
-
-#include <qmldesignercorelib_global.h>
-
-#include <QSharedPointer>
-#include <QString>
-
-#include <vector>
-
-namespace QmlDesigner {
-
-class PropertyMetaInfo
-{
-public:
- PropertyMetaInfo() = default;
- PropertyMetaInfo(QSharedPointer<class NodeMetaInfoPrivate>, const PropertyName &) {}
- ~PropertyMetaInfo() {}
-
- const TypeName &propertyTypeName() const
- {
- static TypeName foo;
- return foo;
- }
- class NodeMetaInfo propertyNodeMetaInfo() const;
-
- bool isWritable() const { return {}; }
- bool isListProperty() const { return {}; }
- bool isEnumType() const { return {}; }
- bool isPrivate() const { return {}; }
- bool isPointer() const { return {}; }
- QVariant castedValue(const QVariant &) const { return {}; }
- PropertyName name() const & { return {}; }
-
- template<typename... TypeName>
- bool hasPropertyTypeName(const TypeName &...typeName) const
- {
- auto propertyTypeName_ = propertyTypeName();
- return ((propertyTypeName_ == typeName) && ...);
- }
-
- bool propertyTypeNameIsUrl() const { return hasPropertyTypeName("QUrl", "url"); }
-};
-
-using PropertyMetaInfos = std::vector<PropertyMetaInfo>;
-
-} // namespace QmlDesigner
diff --git a/tests/unit/tools/CMakeLists.txt b/tests/unit/tools/CMakeLists.txt
new file mode 100644
index 00000000000..05b561491fc
--- /dev/null
+++ b/tests/unit/tools/CMakeLists.txt
@@ -0,0 +1 @@
+add_subdirectory(qmlprojectmanager)
diff --git a/tests/unit/tools/qmlprojectmanager/CMakeLists.txt b/tests/unit/tools/qmlprojectmanager/CMakeLists.txt
new file mode 100644
index 00000000000..0f5a41c6331
--- /dev/null
+++ b/tests/unit/tools/qmlprojectmanager/CMakeLists.txt
@@ -0,0 +1,16 @@
+project(QmlProjectManagerConverterDataCreator)
+
+add_compile_definitions(QT_CREATOR)
+
+add_executable(${PROJECT_NAME}
+ main.cpp
+)
+
+set_target_properties(${PROJECT_NAME}
+ PROPERTIES
+ OUTPUT_NAME "dataSetGenerator"
+)
+
+target_link_libraries(${PROJECT_NAME}
+ QmlJS Utils ProjectExplorer QmlProjectManagerLib
+)
diff --git a/tests/unit/tools/qmlprojectmanager/main.cpp b/tests/unit/tools/qmlprojectmanager/main.cpp
new file mode 100644
index 00000000000..688a8e6f540
--- /dev/null
+++ b/tests/unit/tools/qmlprojectmanager/main.cpp
@@ -0,0 +1,95 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include <QJsonDocument>
+#include <qmlprojectmanager/buildsystem/projectitem/converters.h>
+
+class DataSet
+{
+public:
+ DataSet(const QString &rootDir)
+ : m_rootDir(rootDir)
+ {}
+ void setDataSource(const QString &dataSetName)
+ {
+ m_dataSetDirectory.setPath(m_rootDir.path() + "/" + dataSetName);
+
+ m_qmlProjectFile = Utils::FilePath::fromString(
+ QString(m_dataSetDirectory.absolutePath()).append("/testfile.qmlproject"));
+ m_jsonToQmlProjectFile = Utils::FilePath::fromString(
+ QString(m_dataSetDirectory.absolutePath()).append("/testfile.jsontoqml"));
+ m_qmlProjectToJsonFile = Utils::FilePath::fromString(
+ QString(m_dataSetDirectory.absolutePath()).append("/testfile.qmltojson"));
+ }
+
+ QString qmlProjectContent() const
+ {
+ return (m_qmlProjectFile.fileContents()
+ ? QString::fromLatin1(m_qmlProjectFile.fileContents().value())
+ : QString{});
+ }
+ QString jsonToQmlProjectContent() const
+ {
+ return m_jsonToQmlProjectFile.fileContents()
+ ? QString::fromLatin1(m_jsonToQmlProjectFile.fileContents().value())
+ : QString{};
+ }
+ QString qmlProjectToJsonContent() const
+ {
+ return m_qmlProjectToJsonFile.fileContents()
+ ? QString::fromLatin1(m_qmlProjectToJsonFile.fileContents().value())
+ : QString{};
+ }
+
+ QString dataSetPath() const { return m_dataSetDirectory.absolutePath(); }
+ QString dataSetName() const { return m_dataSetDirectory.dirName(); }
+ Utils::FilePath qmlProjectFile() const { return m_qmlProjectFile; }
+ Utils::FilePath jsonToQmlProjectFile() const { return m_jsonToQmlProjectFile; }
+ Utils::FilePath qmlProjectToJsonFile() const { return m_qmlProjectToJsonFile; }
+
+private:
+ QDir m_rootDir;
+ QDir m_dataSetDirectory;
+ Utils::FilePath m_qmlProjectFile;
+ Utils::FilePath m_jsonToQmlProjectFile;
+ Utils::FilePath m_qmlProjectToJsonFile;
+};
+
+int main(int argc, char **argv)
+{
+ const QString helpText{"./dataSetGenerator [path]\n"
+ "[path]: Path to the data set folders. The default is current dir.\n"
+ " Folder names should be in the form of test-set-x.\n"};
+
+ QDir dataSetPath{QDir::currentPath()};
+ if (argc >= 2) {
+ dataSetPath.setPath(argv[1]);
+ }
+
+ if (!dataSetPath.exists()) {
+ qDebug() << "Data path does not exist:" << dataSetPath.path() << Qt::endl;
+ qDebug().noquote() << helpText;
+ return -1;
+ }
+
+ QStringList dataSetList{dataSetPath.entryList({"test-set-*"})};
+ if (!dataSetList.size()) {
+ qDebug() << "No test sets are available under" << dataSetPath.path() << Qt::endl;
+ qDebug().noquote() << helpText;
+ return -1;
+ }
+
+ DataSet dataSet(dataSetPath.path());
+ for (const auto &dataSetName : dataSetList) {
+ dataSet.setDataSource(dataSetName);
+
+ qDebug() << "Regenerating data set:" << dataSet.dataSetName();
+ QJsonObject qml2json = QmlProjectManager::Converters::qmlProjectTojson(
+ dataSet.qmlProjectFile());
+ QString json2qml = QmlProjectManager::Converters::jsonToQmlProject(qml2json);
+
+ dataSet.qmlProjectToJsonFile().writeFileContents(QJsonDocument(qml2json).toJson());
+ dataSet.jsonToQmlProjectFile().writeFileContents(json2qml.toUtf8());
+ }
+ return 0;
+}
diff --git a/tests/unit/unittest/CMakeLists.txt b/tests/unit/unittest/CMakeLists.txt
index 7522a8e180e..a77b855985e 100644
--- a/tests/unit/unittest/CMakeLists.txt
+++ b/tests/unit/unittest/CMakeLists.txt
@@ -25,17 +25,22 @@ add_qtc_test(unittest GTEST
BEFORE "../mockup/qmldesigner/designercore/include"
DEPENDS
Qt::Core Qt::Network Qt::Widgets
- Qt::Xml Qt::Concurrent Qt::Qml Qt::Gui
+ Qt::Xml Qt::Concurrent Qt::QmlPrivate Qt::Gui
Qt::Core5Compat QmlJS Sqlite SqliteC
Googletest
DEFINES
+ GTEST_INTERNAL_HAS_STRING_VIEW
QT_NO_CAST_TO_ASCII
QT_RESTRICTED_CAST_FROM_ASCII
UNIT_TESTS
DONT_CHECK_MESSAGE_COUNTER
QTC_RESOURCE_DIR="${CMAKE_CURRENT_LIST_DIR}/../../../share/qtcreator"
- TESTDATA_DIR="${CMAKE_CURRENT_BINARY_DIR}/data"
+ TESTDATA_DIR="${CMAKE_CURRENT_SOURCE_DIR}/data"
+ UNITTEST_DIR="${CMAKE_CURRENT_SOURCE_DIR}"
TEST_RELATIVE_LIBEXEC_PATH="${TEST_RELATIVE_LIBEXEC_PATH}"
+ QT6_INSTALL_PREFIX="${QT6_INSTALL_PREFIX}"
+ QDS_MODEL_USE_PROJECTSTORAGEINTERFACE
+ QDS_USE_PROJECTSTORAGE
SOURCES
abstractviewmock.h
conditionally-disabled-tests.h
@@ -49,6 +54,9 @@ add_qtc_test(unittest GTEST
gtest-qt-printing.cpp gtest-qt-printing.h
gtest-std-printing.h
lastchangedrowid-test.cpp
+ import-test.cpp
+ model-test.cpp
+ modelresourcemanagementmock.h
matchingtext-test.cpp
mockfutureinterface.h
mockmutex.h
@@ -59,6 +67,7 @@ add_qtc_test(unittest GTEST
mocktimer.cpp mocktimer.h
nodelistproperty-test.cpp
processevents-utilities.cpp processevents-utilities.h
+ projectstoragemock.cpp projectstoragemock.h
sizedarray-test.cpp
smallstring-test.cpp
spydummy.cpp spydummy.h
@@ -96,6 +105,7 @@ add_qtc_test(unittest GTEST
mockimagecachestorage.h
asynchronousexplicitimagecache-test.cpp
asynchronousimagefactory-test.cpp
+ modulescanner-test.cpp
)
if (NOT TARGET unittest)
@@ -205,16 +215,27 @@ extend_qtc_test(unittest
include/bindingproperty.h
include/imagecacheauxiliarydata.h
include/import.h
+ include/itemlibraryinfo.h
+ include/metainfo.h
+ include/metainforeader.h
include/model.h
include/modelnode.h
include/nodeabstractproperty.h
include/nodelistproperty.h
+ include/nodemetainfo.h
include/nodeproperty.h
include/projectstorageids.h
+ include/propertymetainfo.h
+ include/propertycontainer.h
+ include/propertyparser.h
include/qmldesignercorelib_global.h
include/signalhandlerproperty.h
include/synchronousimagecache.h
include/variantproperty.h
+ metainfo/itemlibraryinfo.cpp
+ metainfo/metainfo.cpp
+ metainfo/metainforeader.cpp
+ metainfo/nodemetainfo.cpp
model/abstractproperty.cpp
model/abstractview.cpp
model/annotation.cpp
@@ -239,16 +260,22 @@ extend_qtc_test(unittest
model/model.cpp
model/model_p.h
model/modelnode.cpp
+ model/modelresourcemanagementinterface.h
+ model/propertycontainer.cpp
+ model/propertyparser.cpp
model/nodeabstractproperty.cpp
model/nodelistproperty.cpp
model/nodeproperty.cpp
model/signalhandlerproperty.cpp
model/variantproperty.cpp
+ pluginmanager/widgetpluginmanager.h pluginmanager/widgetpluginmanager.cpp
+ pluginmanager/widgetpluginpath.h pluginmanager/widgetpluginpath.cpp
projectstorage/directorypathcompressor.h
projectstorage/filesysteminterface.h
projectstorage/filesystem.cpp projectstorage/filesystem.h
projectstorage/filestatus.h
projectstorage/filestatuscache.cpp projectstorage/filestatuscache.h
+ projectstorage/modulescanner.cpp projectstorage/modulescanner.h
projectstorage/nonlockingmutex.h
projectstorage/projectstorageexceptions.cpp projectstorage/projectstorageexceptions.h
projectstorage/projectstorageinterface.h
@@ -314,7 +341,7 @@ endif()
extend_qtc_test(unittest DEPENDS Utils CPlusPlus)
extend_qtc_test(unittest
- CONDITION TARGET Qt6::QmlDomPrivate AND TARGET Qt6::QmlCompilerPrivate AND Qt6_VERSION VERSION_GREATER_EQUAL 6.5.0
+ CONDITION TARGET Qt6::QmlDomPrivate AND TARGET Qt6::QmlCompilerPrivate AND Qt6_VERSION VERSION_GREATER_EQUAL 6.5.0 AND Qt6_VERSION VERSION_LESS 6.6.0
DEPENDS Qt6::QmlDomPrivate Qt6::QmlCompilerPrivate
SOURCES
qmldocumentparser-test.cpp
@@ -322,10 +349,10 @@ extend_qtc_test(unittest
)
extend_qtc_test(unittest
- CONDITION TARGET Qt6::QmlDomPrivate AND TARGET Qt6::QmlCompilerPrivate AND Qt6_VERSION VERSION_GREATER_EQUAL 6.5.0
+ CONDITION TARGET Qt6::QmlDomPrivate AND TARGET Qt6::QmlCompilerPrivate AND Qt6_VERSION VERSION_GREATER_EQUAL 6.5.0 AND Qt6_VERSION VERSION_LESS 6.6.0
SOURCES_PREFIX "${QmlDesignerDir}/designercore"
DEPENDS Qt6::QmlDomPrivate Qt6::QmlCompilerPrivate
- DEFINES QDS_HAS_QMLDOM
+ DEFINES QDS_BUILD_QMLPARSER
SOURCES
projectstorage/qmldocumentparser.cpp projectstorage/qmldocumentparser.h
projectstorage/qmltypesparser.cpp projectstorage/qmltypesparser.h
@@ -336,3 +363,5 @@ set_property(SOURCE ${PROJECTSTORAGE_EXCLUDED_SOURCES} PROPERTY SKIP_AUTOMOC ON)
file(GLOB UNITTEST_EXCLUDED_SOURCES *.cpp)
set_property(SOURCE ${UNITTEST_EXCLUDED_SOURCES} PROPERTY SKIP_AUTOMOC ON)
+
+add_subdirectory(qmlprojectmanager)
diff --git a/tests/unit/unittest/data/modulescanner/Example/qmldir b/tests/unit/unittest/data/modulescanner/Example/qmldir
new file mode 100644
index 00000000000..88203422f01
--- /dev/null
+++ b/tests/unit/unittest/data/modulescanner/Example/qmldir
@@ -0,0 +1,5 @@
+module Example
+MyButton 1.0 MyButton.qml
+MyButton 1.1 MyButton11.qml
+MyButton 1.3 MyButton13.qml
+MyRectangle 1.2 MyRectangle12.qml
diff --git a/tests/unit/unittest/data/qml/QmlTime/qmldir b/tests/unit/unittest/data/qml/QmlTime/qmldir
new file mode 100644
index 00000000000..6610b421041
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QmlTime/qmldir
@@ -0,0 +1,4 @@
+module QmlTime
+typeinfo qmltime.qmltypes
+prefer :/qt-project.org/imports/QmlTime/
+
diff --git a/tests/unit/unittest/data/qml/Qt/labs/animation/qmldir b/tests/unit/unittest/data/qml/Qt/labs/animation/qmldir
new file mode 100644
index 00000000000..5f58f4bb3c2
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt/labs/animation/qmldir
@@ -0,0 +1,8 @@
+module Qt.labs.animation
+linktarget Qt6::labsanimationplugin
+optional plugin labsanimationplugin
+classname QtLabsAnimationPlugin
+typeinfo plugins.qmltypes
+depends QtQml
+prefer :/qt-project.org/imports/Qt/labs/animation/
+
diff --git a/tests/unit/unittest/data/qml/Qt/labs/folderlistmodel/qmldir b/tests/unit/unittest/data/qml/Qt/labs/folderlistmodel/qmldir
new file mode 100644
index 00000000000..5a61a7149d3
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt/labs/folderlistmodel/qmldir
@@ -0,0 +1,8 @@
+module Qt.labs.folderlistmodel
+linktarget Qt6::qmlfolderlistmodelplugin
+optional plugin qmlfolderlistmodelplugin
+classname QmlFolderListModelPlugin
+typeinfo plugins.qmltypes
+depends QtQml.Models auto
+prefer :/qt-project.org/imports/Qt/labs/folderlistmodel/
+
diff --git a/tests/unit/unittest/data/qml/Qt/labs/lottieqt/qmldir b/tests/unit/unittest/data/qml/Qt/labs/lottieqt/qmldir
new file mode 100644
index 00000000000..5d5eb586b36
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt/labs/lottieqt/qmldir
@@ -0,0 +1,8 @@
+module Qt.labs.lottieqt
+linktarget Qt6::lottieqtplugin
+optional plugin lottieqtplugin
+classname BodymovinPlugin
+typeinfo plugins.qmltypes
+depends QtQuick
+prefer :/qt-project.org/imports/Qt/labs/lottieqt/
+
diff --git a/tests/unit/unittest/data/qml/Qt/labs/platform/qmldir b/tests/unit/unittest/data/qml/Qt/labs/platform/qmldir
new file mode 100644
index 00000000000..01800b393b9
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt/labs/platform/qmldir
@@ -0,0 +1,8 @@
+module Qt.labs.platform
+linktarget Qt6::qtlabsplatformplugin
+optional plugin qtlabsplatformplugin
+classname QtLabsPlatformPlugin
+typeinfo plugins.qmltypes
+depends QtQuick
+prefer :/qt-project.org/imports/Qt/labs/platform/
+
diff --git a/tests/unit/unittest/data/qml/Qt/labs/qmlmodels/qmldir b/tests/unit/unittest/data/qml/Qt/labs/qmlmodels/qmldir
new file mode 100644
index 00000000000..6b928f6776f
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt/labs/qmlmodels/qmldir
@@ -0,0 +1,8 @@
+module Qt.labs.qmlmodels
+linktarget Qt6::labsmodelsplugin
+optional plugin labsmodelsplugin
+classname QtQmlLabsModelsPlugin
+typeinfo plugins.qmltypes
+depends QtQml.Models auto
+prefer :/qt-project.org/imports/Qt/labs/qmlmodels/
+
diff --git a/tests/unit/unittest/data/qml/Qt/labs/settings/qmldir b/tests/unit/unittest/data/qml/Qt/labs/settings/qmldir
new file mode 100644
index 00000000000..86b0864288d
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt/labs/settings/qmldir
@@ -0,0 +1,7 @@
+module Qt.labs.settings
+linktarget Qt6::qmlsettingsplugin
+optional plugin qmlsettingsplugin
+classname QmlSettingsPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/Qt/labs/settings/
+
diff --git a/tests/unit/unittest/data/qml/Qt/labs/sharedimage/qmldir b/tests/unit/unittest/data/qml/Qt/labs/sharedimage/qmldir
new file mode 100644
index 00000000000..089730519ce
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt/labs/sharedimage/qmldir
@@ -0,0 +1,8 @@
+module Qt.labs.sharedimage
+linktarget Qt6::sharedimageplugin
+plugin sharedimageplugin
+classname QtQuickSharedImagePlugin
+static
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/Qt/labs/sharedimage/
+
diff --git a/tests/unit/unittest/data/qml/Qt/labs/wavefrontmesh/qmldir b/tests/unit/unittest/data/qml/Qt/labs/wavefrontmesh/qmldir
new file mode 100644
index 00000000000..35e8425429c
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt/labs/wavefrontmesh/qmldir
@@ -0,0 +1,8 @@
+module Qt.labs.wavefrontmesh
+linktarget Qt6::qmlwavefrontmeshplugin
+optional plugin qmlwavefrontmeshplugin
+classname QmlWavefrontMeshPlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/Qt/labs/wavefrontmesh/
+
diff --git a/tests/unit/unittest/data/qml/Qt/test/controls/qmldir b/tests/unit/unittest/data/qml/Qt/test/controls/qmldir
new file mode 100644
index 00000000000..e2ee693d15c
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt/test/controls/qmldir
@@ -0,0 +1,7 @@
+module Qt.test.controls
+linktarget Qt6::QuickControlsTestUtilsPrivateplugin
+optional plugin quickcontrolstestutilsprivateplugin
+classname Qt_test_controlsPlugin
+typeinfo QuickControlsTestUtilsPrivate.qmltypes
+prefer :/qt-project.org/imports/Qt/test/controls/
+
diff --git a/tests/unit/unittest/data/qml/Qt3D/Animation/qmldir b/tests/unit/unittest/data/qml/Qt3D/Animation/qmldir
new file mode 100644
index 00000000000..e122e29243e
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt3D/Animation/qmldir
@@ -0,0 +1,9 @@
+module Qt3D.Animation
+linktarget Qt6::quick3danimationplugin
+plugin quick3danimationplugin
+classname Qt3DQuick3DAnimationPlugin
+typeinfo plugins.qmltypes
+depends QtQml auto
+depends Qt3D.Render auto
+prefer :/qt-project.org/imports/Qt3D/Animation/
+
diff --git a/tests/unit/unittest/data/qml/Qt3D/Core/qmldir b/tests/unit/unittest/data/qml/Qt3D/Core/qmldir
new file mode 100644
index 00000000000..7c8712f946c
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt3D/Core/qmldir
@@ -0,0 +1,8 @@
+module Qt3D.Core
+linktarget Qt6::quick3dcoreplugin
+plugin quick3dcoreplugin
+classname Qt3DQuick3DCorePlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/Qt3D/Core/
+
diff --git a/tests/unit/unittest/data/qml/Qt3D/Extras/qmldir b/tests/unit/unittest/data/qml/Qt3D/Extras/qmldir
new file mode 100644
index 00000000000..c3e41f097f3
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt3D/Extras/qmldir
@@ -0,0 +1,9 @@
+module Qt3D.Extras
+linktarget Qt6::quick3dextrasplugin
+plugin quick3dextrasplugin
+classname Qt3DQuick3DExtrasPlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+depends Qt3D.Logic auto
+prefer :/qt-project.org/imports/Qt3D/Extras/
+
diff --git a/tests/unit/unittest/data/qml/Qt3D/Input/qmldir b/tests/unit/unittest/data/qml/Qt3D/Input/qmldir
new file mode 100644
index 00000000000..b34bf8caeac
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt3D/Input/qmldir
@@ -0,0 +1,8 @@
+module Qt3D.Input
+linktarget Qt6::quick3dinputplugin
+plugin quick3dinputplugin
+classname Qt3DQuick3DInputPlugin
+typeinfo plugins.qmltypes
+depends QtQml auto
+prefer :/qt-project.org/imports/Qt3D/Input/
+
diff --git a/tests/unit/unittest/data/qml/Qt3D/Logic/qmldir b/tests/unit/unittest/data/qml/Qt3D/Logic/qmldir
new file mode 100644
index 00000000000..c61405b9da4
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt3D/Logic/qmldir
@@ -0,0 +1,7 @@
+module Qt3D.Logic
+linktarget Qt6::quick3dlogicplugin
+plugin quick3dlogicplugin
+classname Qt3DQuick3DLogicPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/Qt3D/Logic/
+
diff --git a/tests/unit/unittest/data/qml/Qt3D/Render/qmldir b/tests/unit/unittest/data/qml/Qt3D/Render/qmldir
new file mode 100644
index 00000000000..fe3e762347e
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt3D/Render/qmldir
@@ -0,0 +1,8 @@
+module Qt3D.Render
+linktarget Qt6::quick3drenderplugin
+plugin quick3drenderplugin
+classname Qt3DQuick3DRenderPlugin
+typeinfo plugins.qmltypes
+depends QtQml auto
+prefer :/qt-project.org/imports/Qt3D/Render/
+
diff --git a/tests/unit/unittest/data/qml/Qt5Compat/GraphicalEffects/private/qmldir b/tests/unit/unittest/data/qml/Qt5Compat/GraphicalEffects/private/qmldir
new file mode 100644
index 00000000000..b7d43299006
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt5Compat/GraphicalEffects/private/qmldir
@@ -0,0 +1,21 @@
+module Qt5Compat.GraphicalEffects.private
+linktarget Qt6::qtgraphicaleffectsprivate
+optional plugin qtgraphicaleffectsprivateplugin
+classname QtGraphicalEffectsPrivatePlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/Qt5Compat/GraphicalEffects/private/
+DropShadowBase 6.0 DropShadowBase.qml
+DropShadowBase 1.0 DropShadowBase.qml
+FastGlow 6.0 FastGlow.qml
+FastGlow 1.0 FastGlow.qml
+FastInnerShadow 6.0 FastInnerShadow.qml
+FastInnerShadow 1.0 FastInnerShadow.qml
+GaussianDirectionalBlur 6.0 GaussianDirectionalBlur.qml
+GaussianDirectionalBlur 1.0 GaussianDirectionalBlur.qml
+GaussianGlow 6.0 GaussianGlow.qml
+GaussianGlow 1.0 GaussianGlow.qml
+GaussianInnerShadow 6.0 GaussianInnerShadow.qml
+GaussianInnerShadow 1.0 GaussianInnerShadow.qml
+GaussianMaskedBlur 6.0 GaussianMaskedBlur.qml
+GaussianMaskedBlur 1.0 GaussianMaskedBlur.qml
+
diff --git a/tests/unit/unittest/data/qml/Qt5Compat/GraphicalEffects/qmldir b/tests/unit/unittest/data/qml/Qt5Compat/GraphicalEffects/qmldir
new file mode 100644
index 00000000000..60238eaa0b6
--- /dev/null
+++ b/tests/unit/unittest/data/qml/Qt5Compat/GraphicalEffects/qmldir
@@ -0,0 +1,60 @@
+module Qt5Compat.GraphicalEffects
+linktarget Qt6::qtgraphicaleffectsplugin
+plugin qtgraphicaleffectsplugin
+classname QtGraphicalEffectsPlugin
+designersupported
+typeinfo plugins.qmltypes
+depends Qt5Compat.GraphicalEffects.private
+depends QtQuick.Window
+prefer :/qt-project.org/imports/Qt5Compat/GraphicalEffects/
+Blend 6.0 Blend.qml
+Blend 1.0 Blend.qml
+BrightnessContrast 6.0 BrightnessContrast.qml
+BrightnessContrast 1.0 BrightnessContrast.qml
+ColorOverlay 6.0 ColorOverlay.qml
+ColorOverlay 1.0 ColorOverlay.qml
+Colorize 6.0 Colorize.qml
+Colorize 1.0 Colorize.qml
+ConicalGradient 6.0 ConicalGradient.qml
+ConicalGradient 1.0 ConicalGradient.qml
+Desaturate 6.0 Desaturate.qml
+Desaturate 1.0 Desaturate.qml
+DirectionalBlur 6.0 DirectionalBlur.qml
+DirectionalBlur 1.0 DirectionalBlur.qml
+Displace 6.0 Displace.qml
+Displace 1.0 Displace.qml
+DropShadow 6.0 DropShadow.qml
+DropShadow 1.0 DropShadow.qml
+FastBlur 6.0 FastBlur.qml
+FastBlur 1.0 FastBlur.qml
+GammaAdjust 6.0 GammaAdjust.qml
+GammaAdjust 1.0 GammaAdjust.qml
+GaussianBlur 6.0 GaussianBlur.qml
+GaussianBlur 1.0 GaussianBlur.qml
+Glow 6.0 Glow.qml
+Glow 1.0 Glow.qml
+HueSaturation 6.0 HueSaturation.qml
+HueSaturation 1.0 HueSaturation.qml
+InnerShadow 6.0 InnerShadow.qml
+InnerShadow 1.0 InnerShadow.qml
+LevelAdjust 6.0 LevelAdjust.qml
+LevelAdjust 1.0 LevelAdjust.qml
+LinearGradient 6.0 LinearGradient.qml
+LinearGradient 1.0 LinearGradient.qml
+MaskedBlur 6.0 MaskedBlur.qml
+MaskedBlur 1.0 MaskedBlur.qml
+OpacityMask 6.0 OpacityMask.qml
+OpacityMask 1.0 OpacityMask.qml
+RadialBlur 6.0 RadialBlur.qml
+RadialBlur 1.0 RadialBlur.qml
+RadialGradient 6.0 RadialGradient.qml
+RadialGradient 1.0 RadialGradient.qml
+RectangularGlow 6.0 RectangularGlow.qml
+RectangularGlow 1.0 RectangularGlow.qml
+RecursiveBlur 6.0 RecursiveBlur.qml
+RecursiveBlur 1.0 RecursiveBlur.qml
+ThresholdMask 6.0 ThresholdMask.qml
+ThresholdMask 1.0 ThresholdMask.qml
+ZoomBlur 6.0 ZoomBlur.qml
+ZoomBlur 1.0 ZoomBlur.qml
+
diff --git a/tests/unit/unittest/data/qml/QtApplicationManager/Application/qmldir b/tests/unit/unittest/data/qml/QtApplicationManager/Application/qmldir
new file mode 100644
index 00000000000..4ed2cd6755f
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtApplicationManager/Application/qmldir
@@ -0,0 +1 @@
+typeinfo plugins.qmltypes
diff --git a/tests/unit/unittest/data/qml/QtApplicationManager/SystemUI/qmldir b/tests/unit/unittest/data/qml/QtApplicationManager/SystemUI/qmldir
new file mode 100644
index 00000000000..4ed2cd6755f
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtApplicationManager/SystemUI/qmldir
@@ -0,0 +1 @@
+typeinfo plugins.qmltypes
diff --git a/tests/unit/unittest/data/qml/QtApplicationManager/qmldir b/tests/unit/unittest/data/qml/QtApplicationManager/qmldir
new file mode 100644
index 00000000000..4ed2cd6755f
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtApplicationManager/qmldir
@@ -0,0 +1 @@
+typeinfo plugins.qmltypes
diff --git a/tests/unit/unittest/data/qml/QtCharts/qmldir b/tests/unit/unittest/data/qml/QtCharts/qmldir
new file mode 100644
index 00000000000..42d00490467
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtCharts/qmldir
@@ -0,0 +1,10 @@
+module QtCharts
+linktarget Qt6::qtchartsqml2
+optional plugin qtchartsqml2plugin
+classname QtChartsQml2Plugin
+designersupported
+typeinfo plugins.qmltypes
+depends QtQuick
+depends QtCharts
+prefer :/qt-project.org/imports/QtCharts/
+
diff --git a/tests/unit/unittest/data/qml/QtCore/qmldir b/tests/unit/unittest/data/qml/QtCore/qmldir
new file mode 100644
index 00000000000..d652bb201b4
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtCore/qmldir
@@ -0,0 +1,9 @@
+module QtCore
+linktarget Qt6::qtqmlcoreplugin
+optional plugin qtqmlcoreplugin
+classname QtQmlCorePlugin
+designersupported
+typeinfo plugins.qmltypes
+depends QtQml auto
+prefer :/qt-project.org/imports/QtCore/
+
diff --git a/tests/unit/unittest/data/qml/QtDataVisualization/qmldir b/tests/unit/unittest/data/qml/QtDataVisualization/qmldir
new file mode 100644
index 00000000000..714749cb3c6
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtDataVisualization/qmldir
@@ -0,0 +1,8 @@
+module QtDataVisualization
+linktarget Qt6::DataVisualizationQmlplugin
+optional plugin datavisualizationqmlplugin
+classname QtDataVisualizationPlugin
+typeinfo plugins.qmltypes
+depends QtQuick
+prefer :/qt-project.org/imports/QtDataVisualization/
+
diff --git a/tests/unit/unittest/data/qml/QtInsightTracker/qmldir b/tests/unit/unittest/data/qml/QtInsightTracker/qmldir
new file mode 100644
index 00000000000..e9126a4513a
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtInsightTracker/qmldir
@@ -0,0 +1,7 @@
+module QtInsightTracker
+linktarget Qt6::InsightTrackerQmlplugin
+optional plugin insighttrackerqmlplugin
+classname QtInsightTrackerPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtInsightTracker/
+
diff --git a/tests/unit/unittest/data/qml/QtInterfaceFramework/Media/qmldir b/tests/unit/unittest/data/qml/QtInterfaceFramework/Media/qmldir
new file mode 100644
index 00000000000..bcd1c145e04
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtInterfaceFramework/Media/qmldir
@@ -0,0 +1,8 @@
+module QtInterfaceFramework.Media
+linktarget Qt6::IfMediaplugin
+optional plugin ifmediaplugin
+classname QIfMediaPlugin
+typeinfo plugins.qmltypes
+import QtInterfaceFramework auto
+prefer :/qt-project.org/imports/QtInterfaceFramework/Media/
+
diff --git a/tests/unit/unittest/data/qml/QtInterfaceFramework/VehicleFunctions/qmldir b/tests/unit/unittest/data/qml/QtInterfaceFramework/VehicleFunctions/qmldir
new file mode 100644
index 00000000000..009e335aea4
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtInterfaceFramework/VehicleFunctions/qmldir
@@ -0,0 +1,8 @@
+module QtInterfaceFramework.VehicleFunctions
+linktarget Qt6::qtifvehiclefunctionsplugin
+optional plugin qtifvehiclefunctionsplugin
+classname QtIfVehicleFunctionsPlugin
+typeinfo IfVehicleFunctions.qmltypes
+import QtInterfaceFramework auto
+prefer :/qt-project.org/imports/QtInterfaceFramework/VehicleFunctions/
+
diff --git a/tests/unit/unittest/data/qml/QtInterfaceFramework/qmldir b/tests/unit/unittest/data/qml/QtInterfaceFramework/qmldir
new file mode 100644
index 00000000000..727eaf99b77
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtInterfaceFramework/qmldir
@@ -0,0 +1,7 @@
+module QtInterfaceFramework
+linktarget Qt6::InterfaceFrameworkplugin
+optional plugin interfaceframeworkplugin
+classname QtInterfaceFrameworkPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtInterfaceFramework/
+
diff --git a/tests/unit/unittest/data/qml/QtLocation/qmldir b/tests/unit/unittest/data/qml/QtLocation/qmldir
new file mode 100644
index 00000000000..207cd8959b4
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtLocation/qmldir
@@ -0,0 +1,8 @@
+module QtLocation
+linktarget Qt6::declarative_location
+plugin declarative_locationplugin
+classname QtLocationDeclarativeModule
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtLocation/
+MapView 6.0 MapView.qml
+
diff --git a/tests/unit/unittest/data/qml/QtMultimedia/qmldir b/tests/unit/unittest/data/qml/QtMultimedia/qmldir
new file mode 100644
index 00000000000..82f64177ebf
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtMultimedia/qmldir
@@ -0,0 +1,10 @@
+module QtMultimedia
+linktarget Qt6::quickmultimedia
+plugin quickmultimediaplugin
+classname QMultimediaQuickModule
+typeinfo plugins.qmltypes
+depends QtQuick
+prefer :/qt-project.org/imports/QtMultimedia/
+Video 6.0 Video.qml
+Video 5.0 Video.qml
+
diff --git a/tests/unit/unittest/data/qml/QtOpcUa/qmldir b/tests/unit/unittest/data/qml/QtOpcUa/qmldir
new file mode 100644
index 00000000000..4d745231296
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtOpcUa/qmldir
@@ -0,0 +1,8 @@
+module QtOpcUa
+linktarget Qt6::DeclarativeOpcuaplugin
+optional plugin declarativeopcuaplugin
+classname QtOpcUaPlugin
+typeinfo plugins.qmltypes
+depends QtQuick
+prefer :/qt-project.org/imports/QtOpcUa/
+
diff --git a/tests/unit/unittest/data/qml/QtPositioning/qmldir b/tests/unit/unittest/data/qml/QtPositioning/qmldir
new file mode 100644
index 00000000000..9ae0891d083
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtPositioning/qmldir
@@ -0,0 +1,8 @@
+module QtPositioning
+linktarget Qt6::positioningquickplugin
+plugin positioningquickplugin
+classname QtPositioningDeclarativeModule
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtPositioning/
+
diff --git a/tests/unit/unittest/data/qml/QtQml/Base/qmldir b/tests/unit/unittest/data/qml/QtQml/Base/qmldir
new file mode 100644
index 00000000000..7f2da0f0d81
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQml/Base/qmldir
@@ -0,0 +1,9 @@
+module QtQml.Base
+linktarget Qt6::qmlplugin
+optional plugin qmlplugin
+classname QtQmlPlugin
+designersupported
+system
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtQml/Base/
+
diff --git a/tests/unit/unittest/data/qml/QtQml/Models/qmldir b/tests/unit/unittest/data/qml/QtQml/Models/qmldir
new file mode 100644
index 00000000000..60eac9bf196
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQml/Models/qmldir
@@ -0,0 +1,9 @@
+module QtQml.Models
+linktarget Qt6::modelsplugin
+optional plugin modelsplugin
+classname QtQmlModelsPlugin
+designersupported
+typeinfo plugins.qmltypes
+depends QtQml.Base auto
+prefer :/qt-project.org/imports/QtQml/Models/
+
diff --git a/tests/unit/unittest/data/qml/QtQml/StateMachine/qmldir b/tests/unit/unittest/data/qml/QtQml/StateMachine/qmldir
new file mode 100644
index 00000000000..943791ea154
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQml/StateMachine/qmldir
@@ -0,0 +1,8 @@
+module QtQml.StateMachine
+linktarget Qt6::qtqmlstatemachine
+optional plugin qtqmlstatemachineplugin
+classname QtQmlStateMachinePlugin
+typeinfo plugins.qmltypes
+depends QtQml
+prefer :/qt-project.org/imports/QtQml/StateMachine/
+
diff --git a/tests/unit/unittest/data/qml/QtQml/WorkerScript/qmldir b/tests/unit/unittest/data/qml/QtQml/WorkerScript/qmldir
new file mode 100644
index 00000000000..a4de5f38b28
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQml/WorkerScript/qmldir
@@ -0,0 +1,9 @@
+module QtQml.WorkerScript
+linktarget Qt6::workerscriptplugin
+optional plugin workerscriptplugin
+classname QtQmlWorkerScriptPlugin
+designersupported
+typeinfo plugins.qmltypes
+depends QtQml.Base auto
+prefer :/qt-project.org/imports/QtQml/WorkerScript/
+
diff --git a/tests/unit/unittest/data/qml/QtQml/XmlListModel/qmldir b/tests/unit/unittest/data/qml/QtQml/XmlListModel/qmldir
new file mode 100644
index 00000000000..f04f990ef12
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQml/XmlListModel/qmldir
@@ -0,0 +1,8 @@
+module QtQml.XmlListModel
+linktarget Qt6::qmlxmllistmodelplugin
+optional plugin qmlxmllistmodelplugin
+classname QtQmlXmlListModelPlugin
+typeinfo plugins.qmltypes
+depends QtQml auto
+prefer :/qt-project.org/imports/QtQml/XmlListModel/
+
diff --git a/tests/unit/unittest/data/qml/QtQml/qmldir b/tests/unit/unittest/data/qml/QtQml/qmldir
new file mode 100644
index 00000000000..ae6977b9d97
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQml/qmldir
@@ -0,0 +1,10 @@
+module QtQml
+linktarget Qt6::QmlMeta
+optional plugin qmlmetaplugin
+classname QtQmlMetaPlugin
+designersupported
+import QtQml.Base auto
+import QtQml.Models auto
+import QtQml.WorkerScript auto
+prefer :/qt-project.org/imports/QtQml/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Controls/Basic/impl/qmldir b/tests/unit/unittest/data/qml/QtQuick/Controls/Basic/impl/qmldir
new file mode 100644
index 00000000000..d09bc6a1938
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Controls/Basic/impl/qmldir
@@ -0,0 +1,7 @@
+module QtQuick.Controls.Basic.impl
+linktarget Qt6::qtquickcontrols2basicstyleimplplugin
+plugin qtquickcontrols2basicstyleimplplugin
+classname QtQuickControls2BasicStyleImplPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtQuick/Controls/Basic/impl/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Controls/Basic/qmldir b/tests/unit/unittest/data/qml/QtQuick/Controls/Basic/qmldir
new file mode 100644
index 00000000000..8460bd3bf21
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Controls/Basic/qmldir
@@ -0,0 +1,131 @@
+module QtQuick.Controls.Basic
+linktarget Qt6::qtquickcontrols2basicstyleplugin
+plugin qtquickcontrols2basicstyleplugin
+classname QtQuickControls2BasicStylePlugin
+typeinfo plugins.qmltypes
+import QtQuick.Controls.impl auto
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Controls/Basic/
+AbstractButton 6.0 AbstractButton.qml
+AbstractButton 2.0 AbstractButton.qml
+Action 2.3 Action.qml
+Action 6.0 Action.qml
+ActionGroup 2.3 ActionGroup.qml
+ActionGroup 6.0 ActionGroup.qml
+ApplicationWindow 6.0 ApplicationWindow.qml
+ApplicationWindow 2.0 ApplicationWindow.qml
+BusyIndicator 6.0 BusyIndicator.qml
+BusyIndicator 2.0 BusyIndicator.qml
+Button 6.0 Button.qml
+Button 2.0 Button.qml
+ButtonGroup 6.0 ButtonGroup.qml
+ButtonGroup 2.0 ButtonGroup.qml
+CheckBox 6.0 CheckBox.qml
+CheckBox 2.0 CheckBox.qml
+CheckDelegate 6.0 CheckDelegate.qml
+CheckDelegate 2.0 CheckDelegate.qml
+ComboBox 6.0 ComboBox.qml
+ComboBox 2.0 ComboBox.qml
+Container 6.0 Container.qml
+Container 2.0 Container.qml
+Control 6.0 Control.qml
+Control 2.0 Control.qml
+DelayButton 2.2 DelayButton.qml
+DelayButton 6.0 DelayButton.qml
+Dial 6.0 Dial.qml
+Dial 2.0 Dial.qml
+Dialog 2.1 Dialog.qml
+Dialog 6.0 Dialog.qml
+DialogButtonBox 2.1 DialogButtonBox.qml
+DialogButtonBox 6.0 DialogButtonBox.qml
+Drawer 6.0 Drawer.qml
+Drawer 2.0 Drawer.qml
+Frame 6.0 Frame.qml
+Frame 2.0 Frame.qml
+GroupBox 6.0 GroupBox.qml
+GroupBox 2.0 GroupBox.qml
+HorizontalHeaderView 2.15 HorizontalHeaderView.qml
+HorizontalHeaderView 6.0 HorizontalHeaderView.qml
+ItemDelegate 6.0 ItemDelegate.qml
+ItemDelegate 2.0 ItemDelegate.qml
+Label 6.0 Label.qml
+Label 2.0 Label.qml
+Menu 6.0 Menu.qml
+Menu 2.0 Menu.qml
+MenuBar 2.3 MenuBar.qml
+MenuBar 6.0 MenuBar.qml
+MenuBarItem 2.3 MenuBarItem.qml
+MenuBarItem 6.0 MenuBarItem.qml
+MenuItem 6.0 MenuItem.qml
+MenuItem 2.0 MenuItem.qml
+MenuSeparator 2.1 MenuSeparator.qml
+MenuSeparator 6.0 MenuSeparator.qml
+Page 6.0 Page.qml
+Page 2.0 Page.qml
+PageIndicator 6.0 PageIndicator.qml
+PageIndicator 2.0 PageIndicator.qml
+Pane 6.0 Pane.qml
+Pane 2.0 Pane.qml
+Popup 6.0 Popup.qml
+Popup 2.0 Popup.qml
+ProgressBar 6.0 ProgressBar.qml
+ProgressBar 2.0 ProgressBar.qml
+RadioButton 6.0 RadioButton.qml
+RadioButton 2.0 RadioButton.qml
+RadioDelegate 6.0 RadioDelegate.qml
+RadioDelegate 2.0 RadioDelegate.qml
+RangeSlider 6.0 RangeSlider.qml
+RangeSlider 2.0 RangeSlider.qml
+RoundButton 2.1 RoundButton.qml
+RoundButton 6.0 RoundButton.qml
+ScrollBar 6.0 ScrollBar.qml
+ScrollBar 2.0 ScrollBar.qml
+ScrollIndicator 6.0 ScrollIndicator.qml
+ScrollIndicator 2.0 ScrollIndicator.qml
+ScrollView 2.2 ScrollView.qml
+ScrollView 6.0 ScrollView.qml
+SelectionRectangle 6.2 SelectionRectangle.qml
+Slider 6.0 Slider.qml
+Slider 2.0 Slider.qml
+SpinBox 6.0 SpinBox.qml
+SpinBox 2.0 SpinBox.qml
+SplitView 2.13 SplitView.qml
+SplitView 6.0 SplitView.qml
+StackView 6.0 StackView.qml
+StackView 2.0 StackView.qml
+SwipeDelegate 6.0 SwipeDelegate.qml
+SwipeDelegate 2.0 SwipeDelegate.qml
+Switch 6.0 Switch.qml
+Switch 2.0 Switch.qml
+SwitchDelegate 6.0 SwitchDelegate.qml
+SwitchDelegate 2.0 SwitchDelegate.qml
+SwipeView 6.0 SwipeView.qml
+SwipeView 2.0 SwipeView.qml
+TabBar 6.0 TabBar.qml
+TabBar 2.0 TabBar.qml
+TabButton 6.0 TabButton.qml
+TabButton 2.0 TabButton.qml
+TextArea 6.0 TextArea.qml
+TextArea 2.0 TextArea.qml
+TextField 6.0 TextField.qml
+TextField 2.0 TextField.qml
+ToolBar 6.0 ToolBar.qml
+ToolBar 2.0 ToolBar.qml
+ToolButton 6.0 ToolButton.qml
+ToolButton 2.0 ToolButton.qml
+ToolSeparator 2.1 ToolSeparator.qml
+ToolSeparator 6.0 ToolSeparator.qml
+ToolTip 6.0 ToolTip.qml
+ToolTip 2.0 ToolTip.qml
+Tumbler 6.0 Tumbler.qml
+Tumbler 2.0 Tumbler.qml
+VerticalHeaderView 2.15 VerticalHeaderView.qml
+VerticalHeaderView 6.0 VerticalHeaderView.qml
+singleton Calendar 6.3 Calendar.qml
+CalendarModel 6.3 CalendarModel.qml
+DayOfWeekRow 6.3 DayOfWeekRow.qml
+MonthGrid 6.3 MonthGrid.qml
+WeekNumberColumn 6.3 WeekNumberColumn.qml
+TreeViewDelegate 6.0 TreeViewDelegate.qml
+TreeViewDelegate 2.0 TreeViewDelegate.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Controls/Fusion/impl/qmldir b/tests/unit/unittest/data/qml/QtQuick/Controls/Fusion/impl/qmldir
new file mode 100644
index 00000000000..69e0bec723b
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Controls/Fusion/impl/qmldir
@@ -0,0 +1,20 @@
+module QtQuick.Controls.Fusion.impl
+linktarget Qt6::qtquickcontrols2fusionstyleimplplugin
+plugin qtquickcontrols2fusionstyleimplplugin
+classname QtQuickControls2FusionStyleImplPlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Controls/Fusion/impl/
+ButtonPanel 6.0 ButtonPanel.qml
+ButtonPanel 2.0 ButtonPanel.qml
+CheckIndicator 6.0 CheckIndicator.qml
+CheckIndicator 2.0 CheckIndicator.qml
+RadioIndicator 6.0 RadioIndicator.qml
+RadioIndicator 2.0 RadioIndicator.qml
+SliderGroove 6.0 SliderGroove.qml
+SliderGroove 2.0 SliderGroove.qml
+SliderHandle 6.0 SliderHandle.qml
+SliderHandle 2.0 SliderHandle.qml
+SwitchIndicator 6.0 SwitchIndicator.qml
+SwitchIndicator 2.0 SwitchIndicator.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Controls/Fusion/qmldir b/tests/unit/unittest/data/qml/QtQuick/Controls/Fusion/qmldir
new file mode 100644
index 00000000000..37e8a1407a6
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Controls/Fusion/qmldir
@@ -0,0 +1,111 @@
+module QtQuick.Controls.Fusion
+linktarget Qt6::qtquickcontrols2fusionstyleplugin
+plugin qtquickcontrols2fusionstyleplugin
+classname QtQuickControls2FusionStylePlugin
+typeinfo plugins.qmltypes
+import QtQuick.Controls.Basic auto
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Controls/Fusion/
+ApplicationWindow 6.0 ApplicationWindow.qml
+ApplicationWindow 2.0 ApplicationWindow.qml
+BusyIndicator 6.0 BusyIndicator.qml
+BusyIndicator 2.0 BusyIndicator.qml
+Button 6.0 Button.qml
+Button 2.0 Button.qml
+CheckBox 6.0 CheckBox.qml
+CheckBox 2.0 CheckBox.qml
+CheckDelegate 6.0 CheckDelegate.qml
+CheckDelegate 2.0 CheckDelegate.qml
+ComboBox 6.0 ComboBox.qml
+ComboBox 2.0 ComboBox.qml
+DelayButton 2.2 DelayButton.qml
+DelayButton 6.0 DelayButton.qml
+Dial 6.0 Dial.qml
+Dial 2.0 Dial.qml
+Dialog 2.1 Dialog.qml
+Dialog 6.0 Dialog.qml
+DialogButtonBox 2.1 DialogButtonBox.qml
+DialogButtonBox 6.0 DialogButtonBox.qml
+Drawer 6.0 Drawer.qml
+Drawer 2.0 Drawer.qml
+Frame 6.0 Frame.qml
+Frame 2.0 Frame.qml
+GroupBox 6.0 GroupBox.qml
+GroupBox 2.0 GroupBox.qml
+HorizontalHeaderView 2.15 HorizontalHeaderView.qml
+HorizontalHeaderView 6.0 HorizontalHeaderView.qml
+ItemDelegate 6.0 ItemDelegate.qml
+ItemDelegate 2.0 ItemDelegate.qml
+Label 6.0 Label.qml
+Label 2.0 Label.qml
+Menu 6.0 Menu.qml
+Menu 2.0 Menu.qml
+MenuBar 2.3 MenuBar.qml
+MenuBar 6.0 MenuBar.qml
+MenuBarItem 2.3 MenuBarItem.qml
+MenuBarItem 6.0 MenuBarItem.qml
+MenuItem 6.0 MenuItem.qml
+MenuItem 2.0 MenuItem.qml
+MenuSeparator 2.1 MenuSeparator.qml
+MenuSeparator 6.0 MenuSeparator.qml
+Page 6.0 Page.qml
+Page 2.0 Page.qml
+PageIndicator 6.0 PageIndicator.qml
+PageIndicator 2.0 PageIndicator.qml
+Pane 6.0 Pane.qml
+Pane 2.0 Pane.qml
+Popup 6.0 Popup.qml
+Popup 2.0 Popup.qml
+ProgressBar 6.0 ProgressBar.qml
+ProgressBar 2.0 ProgressBar.qml
+RadioButton 6.0 RadioButton.qml
+RadioButton 2.0 RadioButton.qml
+RadioDelegate 6.0 RadioDelegate.qml
+RadioDelegate 2.0 RadioDelegate.qml
+RangeSlider 6.0 RangeSlider.qml
+RangeSlider 2.0 RangeSlider.qml
+RoundButton 2.1 RoundButton.qml
+RoundButton 6.0 RoundButton.qml
+ScrollBar 6.0 ScrollBar.qml
+ScrollBar 2.0 ScrollBar.qml
+ScrollView 6.0 ScrollView.qml
+ScrollView 2.0 ScrollView.qml
+ScrollIndicator 6.0 ScrollIndicator.qml
+ScrollIndicator 2.0 ScrollIndicator.qml
+SelectionRectangle 6.0 SelectionRectangle.qml
+SelectionRectangle 2.0 SelectionRectangle.qml
+Slider 6.0 Slider.qml
+Slider 2.0 Slider.qml
+SpinBox 6.0 SpinBox.qml
+SpinBox 2.0 SpinBox.qml
+SplitView 2.13 SplitView.qml
+SplitView 6.0 SplitView.qml
+SwipeDelegate 6.0 SwipeDelegate.qml
+SwipeDelegate 2.0 SwipeDelegate.qml
+SwitchDelegate 6.0 SwitchDelegate.qml
+SwitchDelegate 2.0 SwitchDelegate.qml
+Switch 6.0 Switch.qml
+Switch 2.0 Switch.qml
+TabBar 6.0 TabBar.qml
+TabBar 2.0 TabBar.qml
+TabButton 6.0 TabButton.qml
+TabButton 2.0 TabButton.qml
+TextArea 6.0 TextArea.qml
+TextArea 2.0 TextArea.qml
+TextField 6.0 TextField.qml
+TextField 2.0 TextField.qml
+ToolBar 6.0 ToolBar.qml
+ToolBar 2.0 ToolBar.qml
+ToolButton 6.0 ToolButton.qml
+ToolButton 2.0 ToolButton.qml
+ToolSeparator 2.1 ToolSeparator.qml
+ToolSeparator 6.0 ToolSeparator.qml
+ToolTip 6.0 ToolTip.qml
+ToolTip 2.0 ToolTip.qml
+TreeViewDelegate 6.0 TreeViewDelegate.qml
+TreeViewDelegate 2.0 TreeViewDelegate.qml
+Tumbler 6.0 Tumbler.qml
+Tumbler 2.0 Tumbler.qml
+VerticalHeaderView 2.15 VerticalHeaderView.qml
+VerticalHeaderView 6.0 VerticalHeaderView.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Controls/Imagine/impl/qmldir b/tests/unit/unittest/data/qml/QtQuick/Controls/Imagine/impl/qmldir
new file mode 100644
index 00000000000..7cdf5d634be
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Controls/Imagine/impl/qmldir
@@ -0,0 +1,9 @@
+module QtQuick.Controls.Imagine.impl
+linktarget Qt6::qtquickcontrols2imaginestyleimplplugin
+plugin qtquickcontrols2imaginestyleimplplugin
+classname QtQuickControls2ImagineStyleImplPlugin
+typeinfo qtquickcontrols2imaginestyleimplplugin.qmltypes
+import QtQuick.Controls.impl auto
+prefer :/qt-project.org/imports/QtQuick/Controls/Imagine/impl/
+OpacityMask 6.0 OpacityMask.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Controls/Imagine/qmldir b/tests/unit/unittest/data/qml/QtQuick/Controls/Imagine/qmldir
new file mode 100644
index 00000000000..adce0e5148e
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Controls/Imagine/qmldir
@@ -0,0 +1,108 @@
+module QtQuick.Controls.Imagine
+linktarget Qt6::qtquickcontrols2imaginestyleplugin
+plugin qtquickcontrols2imaginestyleplugin
+classname QtQuickControls2ImagineStylePlugin
+typeinfo plugins.qmltypes
+import QtQuick.Controls.Basic auto
+prefer :/qt-project.org/imports/QtQuick/Controls/Imagine/
+ApplicationWindow 6.0 ApplicationWindow.qml
+ApplicationWindow 2.0 ApplicationWindow.qml
+BusyIndicator 6.0 BusyIndicator.qml
+BusyIndicator 2.0 BusyIndicator.qml
+Button 6.0 Button.qml
+Button 2.0 Button.qml
+CheckBox 6.0 CheckBox.qml
+CheckBox 2.0 CheckBox.qml
+CheckDelegate 6.0 CheckDelegate.qml
+CheckDelegate 2.0 CheckDelegate.qml
+ComboBox 6.0 ComboBox.qml
+ComboBox 2.0 ComboBox.qml
+DelayButton 2.2 DelayButton.qml
+DelayButton 6.0 DelayButton.qml
+Dial 6.0 Dial.qml
+Dial 2.0 Dial.qml
+Dialog 2.1 Dialog.qml
+Dialog 6.0 Dialog.qml
+DialogButtonBox 2.1 DialogButtonBox.qml
+DialogButtonBox 6.0 DialogButtonBox.qml
+Drawer 6.0 Drawer.qml
+Drawer 2.0 Drawer.qml
+Frame 6.0 Frame.qml
+Frame 2.0 Frame.qml
+GroupBox 6.0 GroupBox.qml
+GroupBox 2.0 GroupBox.qml
+HorizontalHeaderView 2.15 HorizontalHeaderView.qml
+HorizontalHeaderView 6.0 HorizontalHeaderView.qml
+ItemDelegate 6.0 ItemDelegate.qml
+ItemDelegate 2.0 ItemDelegate.qml
+Label 6.0 Label.qml
+Label 2.0 Label.qml
+Menu 6.0 Menu.qml
+Menu 2.0 Menu.qml
+MenuItem 6.0 MenuItem.qml
+MenuItem 2.0 MenuItem.qml
+MenuSeparator 2.1 MenuSeparator.qml
+MenuSeparator 6.0 MenuSeparator.qml
+PageIndicator 6.0 PageIndicator.qml
+PageIndicator 2.0 PageIndicator.qml
+Page 6.0 Page.qml
+Page 2.0 Page.qml
+Pane 6.0 Pane.qml
+Pane 2.0 Pane.qml
+Popup 6.0 Popup.qml
+Popup 2.0 Popup.qml
+ProgressBar 6.0 ProgressBar.qml
+ProgressBar 2.0 ProgressBar.qml
+RadioButton 6.0 RadioButton.qml
+RadioButton 2.0 RadioButton.qml
+RadioDelegate 6.0 RadioDelegate.qml
+RadioDelegate 2.0 RadioDelegate.qml
+RangeSlider 6.0 RangeSlider.qml
+RangeSlider 2.0 RangeSlider.qml
+RoundButton 2.1 RoundButton.qml
+RoundButton 6.0 RoundButton.qml
+ScrollView 6.0 ScrollView.qml
+ScrollView 2.0 ScrollView.qml
+ScrollBar 6.0 ScrollBar.qml
+ScrollBar 2.0 ScrollBar.qml
+ScrollIndicator 6.0 ScrollIndicator.qml
+ScrollIndicator 2.0 ScrollIndicator.qml
+SelectionRectangle 6.0 SelectionRectangle.qml
+SelectionRectangle 2.0 SelectionRectangle.qml
+Slider 6.0 Slider.qml
+Slider 2.0 Slider.qml
+SpinBox 6.0 SpinBox.qml
+SpinBox 2.0 SpinBox.qml
+SplitView 2.13 SplitView.qml
+SplitView 6.0 SplitView.qml
+StackView 6.0 StackView.qml
+StackView 2.0 StackView.qml
+SwipeDelegate 6.0 SwipeDelegate.qml
+SwipeDelegate 2.0 SwipeDelegate.qml
+SwipeView 6.0 SwipeView.qml
+SwipeView 2.0 SwipeView.qml
+Switch 6.0 Switch.qml
+Switch 2.0 Switch.qml
+SwitchDelegate 6.0 SwitchDelegate.qml
+SwitchDelegate 2.0 SwitchDelegate.qml
+TextField 6.0 TextField.qml
+TextField 2.0 TextField.qml
+TextArea 6.0 TextArea.qml
+TextArea 2.0 TextArea.qml
+TabBar 6.0 TabBar.qml
+TabBar 2.0 TabBar.qml
+TabButton 6.0 TabButton.qml
+TabButton 2.0 TabButton.qml
+ToolBar 6.0 ToolBar.qml
+ToolBar 2.0 ToolBar.qml
+ToolButton 6.0 ToolButton.qml
+ToolButton 2.0 ToolButton.qml
+ToolSeparator 2.1 ToolSeparator.qml
+ToolSeparator 6.0 ToolSeparator.qml
+ToolTip 6.0 ToolTip.qml
+ToolTip 2.0 ToolTip.qml
+Tumbler 6.0 Tumbler.qml
+Tumbler 2.0 Tumbler.qml
+VerticalHeaderView 2.15 VerticalHeaderView.qml
+VerticalHeaderView 6.0 VerticalHeaderView.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Controls/Material/impl/qmldir b/tests/unit/unittest/data/qml/QtQuick/Controls/Material/impl/qmldir
new file mode 100644
index 00000000000..3608a16f083
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Controls/Material/impl/qmldir
@@ -0,0 +1,26 @@
+module QtQuick.Controls.Material.impl
+linktarget Qt6::qtquickcontrols2materialstyleimplplugin
+plugin qtquickcontrols2materialstyleimplplugin
+classname QtQuickControls2MaterialStyleImplPlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Controls/Material/impl/
+BoxShadow 6.0 BoxShadow.qml
+BoxShadow 2.0 BoxShadow.qml
+CheckIndicator 6.0 CheckIndicator.qml
+CheckIndicator 2.0 CheckIndicator.qml
+CursorDelegate 6.0 CursorDelegate.qml
+CursorDelegate 2.0 CursorDelegate.qml
+ElevationEffect 6.0 ElevationEffect.qml
+ElevationEffect 2.0 ElevationEffect.qml
+RadioIndicator 6.0 RadioIndicator.qml
+RadioIndicator 2.0 RadioIndicator.qml
+RectangularGlow 6.0 RectangularGlow.qml
+RectangularGlow 2.0 RectangularGlow.qml
+RoundedElevationEffect 6.0 RoundedElevationEffect.qml
+RoundedElevationEffect 2.0 RoundedElevationEffect.qml
+SliderHandle 6.0 SliderHandle.qml
+SliderHandle 2.0 SliderHandle.qml
+SwitchIndicator 6.0 SwitchIndicator.qml
+SwitchIndicator 2.0 SwitchIndicator.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Controls/Material/qmldir b/tests/unit/unittest/data/qml/QtQuick/Controls/Material/qmldir
new file mode 100644
index 00000000000..9965cfe2ad7
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Controls/Material/qmldir
@@ -0,0 +1,115 @@
+module QtQuick.Controls.Material
+linktarget Qt6::qtquickcontrols2materialstyleplugin
+plugin qtquickcontrols2materialstyleplugin
+classname QtQuickControls2MaterialStylePlugin
+typeinfo plugins.qmltypes
+import QtQuick.Controls.Basic auto
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Controls/Material/
+ApplicationWindow 6.0 ApplicationWindow.qml
+ApplicationWindow 2.0 ApplicationWindow.qml
+BusyIndicator 6.0 BusyIndicator.qml
+BusyIndicator 2.0 BusyIndicator.qml
+Button 6.0 Button.qml
+Button 2.0 Button.qml
+CheckBox 6.0 CheckBox.qml
+CheckBox 2.0 CheckBox.qml
+CheckDelegate 6.0 CheckDelegate.qml
+CheckDelegate 2.0 CheckDelegate.qml
+ComboBox 6.0 ComboBox.qml
+ComboBox 2.0 ComboBox.qml
+DelayButton 2.2 DelayButton.qml
+DelayButton 6.0 DelayButton.qml
+Dial 6.0 Dial.qml
+Dial 2.0 Dial.qml
+Dialog 2.1 Dialog.qml
+Dialog 6.0 Dialog.qml
+DialogButtonBox 2.1 DialogButtonBox.qml
+DialogButtonBox 6.0 DialogButtonBox.qml
+Drawer 6.0 Drawer.qml
+Drawer 2.0 Drawer.qml
+Frame 6.0 Frame.qml
+Frame 2.0 Frame.qml
+GroupBox 6.0 GroupBox.qml
+GroupBox 2.0 GroupBox.qml
+HorizontalHeaderView 2.15 HorizontalHeaderView.qml
+HorizontalHeaderView 6.0 HorizontalHeaderView.qml
+ItemDelegate 6.0 ItemDelegate.qml
+ItemDelegate 2.0 ItemDelegate.qml
+Label 6.0 Label.qml
+Label 2.0 Label.qml
+Menu 6.0 Menu.qml
+Menu 2.0 Menu.qml
+MenuBar 2.3 MenuBar.qml
+MenuBar 6.0 MenuBar.qml
+MenuBarItem 2.3 MenuBarItem.qml
+MenuBarItem 6.0 MenuBarItem.qml
+MenuItem 6.0 MenuItem.qml
+MenuItem 2.0 MenuItem.qml
+MenuSeparator 2.1 MenuSeparator.qml
+MenuSeparator 6.0 MenuSeparator.qml
+Page 6.0 Page.qml
+Page 2.0 Page.qml
+PageIndicator 6.0 PageIndicator.qml
+PageIndicator 2.0 PageIndicator.qml
+Pane 6.0 Pane.qml
+Pane 2.0 Pane.qml
+Popup 6.0 Popup.qml
+Popup 2.0 Popup.qml
+ProgressBar 6.0 ProgressBar.qml
+ProgressBar 2.0 ProgressBar.qml
+RadioButton 6.0 RadioButton.qml
+RadioButton 2.0 RadioButton.qml
+RadioDelegate 6.0 RadioDelegate.qml
+RadioDelegate 2.0 RadioDelegate.qml
+RangeSlider 6.0 RangeSlider.qml
+RangeSlider 2.0 RangeSlider.qml
+RoundButton 2.1 RoundButton.qml
+RoundButton 6.0 RoundButton.qml
+ScrollView 6.0 ScrollView.qml
+ScrollView 2.0 ScrollView.qml
+ScrollBar 6.0 ScrollBar.qml
+ScrollBar 2.0 ScrollBar.qml
+ScrollIndicator 6.0 ScrollIndicator.qml
+ScrollIndicator 2.0 ScrollIndicator.qml
+SelectionRectangle 6.0 SelectionRectangle.qml
+SelectionRectangle 2.0 SelectionRectangle.qml
+Slider 6.0 Slider.qml
+Slider 2.0 Slider.qml
+SpinBox 6.0 SpinBox.qml
+SpinBox 2.0 SpinBox.qml
+SplitView 2.13 SplitView.qml
+SplitView 6.0 SplitView.qml
+StackView 6.0 StackView.qml
+StackView 2.0 StackView.qml
+SwipeDelegate 6.0 SwipeDelegate.qml
+SwipeDelegate 2.0 SwipeDelegate.qml
+SwipeView 6.0 SwipeView.qml
+SwipeView 2.0 SwipeView.qml
+Switch 6.0 Switch.qml
+Switch 2.0 Switch.qml
+SwitchDelegate 6.0 SwitchDelegate.qml
+SwitchDelegate 2.0 SwitchDelegate.qml
+TabBar 6.0 TabBar.qml
+TabBar 2.0 TabBar.qml
+TabButton 6.0 TabButton.qml
+TabButton 2.0 TabButton.qml
+TextArea 6.0 TextArea.qml
+TextArea 2.0 TextArea.qml
+TextField 6.0 TextField.qml
+TextField 2.0 TextField.qml
+ToolBar 6.0 ToolBar.qml
+ToolBar 2.0 ToolBar.qml
+ToolButton 6.0 ToolButton.qml
+ToolButton 2.0 ToolButton.qml
+ToolSeparator 2.1 ToolSeparator.qml
+ToolSeparator 6.0 ToolSeparator.qml
+ToolTip 6.0 ToolTip.qml
+ToolTip 2.0 ToolTip.qml
+TreeViewDelegate 6.0 TreeViewDelegate.qml
+TreeViewDelegate 2.0 TreeViewDelegate.qml
+Tumbler 6.0 Tumbler.qml
+Tumbler 2.0 Tumbler.qml
+VerticalHeaderView 2.15 VerticalHeaderView.qml
+VerticalHeaderView 6.0 VerticalHeaderView.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Controls/Universal/impl/qmldir b/tests/unit/unittest/data/qml/QtQuick/Controls/Universal/impl/qmldir
new file mode 100644
index 00000000000..e3297d34122
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Controls/Universal/impl/qmldir
@@ -0,0 +1,14 @@
+module QtQuick.Controls.Universal.impl
+linktarget Qt6::qtquickcontrols2universalstyleimplplugin
+plugin qtquickcontrols2universalstyleimplplugin
+classname QtQuickControls2UniversalStyleImplPlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Controls/Universal/impl/
+CheckIndicator 6.0 CheckIndicator.qml
+CheckIndicator 2.0 CheckIndicator.qml
+RadioIndicator 6.0 RadioIndicator.qml
+RadioIndicator 2.0 RadioIndicator.qml
+SwitchIndicator 6.0 SwitchIndicator.qml
+SwitchIndicator 2.0 SwitchIndicator.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Controls/Universal/qmldir b/tests/unit/unittest/data/qml/QtQuick/Controls/Universal/qmldir
new file mode 100644
index 00000000000..05fc6f15c50
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Controls/Universal/qmldir
@@ -0,0 +1,111 @@
+module QtQuick.Controls.Universal
+linktarget Qt6::qtquickcontrols2universalstyleplugin
+plugin qtquickcontrols2universalstyleplugin
+classname QtQuickControls2UniversalStylePlugin
+typeinfo plugins.qmltypes
+import QtQuick.Controls.Basic auto
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Controls/Universal/
+ApplicationWindow 6.0 ApplicationWindow.qml
+ApplicationWindow 2.0 ApplicationWindow.qml
+BusyIndicator 6.0 BusyIndicator.qml
+BusyIndicator 2.0 BusyIndicator.qml
+Button 6.0 Button.qml
+Button 2.0 Button.qml
+CheckBox 6.0 CheckBox.qml
+CheckBox 2.0 CheckBox.qml
+CheckDelegate 6.0 CheckDelegate.qml
+CheckDelegate 2.0 CheckDelegate.qml
+ComboBox 6.0 ComboBox.qml
+ComboBox 2.0 ComboBox.qml
+DelayButton 2.2 DelayButton.qml
+DelayButton 6.0 DelayButton.qml
+Dial 6.0 Dial.qml
+Dial 2.0 Dial.qml
+Dialog 2.1 Dialog.qml
+Dialog 6.0 Dialog.qml
+DialogButtonBox 2.1 DialogButtonBox.qml
+DialogButtonBox 6.0 DialogButtonBox.qml
+Drawer 6.0 Drawer.qml
+Drawer 2.0 Drawer.qml
+Frame 6.0 Frame.qml
+Frame 2.0 Frame.qml
+GroupBox 6.0 GroupBox.qml
+GroupBox 2.0 GroupBox.qml
+HorizontalHeaderView 2.15 HorizontalHeaderView.qml
+HorizontalHeaderView 6.0 HorizontalHeaderView.qml
+ItemDelegate 6.0 ItemDelegate.qml
+ItemDelegate 2.0 ItemDelegate.qml
+Label 6.0 Label.qml
+Label 2.0 Label.qml
+Menu 6.0 Menu.qml
+Menu 2.0 Menu.qml
+MenuBar 2.3 MenuBar.qml
+MenuBar 6.0 MenuBar.qml
+MenuBarItem 2.3 MenuBarItem.qml
+MenuBarItem 6.0 MenuBarItem.qml
+MenuItem 6.0 MenuItem.qml
+MenuItem 2.0 MenuItem.qml
+MenuSeparator 2.1 MenuSeparator.qml
+MenuSeparator 6.0 MenuSeparator.qml
+Page 6.0 Page.qml
+Page 2.0 Page.qml
+PageIndicator 6.0 PageIndicator.qml
+PageIndicator 2.0 PageIndicator.qml
+Pane 6.0 Pane.qml
+Pane 2.0 Pane.qml
+Popup 6.0 Popup.qml
+Popup 2.0 Popup.qml
+ProgressBar 6.0 ProgressBar.qml
+ProgressBar 2.0 ProgressBar.qml
+RadioButton 6.0 RadioButton.qml
+RadioButton 2.0 RadioButton.qml
+RadioDelegate 6.0 RadioDelegate.qml
+RadioDelegate 2.0 RadioDelegate.qml
+RangeSlider 6.0 RangeSlider.qml
+RangeSlider 2.0 RangeSlider.qml
+RoundButton 2.1 RoundButton.qml
+RoundButton 6.0 RoundButton.qml
+ScrollView 6.0 ScrollView.qml
+ScrollView 2.0 ScrollView.qml
+ScrollBar 6.0 ScrollBar.qml
+ScrollBar 2.0 ScrollBar.qml
+ScrollIndicator 6.0 ScrollIndicator.qml
+ScrollIndicator 2.0 ScrollIndicator.qml
+SelectionRectangle 6.0 SelectionRectangle.qml
+SelectionRectangle 2.0 SelectionRectangle.qml
+Slider 6.0 Slider.qml
+Slider 2.0 Slider.qml
+SpinBox 6.0 SpinBox.qml
+SpinBox 2.0 SpinBox.qml
+SplitView 2.13 SplitView.qml
+SplitView 6.0 SplitView.qml
+StackView 6.0 StackView.qml
+StackView 2.0 StackView.qml
+SwipeDelegate 6.0 SwipeDelegate.qml
+SwipeDelegate 2.0 SwipeDelegate.qml
+SwitchDelegate 6.0 SwitchDelegate.qml
+SwitchDelegate 2.0 SwitchDelegate.qml
+Switch 6.0 Switch.qml
+Switch 2.0 Switch.qml
+TabBar 6.0 TabBar.qml
+TabBar 2.0 TabBar.qml
+TabButton 6.0 TabButton.qml
+TabButton 2.0 TabButton.qml
+TextArea 6.0 TextArea.qml
+TextArea 2.0 TextArea.qml
+TextField 6.0 TextField.qml
+TextField 2.0 TextField.qml
+ToolBar 6.0 ToolBar.qml
+ToolBar 2.0 ToolBar.qml
+ToolButton 6.0 ToolButton.qml
+ToolButton 2.0 ToolButton.qml
+ToolSeparator 2.1 ToolSeparator.qml
+ToolSeparator 6.0 ToolSeparator.qml
+ToolTip 6.0 ToolTip.qml
+ToolTip 2.0 ToolTip.qml
+Tumbler 6.0 Tumbler.qml
+Tumbler 2.0 Tumbler.qml
+VerticalHeaderView 2.15 VerticalHeaderView.qml
+VerticalHeaderView 6.0 VerticalHeaderView.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Controls/impl/qmldir b/tests/unit/unittest/data/qml/QtQuick/Controls/impl/qmldir
new file mode 100644
index 00000000000..84355c3b9f9
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Controls/impl/qmldir
@@ -0,0 +1,9 @@
+module QtQuick.Controls.impl
+linktarget Qt6::qtquickcontrols2implplugin
+optional plugin qtquickcontrols2implplugin
+classname QtQuickControls2ImplPlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+depends QtQuick.Templates auto
+prefer :/qt-project.org/imports/QtQuick/Controls/impl/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Controls/qmldir b/tests/unit/unittest/data/qml/QtQuick/Controls/qmldir
new file mode 100644
index 00000000000..86f42c2274d
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Controls/qmldir
@@ -0,0 +1,16 @@
+module QtQuick.Controls
+linktarget Qt6::qtquickcontrols2plugin
+plugin qtquickcontrols2plugin
+classname QtQuickControls2Plugin
+designersupported
+typeinfo plugins.qmltypes
+optional import QtQuick.Controls.Fusion auto
+optional import QtQuick.Controls.Material auto
+optional import QtQuick.Controls.Imagine auto
+optional import QtQuick.Controls.Universal auto
+optional import QtQuick.Controls.Windows auto
+optional import QtQuick.Controls.macOS auto
+optional import QtQuick.Controls.iOS auto
+default import QtQuick.Controls.Basic auto
+prefer :/qt-project.org/imports/QtQuick/Controls/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Dialogs/qmldir b/tests/unit/unittest/data/qml/QtQuick/Dialogs/qmldir
new file mode 100644
index 00000000000..9468d95530c
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Dialogs/qmldir
@@ -0,0 +1,8 @@
+module QtQuick.Dialogs
+linktarget Qt6::qtquickdialogsplugin
+optional plugin qtquickdialogsplugin
+classname QtQuickDialogsPlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Dialogs/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Dialogs/quickimpl/qmldir b/tests/unit/unittest/data/qml/QtQuick/Dialogs/quickimpl/qmldir
new file mode 100644
index 00000000000..85a331e3067
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Dialogs/quickimpl/qmldir
@@ -0,0 +1,57 @@
+module QtQuick.Dialogs.quickimpl
+linktarget Qt6::qtquickdialogs2quickimplplugin
+optional plugin qtquickdialogs2quickimplplugin
+classname QtQuickDialogs2QuickImplPlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+depends QtQuick.Templates auto
+depends QtQuick.Layouts auto
+prefer :/qt-project.org/imports/QtQuick/Dialogs/quickimpl/
+ColorDialog 6.0 qml/ColorDialog.qml
+ColorInputs 6.0 qml/ColorInputs.qml
+FileDialog 6.0 qml/FileDialog.qml
+FileDialogDelegate 6.0 qml/FileDialogDelegate.qml
+FileDialogDelegateLabel 6.0 qml/FileDialogDelegateLabel.qml
+FolderBreadcrumbBar 6.0 qml/FolderBreadcrumbBar.qml
+FolderDialog 6.0 qml/FolderDialog.qml
+FolderDialogDelegate 6.0 qml/FolderDialogDelegate.qml
+FolderDialogDelegateLabel 6.0 qml/FolderDialogDelegateLabel.qml
+FontDialog 6.0 qml/FontDialog.qml
+FontDialogContent 6.0 qml/FontDialogContent.qml
+HueGradient 6.0 qml/HueGradient.qml
+MessageDialog 6.0 qml/MessageDialog.qml
+PickerHandle 6.0 qml/PickerHandle.qml
+SaturationLightnessPicker 6.0 qml/SaturationLightnessPicker.qml
+ColorDialog 6.0 qml/+Fusion/ColorDialog.qml
+FileDialog 6.0 qml/+Fusion/FileDialog.qml
+FileDialogDelegate 6.0 qml/+Fusion/FileDialogDelegate.qml
+FolderBreadcrumbBar 6.0 qml/+Fusion/FolderBreadcrumbBar.qml
+FolderDialog 6.0 qml/+Fusion/FolderDialog.qml
+FolderDialogDelegate 6.0 qml/+Fusion/FolderDialogDelegate.qml
+FontDialog 6.0 qml/+Fusion/FontDialog.qml
+MessageDialog 6.0 qml/+Fusion/MessageDialog.qml
+ColorDialog 6.0 qml/+Imagine/ColorDialog.qml
+FileDialog 6.0 qml/+Imagine/FileDialog.qml
+FileDialogDelegate 6.0 qml/+Imagine/FileDialogDelegate.qml
+FolderBreadcrumbBar 6.0 qml/+Imagine/FolderBreadcrumbBar.qml
+FolderDialog 6.0 qml/+Imagine/FolderDialog.qml
+FolderDialogDelegate 6.0 qml/+Imagine/FolderDialogDelegate.qml
+FontDialog 6.0 qml/+Imagine/FontDialog.qml
+MessageDialog 6.0 qml/+Imagine/MessageDialog.qml
+ColorDialog 6.0 qml/+Material/ColorDialog.qml
+FileDialog 6.0 qml/+Material/FileDialog.qml
+FileDialogDelegate 6.0 qml/+Material/FileDialogDelegate.qml
+FolderBreadcrumbBar 6.0 qml/+Material/FolderBreadcrumbBar.qml
+FolderDialog 6.0 qml/+Material/FolderDialog.qml
+FolderDialogDelegate 6.0 qml/+Material/FolderDialogDelegate.qml
+FontDialog 6.0 qml/+Material/FontDialog.qml
+MessageDialog 6.0 qml/+Material/MessageDialog.qml
+ColorDialog 6.0 qml/+Universal/ColorDialog.qml
+FileDialog 6.0 qml/+Universal/FileDialog.qml
+FileDialogDelegate 6.0 qml/+Universal/FileDialogDelegate.qml
+FolderBreadcrumbBar 6.0 qml/+Universal/FolderBreadcrumbBar.qml
+FolderDialog 6.0 qml/+Universal/FolderDialog.qml
+FolderDialogDelegate 6.0 qml/+Universal/FolderDialogDelegate.qml
+FontDialog 6.0 qml/+Universal/FontDialog.qml
+MessageDialog 6.0 qml/+Universal/MessageDialog.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Effects/qmldir b/tests/unit/unittest/data/qml/QtQuick/Effects/qmldir
new file mode 100644
index 00000000000..4fbc513d21e
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Effects/qmldir
@@ -0,0 +1,8 @@
+module QtQuick.Effects
+linktarget Qt6::effectsplugin
+optional plugin effectsplugin
+classname QtQuickEffectsPlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Effects/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Layouts/qmldir b/tests/unit/unittest/data/qml/QtQuick/Layouts/qmldir
new file mode 100644
index 00000000000..9fa0f0d84c5
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Layouts/qmldir
@@ -0,0 +1,9 @@
+module QtQuick.Layouts
+linktarget Qt6::qquicklayoutsplugin
+optional plugin qquicklayoutsplugin
+classname QtQuickLayoutsPlugin
+designersupported
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Layouts/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/LocalStorage/qmldir b/tests/unit/unittest/data/qml/QtQuick/LocalStorage/qmldir
new file mode 100644
index 00000000000..de9d480b6cd
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/LocalStorage/qmldir
@@ -0,0 +1,7 @@
+module QtQuick.LocalStorage
+linktarget Qt6::qmllocalstorageplugin
+optional plugin qmllocalstorageplugin
+classname QQmlLocalStoragePlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtQuick/LocalStorage/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/NativeStyle/qmldir b/tests/unit/unittest/data/qml/QtQuick/NativeStyle/qmldir
new file mode 100644
index 00000000000..4ab0813a4d7
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/NativeStyle/qmldir
@@ -0,0 +1,38 @@
+module QtQuick.NativeStyle
+linktarget Qt6::qtquickcontrols2nativestyleplugin
+plugin qtquickcontrols2nativestyleplugin
+classname QtQuickControls2NativeStylePlugin
+typeinfo plugins.qmltypes
+depends QtQuick.Controls auto
+depends QtQuick.Layouts auto
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/NativeStyle/
+DefaultButton 6.0 controls/DefaultButton.qml
+DefaultButton 2.0 controls/DefaultButton.qml
+DefaultSlider 6.0 controls/DefaultSlider.qml
+DefaultSlider 2.0 controls/DefaultSlider.qml
+DefaultGroupBox 6.0 controls/DefaultGroupBox.qml
+DefaultGroupBox 2.0 controls/DefaultGroupBox.qml
+DefaultCheckBox 6.0 controls/DefaultCheckBox.qml
+DefaultCheckBox 2.0 controls/DefaultCheckBox.qml
+DefaultRadioButton 6.0 controls/DefaultRadioButton.qml
+DefaultRadioButton 2.0 controls/DefaultRadioButton.qml
+DefaultSpinBox 6.0 controls/DefaultSpinBox.qml
+DefaultSpinBox 2.0 controls/DefaultSpinBox.qml
+DefaultTextField 6.0 controls/DefaultTextField.qml
+DefaultTextField 2.0 controls/DefaultTextField.qml
+DefaultFrame 6.0 controls/DefaultFrame.qml
+DefaultFrame 2.0 controls/DefaultFrame.qml
+DefaultTextArea 6.0 controls/DefaultTextArea.qml
+DefaultTextArea 2.0 controls/DefaultTextArea.qml
+DefaultComboBox 6.0 controls/DefaultComboBox.qml
+DefaultComboBox 2.0 controls/DefaultComboBox.qml
+DefaultScrollBar 6.0 controls/DefaultScrollBar.qml
+DefaultScrollBar 2.0 controls/DefaultScrollBar.qml
+DefaultProgressBar 6.0 controls/DefaultProgressBar.qml
+DefaultProgressBar 2.0 controls/DefaultProgressBar.qml
+DefaultDial 6.0 controls/DefaultDial.qml
+DefaultDial 2.0 controls/DefaultDial.qml
+DefaultTreeViewDelegate 6.0 controls/DefaultTreeViewDelegate.qml
+DefaultTreeViewDelegate 2.0 controls/DefaultTreeViewDelegate.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Particles/qmldir b/tests/unit/unittest/data/qml/QtQuick/Particles/qmldir
new file mode 100644
index 00000000000..163fb28bdf8
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Particles/qmldir
@@ -0,0 +1,8 @@
+module QtQuick.Particles
+linktarget Qt6::particlesplugin
+optional plugin particlesplugin
+classname QtQuick2ParticlesPlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Particles/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Pdf/qmldir b/tests/unit/unittest/data/qml/QtQuick/Pdf/qmldir
new file mode 100644
index 00000000000..9004a9ed71e
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Pdf/qmldir
@@ -0,0 +1,22 @@
+module QtQuick.Pdf
+linktarget Qt6::PdfQuickplugin
+optional plugin pdfquickplugin
+classname QtQuick_PdfPlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Pdf/
+PdfStyle 6.0 +Material/PdfStyle.qml
+PdfStyle 5.0 +Material/PdfStyle.qml
+PdfStyle 6.0 +Universal/PdfStyle.qml
+PdfStyle 5.0 +Universal/PdfStyle.qml
+PdfLinkDelegate 6.0 PdfLinkDelegate.qml
+PdfLinkDelegate 5.0 PdfLinkDelegate.qml
+PdfMultiPageView 6.0 PdfMultiPageView.qml
+PdfMultiPageView 5.0 PdfMultiPageView.qml
+PdfPageView 6.0 PdfPageView.qml
+PdfPageView 5.0 PdfPageView.qml
+PdfScrollablePageView 6.0 PdfScrollablePageView.qml
+PdfScrollablePageView 5.0 PdfScrollablePageView.qml
+PdfStyle 6.0 PdfStyle.qml
+PdfStyle 5.0 PdfStyle.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Scene2D/qmldir b/tests/unit/unittest/data/qml/QtQuick/Scene2D/qmldir
new file mode 100644
index 00000000000..8a222334339
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Scene2D/qmldir
@@ -0,0 +1,7 @@
+module QtQuick.Scene2D
+linktarget Qt6::qtquickscene2dplugin
+plugin qtquickscene2dplugin
+classname QtQuickScene2DPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtQuick/Scene2D/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Scene3D/qmldir b/tests/unit/unittest/data/qml/QtQuick/Scene3D/qmldir
new file mode 100644
index 00000000000..6dcd613d391
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Scene3D/qmldir
@@ -0,0 +1,7 @@
+module QtQuick.Scene3D
+linktarget Qt6::qtquickscene3dplugin
+plugin qtquickscene3dplugin
+classname QtQuickScene3DPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtQuick/Scene3D/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Shapes/qmldir b/tests/unit/unittest/data/qml/QtQuick/Shapes/qmldir
new file mode 100644
index 00000000000..428ff391a4a
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Shapes/qmldir
@@ -0,0 +1,8 @@
+module QtQuick.Shapes
+linktarget Qt6::qmlshapesplugin
+plugin qmlshapesplugin
+classname QmlShapesPlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Shapes/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Templates/qmldir b/tests/unit/unittest/data/qml/QtQuick/Templates/qmldir
new file mode 100644
index 00000000000..bd768665387
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Templates/qmldir
@@ -0,0 +1,8 @@
+module QtQuick.Templates
+linktarget Qt6::qtquicktemplates2plugin
+plugin qtquicktemplates2plugin
+classname QtQuickTemplates2Plugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Templates/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Timeline/qmldir b/tests/unit/unittest/data/qml/QtQuick/Timeline/qmldir
new file mode 100644
index 00000000000..f4e953c568e
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Timeline/qmldir
@@ -0,0 +1,9 @@
+module QtQuick.Timeline
+linktarget Qt6::qtquicktimelineplugin
+optional plugin qtquicktimelineplugin
+classname QtQuickTimelinePlugin
+designersupported
+typeinfo plugins.qmltypes
+depends QtQuick
+prefer :/qt-project.org/imports/QtQuick/Timeline/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Components/qmldir b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Components/qmldir
new file mode 100644
index 00000000000..d1f487261ae
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Components/qmldir
@@ -0,0 +1,103 @@
+module QtQuick.VirtualKeyboard.Components
+linktarget Qt6::qtvkbcomponentsplugin
+optional plugin qtvkbcomponentsplugin
+classname QtQuick_VirtualKeyboard_ComponentsPlugin
+typeinfo qtvkbcomponentsplugin.qmltypes
+depends QtQuick auto
+depends QtQuick.Layouts auto
+depends QtQuick.VirtualKeyboard.Settings auto
+prefer :/qt-project.org/imports/QtQuick/VirtualKeyboard/Components/
+AlternativeKeys 6.0 AlternativeKeys.qml
+AlternativeKeys 2.0 AlternativeKeys.qml
+AlternativeKeys 1.0 AlternativeKeys.qml
+BackspaceKey 6.0 BackspaceKey.qml
+BackspaceKey 2.0 BackspaceKey.qml
+BackspaceKey 1.0 BackspaceKey.qml
+BaseKey 6.0 BaseKey.qml
+BaseKey 2.0 BaseKey.qml
+BaseKey 1.0 BaseKey.qml
+ChangeLanguageKey 6.0 ChangeLanguageKey.qml
+ChangeLanguageKey 2.0 ChangeLanguageKey.qml
+ChangeLanguageKey 1.0 ChangeLanguageKey.qml
+CharacterPreviewBubble 6.0 CharacterPreviewBubble.qml
+CharacterPreviewBubble 2.0 CharacterPreviewBubble.qml
+CharacterPreviewBubble 1.0 CharacterPreviewBubble.qml
+EnterKey 6.0 EnterKey.qml
+EnterKey 2.0 EnterKey.qml
+EnterKey 1.0 EnterKey.qml
+FillerKey 6.0 FillerKey.qml
+FillerKey 2.0 FillerKey.qml
+FillerKey 1.0 FillerKey.qml
+FlickKey 6.0 FlickKey.qml
+FlickKey 2.0 FlickKey.qml
+FlickKey 1.0 FlickKey.qml
+FunctionPopupList 6.0 FunctionPopupList.qml
+FunctionPopupList 2.0 FunctionPopupList.qml
+FunctionPopupList 1.0 FunctionPopupList.qml
+HandwritingModeKey 6.0 HandwritingModeKey.qml
+HandwritingModeKey 2.0 HandwritingModeKey.qml
+HandwritingModeKey 1.0 HandwritingModeKey.qml
+HideKeyboardKey 6.0 HideKeyboardKey.qml
+HideKeyboardKey 2.0 HideKeyboardKey.qml
+HideKeyboardKey 1.0 HideKeyboardKey.qml
+InputModeKey 6.0 InputModeKey.qml
+InputModeKey 2.0 InputModeKey.qml
+InputModeKey 1.0 InputModeKey.qml
+Key 6.0 Key.qml
+Key 2.0 Key.qml
+Key 1.0 Key.qml
+Keyboard 6.0 Keyboard.qml
+Keyboard 2.0 Keyboard.qml
+Keyboard 1.0 Keyboard.qml
+KeyboardColumn 6.0 KeyboardColumn.qml
+KeyboardColumn 2.0 KeyboardColumn.qml
+KeyboardColumn 1.0 KeyboardColumn.qml
+KeyboardLayout 6.0 KeyboardLayout.qml
+KeyboardLayout 2.0 KeyboardLayout.qml
+KeyboardLayout 1.0 KeyboardLayout.qml
+KeyboardLayoutLoader 6.0 KeyboardLayoutLoader.qml
+KeyboardLayoutLoader 2.0 KeyboardLayoutLoader.qml
+KeyboardLayoutLoader 1.0 KeyboardLayoutLoader.qml
+KeyboardRow 6.0 KeyboardRow.qml
+KeyboardRow 2.0 KeyboardRow.qml
+KeyboardRow 1.0 KeyboardRow.qml
+ModeKey 6.0 ModeKey.qml
+ModeKey 2.0 ModeKey.qml
+ModeKey 1.0 ModeKey.qml
+MultiSoundEffect 6.0 MultiSoundEffect.qml
+MultiSoundEffect 2.0 MultiSoundEffect.qml
+MultiSoundEffect 1.0 MultiSoundEffect.qml
+MultitapInputMethod 6.0 MultitapInputMethod.qml
+MultitapInputMethod 2.0 MultitapInputMethod.qml
+MultitapInputMethod 1.0 MultitapInputMethod.qml
+NumberKey 6.0 NumberKey.qml
+NumberKey 2.0 NumberKey.qml
+NumberKey 1.0 NumberKey.qml
+PopupList 6.0 PopupList.qml
+PopupList 2.0 PopupList.qml
+PopupList 1.0 PopupList.qml
+SelectionControl 6.0 SelectionControl.qml
+SelectionControl 2.0 SelectionControl.qml
+SelectionControl 1.0 SelectionControl.qml
+ShadowInputControl 6.0 ShadowInputControl.qml
+ShadowInputControl 2.0 ShadowInputControl.qml
+ShadowInputControl 1.0 ShadowInputControl.qml
+ShiftKey 6.0 ShiftKey.qml
+ShiftKey 2.0 ShiftKey.qml
+ShiftKey 1.0 ShiftKey.qml
+SpaceKey 6.0 SpaceKey.qml
+SpaceKey 2.0 SpaceKey.qml
+SpaceKey 1.0 SpaceKey.qml
+SymbolModeKey 6.0 SymbolModeKey.qml
+SymbolModeKey 2.0 SymbolModeKey.qml
+SymbolModeKey 1.0 SymbolModeKey.qml
+TraceInputArea 6.0 TraceInputArea.qml
+TraceInputArea 2.0 TraceInputArea.qml
+TraceInputArea 1.0 TraceInputArea.qml
+TraceInputKey 6.0 TraceInputKey.qml
+TraceInputKey 2.0 TraceInputKey.qml
+TraceInputKey 1.0 TraceInputKey.qml
+WordCandidatePopupList 6.0 WordCandidatePopupList.qml
+WordCandidatePopupList 2.0 WordCandidatePopupList.qml
+WordCandidatePopupList 1.0 WordCandidatePopupList.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Layouts/qmldir b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Layouts/qmldir
new file mode 100644
index 00000000000..626958542b1
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Layouts/qmldir
@@ -0,0 +1,7 @@
+module QtQuick.VirtualKeyboard.Layouts
+linktarget Qt6::qtvkblayoutsplugin
+plugin qtvkblayoutsplugin
+classname QtQuick_VirtualKeyboard_LayoutsPlugin
+typeinfo qtvkblayoutsplugin.qmltypes
+prefer :/qt-project.org/imports/QtQuick/VirtualKeyboard/Layouts/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/Hangul/qmldir b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/Hangul/qmldir
new file mode 100644
index 00000000000..d884562c66d
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/Hangul/qmldir
@@ -0,0 +1,8 @@
+module QtQuick.VirtualKeyboard.Plugins.Hangul
+linktarget Qt6::qtvkbhangulplugin
+plugin qtvkbhangulplugin
+classname QtQuick_VirtualKeyboard_Plugins_HangulPlugin
+typeinfo plugins.qmltypes
+depends QtQuick.VirtualKeyboard auto
+prefer :/qt-project.org/imports/QtQuick/VirtualKeyboard/Plugins/Hangul/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/OpenWNN/qmldir b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/OpenWNN/qmldir
new file mode 100644
index 00000000000..d356a13a061
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/OpenWNN/qmldir
@@ -0,0 +1,8 @@
+module QtQuick.VirtualKeyboard.Plugins.OpenWNN
+linktarget Qt6::qtvkbopenwnnplugin
+plugin qtvkbopenwnnplugin
+classname QtQuick_VirtualKeyboard_Plugins_OpenWNNPlugin
+typeinfo plugins.qmltypes
+depends QtQuick.VirtualKeyboard auto
+prefer :/qt-project.org/imports/QtQuick/VirtualKeyboard/Plugins/OpenWNN/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/Pinyin/qmldir b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/Pinyin/qmldir
new file mode 100644
index 00000000000..cdf07320229
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/Pinyin/qmldir
@@ -0,0 +1,8 @@
+module QtQuick.VirtualKeyboard.Plugins.Pinyin
+linktarget Qt6::qtvkbpinyinplugin
+plugin qtvkbpinyinplugin
+classname QtQuick_VirtualKeyboard_Plugins_PinyinPlugin
+typeinfo plugins.qmltypes
+depends QtQuick.VirtualKeyboard auto
+prefer :/qt-project.org/imports/QtQuick/VirtualKeyboard/Plugins/Pinyin/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/TCIme/qmldir b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/TCIme/qmldir
new file mode 100644
index 00000000000..f3d7c580539
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/TCIme/qmldir
@@ -0,0 +1,8 @@
+module QtQuick.VirtualKeyboard.Plugins.TCIme
+linktarget Qt6::qtvkbtcimeplugin
+plugin qtvkbtcimeplugin
+classname QtQuick_VirtualKeyboard_Plugins_TCImePlugin
+typeinfo plugins.qmltypes
+depends QtQuick.VirtualKeyboard auto
+prefer :/qt-project.org/imports/QtQuick/VirtualKeyboard/Plugins/TCIme/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/Thai/qmldir b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/Thai/qmldir
new file mode 100644
index 00000000000..79164dda638
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/Thai/qmldir
@@ -0,0 +1,8 @@
+module QtQuick.VirtualKeyboard.Plugins.Thai
+linktarget Qt6::qtvkbthaiplugin
+plugin qtvkbthaiplugin
+classname QtQuick_VirtualKeyboard_Plugins_ThaiPlugin
+typeinfo plugins.qmltypes
+depends QtQuick.VirtualKeyboard auto
+prefer :/qt-project.org/imports/QtQuick/VirtualKeyboard/Plugins/Thai/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/qmldir b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/qmldir
new file mode 100644
index 00000000000..d07a1a1c2d7
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Plugins/qmldir
@@ -0,0 +1,12 @@
+module QtQuick.VirtualKeyboard.Plugins
+linktarget Qt6::qtvkbpluginsplugin
+optional plugin qtvkbpluginsplugin
+classname QtQuick_VirtualKeyboard_PluginsPlugin
+typeinfo qtvkbpluginsplugin.qmltypes
+import QtQuick.VirtualKeyboard.Plugins.Hangul auto
+import QtQuick.VirtualKeyboard.Plugins.OpenWNN auto
+import QtQuick.VirtualKeyboard.Plugins.Pinyin auto
+import QtQuick.VirtualKeyboard.Plugins.TCIme auto
+import QtQuick.VirtualKeyboard.Plugins.Thai auto
+prefer :/qt-project.org/imports/QtQuick/VirtualKeyboard/Plugins/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Settings/qmldir b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Settings/qmldir
new file mode 100644
index 00000000000..a3043cf3f69
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Settings/qmldir
@@ -0,0 +1,7 @@
+module QtQuick.VirtualKeyboard.Settings
+linktarget Qt6::qtvkbsettingsplugin
+plugin qtvkbsettingsplugin
+classname QtQuick_VirtualKeyboard_SettingsPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtQuick/VirtualKeyboard/Settings/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Styles/Builtin/qmldir b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Styles/Builtin/qmldir
new file mode 100644
index 00000000000..fdf9f086abb
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Styles/Builtin/qmldir
@@ -0,0 +1,7 @@
+module QtQuick.VirtualKeyboard.Styles.Builtin
+linktarget Qt6::qtvkbbuiltinstylesplugin
+plugin qtvkbbuiltinstylesplugin
+classname QtQuickVirtualKeyboardStylesBuiltinPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtQuick/VirtualKeyboard/Styles/Builtin/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Styles/qmldir b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Styles/qmldir
new file mode 100644
index 00000000000..8804cd8a731
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/Styles/qmldir
@@ -0,0 +1,30 @@
+module QtQuick.VirtualKeyboard.Styles
+linktarget Qt6::qtvkbstylesplugin
+plugin qtvkbstylesplugin
+classname QtQuickVirtualKeyboardStylesPlugin
+typeinfo plugins.qmltypes
+import QtQuick.VirtualKeyboard.Styles.Builtin auto
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/VirtualKeyboard/Styles/
+KeyboardStyle 6.0 KeyboardStyle.qml
+KeyboardStyle 2.0 KeyboardStyle.qml
+KeyboardStyle 1.0 KeyboardStyle.qml
+KeyIcon 6.0 KeyIcon.qml
+KeyIcon 2.0 KeyIcon.qml
+KeyIcon 1.0 KeyIcon.qml
+KeyPanel 6.0 KeyPanel.qml
+KeyPanel 2.0 KeyPanel.qml
+KeyPanel 1.0 KeyPanel.qml
+SelectionListItem 6.0 SelectionListItem.qml
+SelectionListItem 2.0 SelectionListItem.qml
+SelectionListItem 1.0 SelectionListItem.qml
+TraceInputKeyPanel 6.0 TraceInputKeyPanel.qml
+TraceInputKeyPanel 2.0 TraceInputKeyPanel.qml
+TraceInputKeyPanel 1.0 TraceInputKeyPanel.qml
+TraceCanvas 6.0 TraceCanvas.qml
+TraceCanvas 2.0 TraceCanvas.qml
+TraceCanvas 1.0 TraceCanvas.qml
+TraceUtils 6.0 TraceUtils.js
+TraceUtils 2.0 TraceUtils.js
+TraceUtils 1.0 TraceUtils.js
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/qmldir b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/qmldir
new file mode 100644
index 00000000000..754cc754490
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/VirtualKeyboard/qmldir
@@ -0,0 +1,25 @@
+module QtQuick.VirtualKeyboard
+linktarget Qt6::qtvkbplugin
+optional plugin qtvkbplugin
+classname QtQuick_VirtualKeyboardPlugin
+typeinfo plugins.qmltypes
+import QtQuick.VirtualKeyboard.Layouts auto
+import QtQuick.VirtualKeyboard.Components auto
+depends QtQuick auto
+depends QtQuick.Window auto
+depends QtQuick.Layouts auto
+depends Qt.labs.folderlistmodel auto
+depends QtQuick.VirtualKeyboard.Settings auto
+depends QtQuick.VirtualKeyboard.Styles auto
+depends QtQuick.VirtualKeyboard.Plugins auto
+prefer :/qt-project.org/imports/QtQuick/VirtualKeyboard/
+HandwritingInputPanel 6.0 HandwritingInputPanel.qml
+HandwritingInputPanel 2.0 HandwritingInputPanel.qml
+HandwritingInputPanel 1.0 HandwritingInputPanel.qml
+InputPanel 6.0 InputPanel.qml
+InputPanel 2.0 InputPanel.qml
+InputPanel 1.0 InputPanel.qml
+EnterKey 6.0 EnterKey.qml
+EnterKey 2.0 EnterKey.qml
+EnterKey 1.0 EnterKey.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/Window/qmldir b/tests/unit/unittest/data/qml/QtQuick/Window/qmldir
new file mode 100644
index 00000000000..5ff5ce84ddb
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/Window/qmldir
@@ -0,0 +1,8 @@
+module QtQuick.Window
+linktarget Qt6::quickwindow
+plugin quickwindowplugin
+classname QtQuick_WindowPlugin
+typeinfo quickwindow.qmltypes
+import QtQuick auto
+prefer :/qt-project.org/imports/QtQuick/Window/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/qmldir b/tests/unit/unittest/data/qml/QtQuick/qmldir
new file mode 100644
index 00000000000..7d68a105aa2
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/qmldir
@@ -0,0 +1,9 @@
+module QtQuick
+linktarget Qt6::qtquick2plugin
+optional plugin qtquick2plugin
+classname QtQuick2Plugin
+designersupported
+typeinfo plugins.qmltypes
+import QtQml auto
+prefer :/qt-project.org/imports/QtQuick/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick/tooling/qmldir b/tests/unit/unittest/data/qml/QtQuick/tooling/qmldir
new file mode 100644
index 00000000000..99798d19a69
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick/tooling/qmldir
@@ -0,0 +1,23 @@
+module QtQuick.tooling
+linktarget Qt6::quicktooling
+plugin quicktoolingplugin
+classname QtQuick_toolingPlugin
+typeinfo quicktooling.qmltypes
+prefer :/qt-project.org/imports/QtQuick/tooling/
+Component 1.2 Component.qml
+Component 6.0 Component.qml
+Enum 1.2 Enum.qml
+Enum 6.0 Enum.qml
+Member 1.2 Member.qml
+Member 6.0 Member.qml
+Method 1.2 Method.qml
+Method 6.0 Method.qml
+Module 1.2 Module.qml
+Module 6.0 Module.qml
+Parameter 1.2 Parameter.qml
+Parameter 6.0 Parameter.qml
+Property 1.2 Property.qml
+Property 6.0 Property.qml
+Signal 1.2 Signal.qml
+Signal 6.0 Signal.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick3D/AssetUtils/qmldir b/tests/unit/unittest/data/qml/QtQuick3D/AssetUtils/qmldir
new file mode 100644
index 00000000000..5c759031714
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick3D/AssetUtils/qmldir
@@ -0,0 +1,9 @@
+module QtQuick3D.AssetUtils
+linktarget Qt6::qtquick3dassetutilsplugin
+optional plugin qtquick3dassetutilsplugin
+classname QtQuick3DAssetUtilsPlugin
+designersupported
+typeinfo plugins.qmltypes
+depends QtQuick3D auto
+prefer :/qt-project.org/imports/QtQuick3D/AssetUtils/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick3D/Effects/qmldir b/tests/unit/unittest/data/qml/QtQuick3D/Effects/qmldir
new file mode 100644
index 00000000000..cec26d9c2a4
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick3D/Effects/qmldir
@@ -0,0 +1,31 @@
+module QtQuick3D.Effects
+linktarget Qt6::qtquick3deffectplugin
+optional plugin qtquick3deffectplugin
+classname QtQuick3DEffectPlugin
+designersupported
+typeinfo Quick3DEffects.qmltypes
+depends QtQuick3D auto
+depends QtQuick.Window auto
+prefer :/qt-project.org/imports/QtQuick3D/Effects/
+Vignette 6.0 Vignette.qml
+TiltShift 6.0 TiltShift.qml
+SCurveTonemap 6.0 SCurveTonemap.qml
+Scatter 6.0 Scatter.qml
+MotionBlur 6.0 MotionBlur.qml
+HDRBloomTonemap 6.0 HDRBloomTonemap.qml
+GaussianBlur 6.0 GaussianBlur.qml
+Fxaa 6.0 Fxaa.qml
+Flip 6.0 Flip.qml
+Emboss 6.0 Emboss.qml
+EdgeDetect 6.0 EdgeDetect.qml
+DistortionSpiral 6.0 DistortionSpiral.qml
+DistortionSphere 6.0 DistortionSphere.qml
+DistortionRipple 6.0 DistortionRipple.qml
+Desaturate 6.0 Desaturate.qml
+DepthOfFieldHQBlur 6.0 DepthOfFieldHQBlur.qml
+ColorMaster 6.0 ColorMaster.qml
+ChromaticAberration 6.0 ChromaticAberration.qml
+BrushStrokes 6.0 BrushStrokes.qml
+Blur 6.0 Blur.qml
+AdditiveColorGradient 6.0 AdditiveColorGradient.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick3D/Helpers/impl/qmldir b/tests/unit/unittest/data/qml/QtQuick3D/Helpers/impl/qmldir
new file mode 100644
index 00000000000..013c950285b
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick3D/Helpers/impl/qmldir
@@ -0,0 +1,12 @@
+module QtQuick3D.Helpers.impl
+linktarget Qt6::qtquick3dhelpersimplplugin
+plugin qtquick3dhelpersimplplugin
+classname QtQuick3DHelpersImplPlugin
+typeinfo plugins.qmltypes
+depends QtQuick3D auto
+depends Quick3DHelpers auto
+prefer :/qt-project.org/imports/QtQuick3D/Helpers/impl/
+DepthOfFieldBlur 6.0 DepthOfFieldBlur.qml
+SceneEffect 6.0 SceneEffect.qml
+LightmapperOutputWindow 6.0 LightmapperOutputWindow.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick3D/Helpers/qmldir b/tests/unit/unittest/data/qml/QtQuick3D/Helpers/qmldir
new file mode 100644
index 00000000000..f70948ab74e
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick3D/Helpers/qmldir
@@ -0,0 +1,21 @@
+module QtQuick3D.Helpers
+linktarget Qt6::qtquick3dhelpersplugin
+optional plugin qtquick3dhelpersplugin
+classname QtQuick3DHelpersPlugin
+designersupported
+typeinfo plugins.qmltypes
+depends QtQuick3D auto
+prefer :/qt-project.org/imports/QtQuick3D/Helpers/
+AxisHelper 6.0 AxisHelper.qml
+AxisHelper 1.0 AxisHelper.qml
+DebugView 6.0 DebugView.qml
+DebugView 1.0 DebugView.qml
+WasdController 6.0 WasdController.qml
+WasdController 1.0 WasdController.qml
+OrbitCameraController 6.0 OrbitCameraController.qml
+OrbitCameraController 1.0 OrbitCameraController.qml
+LodManager 6.0 LodManager.qml
+LodManager 1.0 LodManager.qml
+ExtendedSceneEnvironment 6.0 ExtendedSceneEnvironment.qml
+ExtendedSceneEnvironment 1.0 ExtendedSceneEnvironment.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick3D/MaterialEditor/qmldir b/tests/unit/unittest/data/qml/QtQuick3D/MaterialEditor/qmldir
new file mode 100644
index 00000000000..0286f76d757
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick3D/MaterialEditor/qmldir
@@ -0,0 +1,13 @@
+module QtQuick3D.MaterialEditor
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtQuick3D/MaterialEditor/
+ShaderEditor 1.0 ShaderEditor.qml
+EditorView 1.0 EditorView.qml
+Preview 1.0 Preview.qml
+PreviewControls 1.0 PreviewControls.qml
+FrostedGlass 1.0 FrostedGlass.qml
+AboutDialog 1.0 AboutDialog.qml
+MaterialPropertiesPane 1.0 MaterialPropertiesPane.qml
+SaveChangesDialog 1.0 SaveChangesDialog.qml
+UniformManagerPane 1.0 UniformManagerPane.qml
+
diff --git a/tests/unit/unittest/data/qml/QtQuick3D/ParticleEffects/qmldir b/tests/unit/unittest/data/qml/QtQuick3D/ParticleEffects/qmldir
new file mode 100644
index 00000000000..6abbe020127
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick3D/ParticleEffects/qmldir
@@ -0,0 +1,10 @@
+module QtQuick3D.ParticleEffects
+linktarget Qt6::qtquick3dparticleeffectsplugin
+optional plugin qtquick3dparticleeffectsplugin
+classname QtQuick3DParticleEffectsPlugin
+designersupported
+typeinfo Quick3DParticleEffects.qmltypes
+depends QtQuick3D auto
+depends QtQuick3DParticles3D auto
+prefer :/qt-project.org/imports/QtQuick3D/ParticleEffects/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick3D/Particles3D/qmldir b/tests/unit/unittest/data/qml/QtQuick3D/Particles3D/qmldir
new file mode 100644
index 00000000000..840899a28f3
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick3D/Particles3D/qmldir
@@ -0,0 +1,9 @@
+module QtQuick3D.Particles3D
+linktarget Qt6::qtquick3dparticles3dplugin
+optional plugin qtquick3dparticles3dplugin
+classname QtQuick3DParticles3DPlugin
+designersupported
+typeinfo plugins.qmltypes
+depends QtQuick3D auto
+prefer :/qt-project.org/imports/QtQuick3D/Particles3D/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick3D/Physics/Helpers/qmldir b/tests/unit/unittest/data/qml/QtQuick3D/Physics/Helpers/qmldir
new file mode 100644
index 00000000000..01802761653
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick3D/Physics/Helpers/qmldir
@@ -0,0 +1,8 @@
+module QtQuick3D.Physics.Helpers
+linktarget Qt6::qtquick3dphysicshelpersplugin
+optional plugin qtquick3dphysicshelpersplugin
+classname QtQuick3DPhysicsHelpersPlugin
+typeinfo plugins.qmltypes
+depends QtQuick3DPhysics auto
+prefer :/qt-project.org/imports/QtQuick3D/Physics/Helpers/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick3D/Physics/qmldir b/tests/unit/unittest/data/qml/QtQuick3D/Physics/qmldir
new file mode 100644
index 00000000000..eb263336d85
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick3D/Physics/qmldir
@@ -0,0 +1,8 @@
+module QtQuick3D.Physics
+linktarget Qt6::qquick3dphysicsplugin
+plugin qquick3dphysicsplugin
+classname QtQuick3DPhysicsPlugin
+designersupported
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtQuick3D/Physics/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick3D/SpatialAudio/qmldir b/tests/unit/unittest/data/qml/QtQuick3D/SpatialAudio/qmldir
new file mode 100644
index 00000000000..e913a041384
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick3D/SpatialAudio/qmldir
@@ -0,0 +1,10 @@
+module QtQuick3D.SpatialAudio
+linktarget Qt6::quick3dspatialaudio
+plugin quick3dspatialaudioplugin
+classname QQuick3DAudioModule
+typeinfo plugins.qmltypes
+depends QtQuick
+depends QtQuick3DPrivate
+depends QtMultimedia
+prefer :/qt-project.org/imports/QtQuick3D/SpatialAudio/
+
diff --git a/tests/unit/unittest/data/qml/QtQuick3D/qmldir b/tests/unit/unittest/data/qml/QtQuick3D/qmldir
new file mode 100644
index 00000000000..4de7691565a
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtQuick3D/qmldir
@@ -0,0 +1,9 @@
+module QtQuick3D
+linktarget Qt6::qquick3dplugin
+plugin qquick3dplugin
+classname QQuick3DPlugin
+designersupported
+typeinfo plugins.qmltypes
+depends QtQuick auto
+prefer :/qt-project.org/imports/QtQuick3D/
+
diff --git a/tests/unit/unittest/data/qml/QtRemoteObjects/qmldir b/tests/unit/unittest/data/qml/QtRemoteObjects/qmldir
new file mode 100644
index 00000000000..3f52d6267ec
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtRemoteObjects/qmldir
@@ -0,0 +1,7 @@
+module QtRemoteObjects
+linktarget Qt6::declarative_remoteobjects
+optional plugin declarative_remoteobjectsplugin
+classname QtRemoteObjectsPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtRemoteObjects/
+
diff --git a/tests/unit/unittest/data/qml/QtScxml/qmldir b/tests/unit/unittest/data/qml/QtScxml/qmldir
new file mode 100644
index 00000000000..d72487dcb16
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtScxml/qmldir
@@ -0,0 +1,8 @@
+module QtScxml
+linktarget Qt6::declarative_scxml
+optional plugin declarative_scxmlplugin
+classname QScxmlStateMachinePlugin
+typeinfo plugins.qmltypes
+depends QtQml
+prefer :/qt-project.org/imports/QtScxml/
+
diff --git a/tests/unit/unittest/data/qml/QtSensors/qmldir b/tests/unit/unittest/data/qml/QtSensors/qmldir
new file mode 100644
index 00000000000..228471522be
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtSensors/qmldir
@@ -0,0 +1,8 @@
+module QtSensors
+linktarget Qt6::SensorsQuickplugin
+optional plugin sensorsquickplugin
+classname QtSensorsPlugin
+typeinfo plugins.qmltypes
+depends QtQml
+prefer :/qt-project.org/imports/QtSensors/
+
diff --git a/tests/unit/unittest/data/qml/QtTest/qmldir b/tests/unit/unittest/data/qml/QtTest/qmldir
new file mode 100644
index 00000000000..9ce4da24313
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtTest/qmldir
@@ -0,0 +1,14 @@
+module QtTest
+linktarget Qt6::QuickTestplugin
+optional plugin quicktestplugin
+classname QtTestPlugin
+typeinfo plugins.qmltypes
+depends QtQuick.Window auto
+prefer :/qt-project.org/imports/QtTest/
+SignalSpy 6.0 SignalSpy.qml
+SignalSpy 1.0 SignalSpy.qml
+TestCase 6.0 TestCase.qml
+TestCase 1.0 TestCase.qml
+singleton TestSchedule 6.0 TestSchedule.qml
+singleton TestSchedule 1.0 TestSchedule.qml
+
diff --git a/tests/unit/unittest/data/qml/QtTextToSpeech/qmldir b/tests/unit/unittest/data/qml/QtTextToSpeech/qmldir
new file mode 100644
index 00000000000..3ffacdb981b
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtTextToSpeech/qmldir
@@ -0,0 +1,7 @@
+module QtTextToSpeech
+linktarget Qt6::TextToSpeechQml
+optional plugin texttospeechqmlplugin
+classname QtTextToSpeechPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtTextToSpeech/
+
diff --git a/tests/unit/unittest/data/qml/QtVncServer/qmldir b/tests/unit/unittest/data/qml/QtVncServer/qmldir
new file mode 100644
index 00000000000..ccef9dfd6e1
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtVncServer/qmldir
@@ -0,0 +1,8 @@
+module QtVncServer
+linktarget Qt6::qquickvncplugin
+plugin qquickvncplugin
+classname QQuickVncPlugin
+typeinfo plugins.qmltypes
+depends QtQuick
+prefer :/qt-project.org/imports/QtVncServer/
+
diff --git a/tests/unit/unittest/data/qml/QtWayland/Client/TextureSharing/qmldir b/tests/unit/unittest/data/qml/QtWayland/Client/TextureSharing/qmldir
new file mode 100644
index 00000000000..c9517aa7db7
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtWayland/Client/TextureSharing/qmldir
@@ -0,0 +1,7 @@
+module QtWayland.Client.TextureSharing
+linktarget Qt6::WaylandTextureSharing
+plugin waylandtexturesharingplugin
+classname QWaylandTextureSharingPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtWayland/Client/TextureSharing/
+
diff --git a/tests/unit/unittest/data/qml/QtWayland/Compositor/IviApplication/qmldir b/tests/unit/unittest/data/qml/QtWayland/Compositor/IviApplication/qmldir
new file mode 100644
index 00000000000..2a4e19ea91c
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtWayland/Compositor/IviApplication/qmldir
@@ -0,0 +1,7 @@
+module QtWayland.Compositor.IviApplication
+linktarget Qt6::WaylandCompositorIviapplication
+plugin waylandcompositoriviapplicationplugin
+classname QWaylandCompositorIviApplicationPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtWayland/Compositor/IviApplication/
+
diff --git a/tests/unit/unittest/data/qml/QtWayland/Compositor/PresentationTime/qmldir b/tests/unit/unittest/data/qml/QtWayland/Compositor/PresentationTime/qmldir
new file mode 100644
index 00000000000..40e25556307
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtWayland/Compositor/PresentationTime/qmldir
@@ -0,0 +1,7 @@
+module QtWayland.Compositor.PresentationTime
+linktarget Qt6::WaylandCompositorPresentationTime
+plugin waylandcompositorpresentationtimeplugin
+classname QWaylandCompositorPresentationTimePlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtWayland/Compositor/PresentationTime/
+
diff --git a/tests/unit/unittest/data/qml/QtWayland/Compositor/QtShell/qmldir b/tests/unit/unittest/data/qml/QtWayland/Compositor/QtShell/qmldir
new file mode 100644
index 00000000000..851feb14c97
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtWayland/Compositor/QtShell/qmldir
@@ -0,0 +1,7 @@
+module QtWayland.Compositor.QtShell
+linktarget Qt6::WaylandCompositorQtShell
+plugin waylandcompositorqtshellplugin
+classname QWaylandQtShellPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtWayland/Compositor/QtShell/
+
diff --git a/tests/unit/unittest/data/qml/QtWayland/Compositor/TextureSharingExtension/qmldir b/tests/unit/unittest/data/qml/QtWayland/Compositor/TextureSharingExtension/qmldir
new file mode 100644
index 00000000000..fd11b6052c2
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtWayland/Compositor/TextureSharingExtension/qmldir
@@ -0,0 +1,7 @@
+module QtWayland.Compositor.TextureSharingExtension
+linktarget Qt6::WaylandTextureSharingExtension
+plugin waylandtexturesharingextensionplugin
+classname QWaylandTextureSharingExtensionPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtWayland/Compositor/TextureSharingExtension/
+
diff --git a/tests/unit/unittest/data/qml/QtWayland/Compositor/WlShell/qmldir b/tests/unit/unittest/data/qml/QtWayland/Compositor/WlShell/qmldir
new file mode 100644
index 00000000000..19a44ce6b58
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtWayland/Compositor/WlShell/qmldir
@@ -0,0 +1,7 @@
+module QtWayland.Compositor.WlShell
+linktarget Qt6::WaylandCompositorWLShell
+plugin waylandcompositorwlshellplugin
+classname QWaylandCompositorWlShellPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtWayland/Compositor/WlShell/
+
diff --git a/tests/unit/unittest/data/qml/QtWayland/Compositor/XdgShell/qmldir b/tests/unit/unittest/data/qml/QtWayland/Compositor/XdgShell/qmldir
new file mode 100644
index 00000000000..8e04c730e49
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtWayland/Compositor/XdgShell/qmldir
@@ -0,0 +1,7 @@
+module QtWayland.Compositor.XdgShell
+linktarget Qt6::WaylandCompositorXdgShell
+plugin waylandcompositorxdgshellplugin
+classname QWaylandCompositorXdgShellPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtWayland/Compositor/XdgShell/
+
diff --git a/tests/unit/unittest/data/qml/QtWayland/Compositor/qmldir b/tests/unit/unittest/data/qml/QtWayland/Compositor/qmldir
new file mode 100644
index 00000000000..aba6cc89dce
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtWayland/Compositor/qmldir
@@ -0,0 +1,12 @@
+module QtWayland.Compositor
+linktarget Qt6::qwaylandcompositorplugin
+optional plugin qwaylandcompositorplugin
+classname QWaylandCompositorPlugin
+typeinfo WaylandCompositor.qmltypes
+depends QtQuick
+prefer :/qt-project.org/imports/QtWayland/Compositor/
+WaylandCursorItem 6.0 qmlfiles/WaylandCursorItem.qml
+WaylandCursorItem 1.0 qmlfiles/WaylandCursorItem.qml
+WaylandOutputWindow 6.0 qmlfiles/WaylandOutputWindow.qml
+WaylandOutputWindow 1.0 qmlfiles/WaylandOutputWindow.qml
+
diff --git a/tests/unit/unittest/data/qml/QtWebChannel/qmldir b/tests/unit/unittest/data/qml/QtWebChannel/qmldir
new file mode 100644
index 00000000000..4fb6b7116d2
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtWebChannel/qmldir
@@ -0,0 +1,7 @@
+module QtWebChannel
+linktarget Qt6::webchannel
+plugin webchannelplugin
+classname QWebChannelPlugin
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtWebChannel/
+
diff --git a/tests/unit/unittest/data/qml/QtWebEngine/ControlsDelegates/qmldir b/tests/unit/unittest/data/qml/QtWebEngine/ControlsDelegates/qmldir
new file mode 100644
index 00000000000..6c361034764
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtWebEngine/ControlsDelegates/qmldir
@@ -0,0 +1,36 @@
+module QtWebEngine.ControlsDelegates
+linktarget Qt6::qtwebenginequickdelegatesplugin
+optional plugin qtwebenginequickdelegatesplugin
+classname QtWebEngine_ControlsDelegatesPlugin
+typeinfo WebEngineQuickDelegatesQml.qmltypes
+depends QtQuickControls2
+prefer :/qt-project.org/imports/QtWebEngine/ControlsDelegates/
+AlertDialog 6.0 AlertDialog.qml
+AlertDialog 1.0 AlertDialog.qml
+AuthenticationDialog 6.0 AuthenticationDialog.qml
+AuthenticationDialog 1.0 AuthenticationDialog.qml
+AutofillPopup 6.0 AutofillPopup.qml
+AutofillPopup 1.0 AutofillPopup.qml
+ColorDialog 6.0 ColorDialog.qml
+ColorDialog 1.0 ColorDialog.qml
+ConfirmDialog 6.0 ConfirmDialog.qml
+ConfirmDialog 1.0 ConfirmDialog.qml
+DirectoryPicker 6.0 DirectoryPicker.qml
+DirectoryPicker 1.0 DirectoryPicker.qml
+FilePicker 6.0 FilePicker.qml
+FilePicker 1.0 FilePicker.qml
+Menu 6.0 Menu.qml
+Menu 1.0 Menu.qml
+MenuItem 6.0 MenuItem.qml
+MenuItem 1.0 MenuItem.qml
+MenuSeparator 6.0 MenuSeparator.qml
+MenuSeparator 1.0 MenuSeparator.qml
+PromptDialog 6.0 PromptDialog.qml
+PromptDialog 1.0 PromptDialog.qml
+ToolTip 6.0 ToolTip.qml
+ToolTip 1.0 ToolTip.qml
+TouchHandle 6.0 TouchHandle.qml
+TouchHandle 1.0 TouchHandle.qml
+TouchSelectionMenu 6.0 TouchSelectionMenu.qml
+TouchSelectionMenu 1.0 TouchSelectionMenu.qml
+
diff --git a/tests/unit/unittest/data/qml/QtWebEngine/qmldir b/tests/unit/unittest/data/qml/QtWebEngine/qmldir
new file mode 100644
index 00000000000..0709c060c48
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtWebEngine/qmldir
@@ -0,0 +1,9 @@
+module QtWebEngine
+linktarget Qt6::qtwebenginequickplugin
+plugin qtwebenginequickplugin
+classname QtWebEnginePlugin
+typeinfo plugins.qmltypes
+depends QtQuick auto
+depends QtWebChannel auto
+prefer :/qt-project.org/imports/QtWebEngine/
+
diff --git a/tests/unit/unittest/data/qml/QtWebSockets/qmldir b/tests/unit/unittest/data/qml/QtWebSockets/qmldir
new file mode 100644
index 00000000000..24224f087ca
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtWebSockets/qmldir
@@ -0,0 +1,7 @@
+module QtWebSockets
+linktarget Qt6::qmlwebsockets
+plugin qmlwebsocketsplugin
+classname QtWebSocketsDeclarativeModule
+typeinfo plugins.qmltypes
+prefer :/qt-project.org/imports/QtWebSockets/
+
diff --git a/tests/unit/unittest/data/qml/QtWebView/qmldir b/tests/unit/unittest/data/qml/QtWebView/qmldir
new file mode 100644
index 00000000000..3174233870a
--- /dev/null
+++ b/tests/unit/unittest/data/qml/QtWebView/qmldir
@@ -0,0 +1,8 @@
+module QtWebView
+linktarget Qt6::qtwebviewquickplugin
+plugin qtwebviewquickplugin
+classname QWebViewQuickPlugin
+typeinfo plugins.qmltypes
+depends QtWebEngine 2.0
+prefer :/qt-project.org/imports/QtWebView/
+
diff --git a/tests/unit/unittest/externaldependenciesmock.h b/tests/unit/unittest/externaldependenciesmock.h
new file mode 100644
index 00000000000..22654f70551
--- /dev/null
+++ b/tests/unit/unittest/externaldependenciesmock.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2017 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "googletest.h"
+
+#include <externaldependenciesinterface.h>
+
+class ExternalDependenciesMock : public QmlDesigner::ExternalDependenciesInterface
+{
+public:
+ MOCK_METHOD(double, formEditorDevicePixelRatio, (), (const, override));
+ MOCK_METHOD(QString, defaultPuppetFallbackDirectory, (), (const, override));
+ MOCK_METHOD(QString, qmlPuppetFallbackDirectory, (), (const, override));
+ MOCK_METHOD(QString, defaultPuppetToplevelBuildDirectory, (), (const, override));
+ MOCK_METHOD(QUrl, projectUrl, (), (const, override));
+ MOCK_METHOD(QString, currentProjectDirPath, (), (const, override));
+ MOCK_METHOD(QList<QColor>, designerSettingsEdit3DViewBackgroundColor, (), (const, override));
+ MOCK_METHOD(QColor, designerSettingsEdit3DViewGridColor, (), (const, override));
+ MOCK_METHOD(QUrl, currentResourcePath, (), (const, override));
+ MOCK_METHOD(void, parseItemLibraryDescriptions, (), (override));
+ MOCK_METHOD(const QmlDesigner::DesignerSettings &, designerSettings, (), (const, override));
+ MOCK_METHOD(void, undoOnCurrentDesignDocument, (), (override));
+ MOCK_METHOD(bool,
+ viewManagerUsesRewriterView,
+ (class QmlDesigner::RewriterView * view),
+ (const, override));
+ MOCK_METHOD(void, viewManagerDiableWidgets, (), (override));
+ MOCK_METHOD(QString, itemLibraryImportUserComponentsTitle, (), (const, override));
+ MOCK_METHOD(bool, isQt6Import, (), (const, override));
+ MOCK_METHOD(bool, hasStartupTarget, (), (const, override));
+ MOCK_METHOD(QmlDesigner::PuppetStartData,
+ puppetStartData,
+ (const class QmlDesigner::Model &model),
+ (const, override));
+ MOCK_METHOD(bool, instantQmlTextUpdate, (), (const, override));
+ MOCK_METHOD(Utils::FilePath, qmlPuppetPath, (), (const, override));
+ MOCK_METHOD(QStringList, modulePaths, (), (const, override));
+ MOCK_METHOD(QStringList, projectModulePaths, (), (const, override));
+ MOCK_METHOD(bool, isQt6Project, (), (const, override));
+ MOCK_METHOD(QString, qtQuickVersion, (), (const, override));
+ MOCK_METHOD(Utils::FilePath, resourcePath, (const QString &relativePath), (const, override));
+};
diff --git a/tests/unit/unittest/google-using-declarations.h b/tests/unit/unittest/google-using-declarations.h
index 67e887c696d..198bbce7842 100644
--- a/tests/unit/unittest/google-using-declarations.h
+++ b/tests/unit/unittest/google-using-declarations.h
@@ -5,7 +5,6 @@
#include <gmock/gmock.h>
-
using testing::_;
using testing::A;
using testing::AllOf;
@@ -21,15 +20,16 @@ using testing::ByRef;
using testing::ContainerEq;
using testing::Contains;
using testing::ElementsAre;
+using testing::EndsWith;
using testing::Eq;
using testing::Exactly;
using testing::Field;
+using testing::FieldsAre;
using testing::Ge;
using testing::Gt;
using testing::HasSubstr;
using testing::InSequence;
using testing::Invoke;
-using testing::IsEmpty;
using testing::IsNull;
using testing::Le;
using testing::Lt;
@@ -56,5 +56,6 @@ using testing::StrEq;
using testing::Throw;
using testing::TypedEq;
using testing::UnorderedElementsAre;
+using testing::UnorderedElementsAreArray;
using testing::VariantWith;
using testing::WithArg;
diff --git a/tests/unit/unittest/gtest-creator-printing.cpp b/tests/unit/unittest/gtest-creator-printing.cpp
index 602e973af1b..722dd01bc81 100644
--- a/tests/unit/unittest/gtest-creator-printing.cpp
+++ b/tests/unit/unittest/gtest-creator-printing.cpp
@@ -12,6 +12,7 @@
#include <clangtools/clangtoolsdiagnostic.h>
#include <debugger/analyzer/diagnosticlocation.h>
#include <imagecacheauxiliarydata.h>
+#include <import.h>
#include <modelnode.h>
#include <projectstorage/filestatus.h>
#include <projectstorage/projectstoragepathwatchertypes.h>
@@ -463,6 +464,11 @@ std::ostream &operator<<(std::ostream &out, const FileStatus &fileStatus)
<< fileStatus.lastModified << ")";
}
+std::ostream &operator<<(std::ostream &out, const Import &import)
+{
+ return out << "(" << import.url() << ", " << import.version() << ")";
+}
+
std::ostream &operator<<(std::ostream &out, SourceType sourceType)
{
return out << sourceTypeToText(sourceType);
@@ -571,6 +577,17 @@ std::ostream &operator<<(std::ostream &out, PropertyDeclarationTraits traits)
return out << ")";
}
+
+std::ostream &operator<<(std::ostream &out, VersionNumber versionNumber)
+{
+ return out << versionNumber.value;
+}
+
+std::ostream &operator<<(std::ostream &out, Version version)
+{
+ return out << "(" << version.major << ", " << version.minor << ")";
+}
+
} // namespace Storage
namespace Storage::Info {
@@ -691,16 +708,6 @@ std::ostream &operator<<(std::ostream &out, IsQualified isQualified)
return out << isQualifiedToString(isQualified);
}
-std::ostream &operator<<(std::ostream &out, VersionNumber versionNumber)
-{
- return out << versionNumber.value;
-}
-
-std::ostream &operator<<(std::ostream &out, Version version)
-{
- return out << "(" << version.major << ", " << version.minor << ")";
-}
-
std::ostream &operator<<(std::ostream &out, const ExportedType &exportedType)
{
return out << "(\"" << exportedType.name << "\"," << exportedType.moduleId << ", "
diff --git a/tests/unit/unittest/gtest-creator-printing.h b/tests/unit/unittest/gtest-creator-printing.h
index 4fb8b7d316b..aa8e6e77ac3 100644
--- a/tests/unit/unittest/gtest-creator-printing.h
+++ b/tests/unit/unittest/gtest-creator-printing.h
@@ -120,6 +120,7 @@ class IdPaths;
class ProjectChunkId;
enum class SourceType : int;
class FileStatus;
+class Import;
std::ostream &operator<<(std::ostream &out, const ModelNode &node);
std::ostream &operator<<(std::ostream &out, const VariantProperty &property);
@@ -128,6 +129,7 @@ std::ostream &operator<<(std::ostream &out, const IdPaths &idPaths);
std::ostream &operator<<(std::ostream &out, const ProjectChunkId &id);
std::ostream &operator<<(std::ostream &out, SourceType sourceType);
std::ostream &operator<<(std::ostream &out, const FileStatus &fileStatus);
+std::ostream &operator<<(std::ostream &out, const Import &import);
namespace Cache {
class SourceContext;
@@ -157,10 +159,13 @@ std::ostream &operator<<(std::ostream &out, TypeTraits traits);
namespace Storage::Info {
class ProjectDeclaration;
class Type;
+class Version;
+class VersionNumber;
std::ostream &operator<<(std::ostream &out, const ProjectDeclaration &declaration);
std::ostream &operator<<(std::ostream &out, const Type &type);
-
+std::ostream &operator<<(std::ostream &out, VersionNumber versionNumber);
+std::ostream &operator<<(std::ostream &out, Version version);
} // namespace Storage::Info
namespace Storage::Synchronization {
@@ -168,8 +173,6 @@ class Type;
class ExportedType;
class ImportedType;
class QualifiedImportedType;
-class Version;
-class VersionNumber;
class PropertyDeclaration;
class FunctionDeclaration;
class ParameterDeclaration;
@@ -186,8 +189,6 @@ enum class FileType : char;
enum class ChangeLevel : char;
class ModuleExportedImport;
-std::ostream &operator<<(std::ostream &out, VersionNumber versionNumber);
-std::ostream &operator<<(std::ostream &out, Version version);
std::ostream &operator<<(std::ostream &out, const Type &type);
std::ostream &operator<<(std::ostream &out, const ExportedType &exportedType);
std::ostream &operator<<(std::ostream &out, const ImportedType &importedType);
diff --git a/tests/unit/unittest/import-test.cpp b/tests/unit/unittest/import-test.cpp
new file mode 100644
index 00000000000..e4adfd7e5bb
--- /dev/null
+++ b/tests/unit/unittest/import-test.cpp
@@ -0,0 +1,340 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "googletest.h"
+
+#include <import.h>
+
+namespace {
+
+TEST(Import, ParseVersion)
+{
+ auto import = QmlDesigner::Import::createLibraryImport("Qml", "6.5");
+
+ auto version = import.toVersion();
+
+ ASSERT_THAT(version, FieldsAre(6, 5));
+}
+
+TEST(Import, ParseMajorVersion)
+{
+ auto import = QmlDesigner::Import::createLibraryImport("Qml", "6.5");
+
+ auto version = import.majorVersion();
+
+ ASSERT_THAT(version, 6);
+}
+
+TEST(Import, MajorVersionIsInvalidForEmptyString)
+{
+ auto import = QmlDesigner::Import::createLibraryImport("Qml");
+
+ auto version = import.majorVersion();
+
+ ASSERT_THAT(version, -1);
+}
+
+TEST(Import, MajorVersionIsInvalidForBrokenString)
+{
+ auto import = QmlDesigner::Import::createLibraryImport("Qml", "6,5");
+
+ auto version = import.majorVersion();
+
+ ASSERT_THAT(version, -1);
+}
+
+TEST(Import, ParseMinorVersion)
+{
+ auto import = QmlDesigner::Import::createLibraryImport("Qml", "6.5");
+
+ auto version = import.minorVersion();
+
+ ASSERT_THAT(version, 5);
+}
+
+TEST(Import, MinorVersionIsInvalidForEmptyString)
+{
+ auto import = QmlDesigner::Import::createLibraryImport("Qml");
+
+ auto version = import.minorVersion();
+
+ ASSERT_THAT(version, -1);
+}
+
+TEST(Import, MinorVersionIsInvalidForBrokenString)
+{
+ auto import = QmlDesigner::Import::createLibraryImport("Qml", "6,5");
+
+ auto version = import.minorVersion();
+
+ ASSERT_THAT(version, -1);
+}
+
+TEST(Import, VersionIsNotEmpty)
+{
+ auto import = QmlDesigner::Import::createLibraryImport("Qml", "6.5");
+
+ auto version = import.toVersion();
+
+ ASSERT_FALSE(version.isEmpty());
+}
+
+TEST(Import, BrokenVersionStringIsEmptyVersion)
+{
+ auto import = QmlDesigner::Import::createLibraryImport("Qml", "6");
+
+ auto version = import.toVersion();
+
+ ASSERT_TRUE(version.isEmpty());
+}
+
+TEST(Import, EmptyVersionStringIsEmptyVersion)
+{
+ auto import = QmlDesigner::Import::createLibraryImport("Qml");
+
+ auto version = import.toVersion();
+
+ ASSERT_TRUE(version.isEmpty());
+}
+
+TEST(Import, SameVersionsAreEqual)
+{
+ QmlDesigner::Version version1{6, 5};
+ QmlDesigner::Version version2{6, 5};
+
+ bool isEqual = version1 == version2;
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(Import, InvalidVersionsAreEqual)
+{
+ QmlDesigner::Version version1;
+ QmlDesigner::Version version2;
+
+ bool isEqual = version1 == version2;
+
+ ASSERT_TRUE(isEqual);
+}
+
+TEST(Import, DifferentMinorVersionsAreNotEqual)
+{
+ QmlDesigner::Version version1{6, 4};
+ QmlDesigner::Version version2{6, 5};
+
+ bool isEqual = version1 == version2;
+
+ ASSERT_FALSE(isEqual);
+}
+
+TEST(Import, DifferentMajorVersionsAreNotEqual)
+{
+ QmlDesigner::Version version1{5, 5};
+ QmlDesigner::Version version2{6, 5};
+
+ bool isEqual = version1 == version2;
+
+ ASSERT_FALSE(isEqual);
+}
+
+TEST(Import, LessMinorVersionsAreLess)
+{
+ QmlDesigner::Version version1{6, 4};
+ QmlDesigner::Version version2{6, 5};
+
+ bool isLess = version1 < version2;
+
+ ASSERT_TRUE(isLess);
+}
+
+TEST(Import, LessMajorVersionsAreLess)
+{
+ QmlDesigner::Version version1{5, 15};
+ QmlDesigner::Version version2{6, 5};
+
+ bool isLess = version1 < version2;
+
+ ASSERT_TRUE(isLess);
+}
+
+TEST(Import, SameVersionsAreNotLess)
+{
+ QmlDesigner::Version version1{6, 5};
+ QmlDesigner::Version version2{6, 5};
+
+ bool isLess = version1 < version2;
+
+ ASSERT_FALSE(isLess);
+}
+
+TEST(Import, EmptyVersionIsNotLess)
+{
+ QmlDesigner::Version version1;
+ QmlDesigner::Version version2{6, 5};
+
+ bool isLess = version1 < version2;
+
+ ASSERT_FALSE(isLess);
+}
+
+TEST(Import, NonEmptyVersionIsIsLessThanEmptyVersion)
+{
+ QmlDesigner::Version version1{6, 5};
+ QmlDesigner::Version version2;
+
+ bool isLess = version1 < version2;
+
+ ASSERT_TRUE(isLess);
+}
+
+TEST(Import, GreaterMinorVersionsAreGreater)
+{
+ QmlDesigner::Version version1{6, 6};
+ QmlDesigner::Version version2{6, 5};
+
+ bool isGreater = version1 > version2;
+
+ ASSERT_TRUE(isGreater);
+}
+
+TEST(Import, GreaterMajorVersionsAreGreater)
+{
+ QmlDesigner::Version version1{6, 5};
+ QmlDesigner::Version version2{5, 15};
+
+ bool isGreater = version1 > version2;
+
+ ASSERT_TRUE(isGreater);
+}
+
+TEST(Import, SameVersionsAreNotGreater)
+{
+ QmlDesigner::Version version1{6, 5};
+ QmlDesigner::Version version2{6, 5};
+
+ bool isGreater = version1 > version2;
+
+ ASSERT_FALSE(isGreater);
+}
+
+TEST(Import, EmptyVersionIsGreater)
+{
+ QmlDesigner::Version version1;
+ QmlDesigner::Version version2{6, 5};
+
+ bool isGreater = version1 > version2;
+
+ ASSERT_TRUE(isGreater);
+}
+
+TEST(Import, NonEmptyVersionIsIsNotGreaterThanEmptyVersion)
+{
+ QmlDesigner::Version version1{6, 5};
+ QmlDesigner::Version version2;
+
+ bool isGreater = version1 > version2;
+
+ ASSERT_FALSE(isGreater);
+}
+
+TEST(Import, LessEqualMinorVersionsAreLessEqual)
+{
+ QmlDesigner::Version version1{6, 4};
+ QmlDesigner::Version version2{6, 5};
+
+ bool isLessEqual = version1 <= version2;
+
+ ASSERT_TRUE(isLessEqual);
+}
+
+TEST(Import, LessqualMajorVersionsAreLessqual)
+{
+ QmlDesigner::Version version1{5, 15};
+ QmlDesigner::Version version2{6, 5};
+
+ bool isLessEqual = version1 <= version2;
+
+ ASSERT_TRUE(isLessEqual);
+}
+
+TEST(Import, SameVersionsAreLessqual)
+{
+ QmlDesigner::Version version1{6, 5};
+ QmlDesigner::Version version2{6, 5};
+
+ bool isLessEqual = version1 <= version2;
+
+ ASSERT_TRUE(isLessEqual);
+}
+
+TEST(Import, EmptyVersionIsNotLessqual)
+{
+ QmlDesigner::Version version1;
+ QmlDesigner::Version version2{6, 5};
+
+ bool isLessEqual = version1 <= version2;
+
+ ASSERT_FALSE(isLessEqual);
+}
+
+TEST(Import, NonEmptyVersionIsIsLessqualThanEmptyVersion)
+{
+ QmlDesigner::Version version1{6, 5};
+ QmlDesigner::Version version2;
+
+ bool isLessEqual = version1 <= version2;
+
+ ASSERT_TRUE(isLessEqual);
+}
+
+TEST(Import, GreaterEqualMinorVersionsAreGreaterEqual)
+{
+ QmlDesigner::Version version1{6, 6};
+ QmlDesigner::Version version2{6, 5};
+
+ bool isGreaterEqual = version1 >= version2;
+
+ ASSERT_TRUE(isGreaterEqual);
+}
+
+TEST(Import, GreaterEqualMajorVersionsAreGreaterEqual)
+{
+ QmlDesigner::Version version1{6, 5};
+ QmlDesigner::Version version2{5, 15};
+
+ bool isGreaterEqual = version1 >= version2;
+
+ ASSERT_TRUE(isGreaterEqual);
+}
+
+TEST(Import, SameVersionsAreGreaterEqual)
+{
+ QmlDesigner::Version version1{6, 5};
+ QmlDesigner::Version version2{6, 5};
+
+ bool isGreaterEqual = version1 >= version2;
+
+ ASSERT_TRUE(isGreaterEqual);
+}
+
+TEST(Import, EmptyVersionIsGreaterEqual)
+{
+ QmlDesigner::Version version1;
+ QmlDesigner::Version version2{6, 5};
+
+ bool isGreaterEqual = version1 >= version2;
+
+ ASSERT_TRUE(isGreaterEqual);
+}
+
+TEST(Import, NonEmptyVersionIsIsNotGreaterEqualThanEmptyVersion)
+{
+ QmlDesigner::Version version1{6, 5};
+ QmlDesigner::Version version2;
+
+ bool isGreaterEqual = version1 >= version2;
+
+ ASSERT_FALSE(isGreaterEqual);
+}
+
+} // namespace
diff --git a/tests/unit/unittest/listmodeleditor-test.cpp b/tests/unit/unittest/listmodeleditor-test.cpp
index 6443c8a7224..146ba65ad5d 100644
--- a/tests/unit/unittest/listmodeleditor-test.cpp
+++ b/tests/unit/unittest/listmodeleditor-test.cpp
@@ -4,6 +4,7 @@
#include "googletest.h"
#include "mocklistmodeleditorview.h"
+#include "projectstoragemock.h"
#include <qmldesigner/components/listmodeleditor/listmodeleditormodel.h>
#include <qmldesigner/designercore/include/abstractview.h>
@@ -19,6 +20,10 @@ using QmlDesigner::AbstractProperty;
using QmlDesigner::AbstractView;
using QmlDesigner::ListModelEditorModel;
using QmlDesigner::ModelNode;
+using QmlDesigner::ModuleId;
+using QmlDesigner::PropertyDeclarationId;
+using QmlDesigner::TypeId;
+namespace Info = QmlDesigner::Storage::Info;
MATCHER_P2(HasItem,
name,
@@ -91,7 +96,7 @@ public:
mockComponentView,
mockComponentView.rootModelNode());
- ON_CALL(mockGoIntoComponent, Call(_)).WillByDefault([](ModelNode node) { return node; });
+ ON_CALL(goIntoComponentMock, Call(_)).WillByDefault([](ModelNode node) { return node; });
}
using Entry = std::pair<QmlDesigner::PropertyName, QVariant>;
@@ -174,13 +179,15 @@ public:
}
protected:
- MockFunction<ModelNode(const ModelNode &)> mockGoIntoComponent;
- QmlDesigner::ModelPointer designerModel{QmlDesigner::Model::create("QtQuick.Item", 1, 1)};
+ NiceMock<ProjectStorageMockWithQtQtuick> projectStorageMock;
+ NiceMock<MockFunction<ModelNode(const ModelNode &)>> goIntoComponentMock;
+ QmlDesigner::ModelPointer designerModel{
+ QmlDesigner::Model::create(projectStorageMock, "QtQuick.Item", 1, 1)};
NiceMock<MockListModelEditorView> mockView;
QmlDesigner::ListModelEditorModel model{
[&] { return mockView.createModelNode("QtQml.Models.ListModel", 2, 15); },
[&] { return mockView.createModelNode("QtQml.Models.ListElement", 2, 15); },
- mockGoIntoComponent.AsStdFunction()};
+ goIntoComponentMock.AsStdFunction()};
ModelNode listViewNode;
ModelNode listModelNode;
ModelNode emptyListModelNode;
@@ -188,7 +195,7 @@ protected:
ModelNode element2;
ModelNode element3;
QmlDesigner::ModelPointer componentModel{
- QmlDesigner::Model::create("QtQml.Models.ListModel", 1, 1)};
+ QmlDesigner::Model::create(projectStorageMock, "QtQml.Models.ListModel", 1, 1)};
NiceMock<MockListModelEditorView> mockComponentView;
ModelNode componentElement;
};
@@ -1374,7 +1381,7 @@ TEST_F(ListModelEditor, AddFalseAsStringProperties)
TEST_F(ListModelEditor, GoIntoComponentForBinding)
{
- EXPECT_CALL(mockGoIntoComponent, Call(Eq(listModelNode)))
+ EXPECT_CALL(goIntoComponentMock, Call(Eq(listModelNode)))
.WillRepeatedly(Return(mockComponentView.rootModelNode()));
listModelNode.setIdWithoutRefactoring("listModel");
listViewNode.bindingProperty("model").setExpression("listModel");
@@ -1386,7 +1393,7 @@ TEST_F(ListModelEditor, GoIntoComponentForBinding)
TEST_F(ListModelEditor, GoIntoComponentForModelNode)
{
- EXPECT_CALL(mockGoIntoComponent, Call(Eq(listModelNode)))
+ EXPECT_CALL(goIntoComponentMock, Call(Eq(listModelNode)))
.WillRepeatedly(Return(mockComponentView.rootModelNode()));
listViewNode.nodeProperty("model").reparentHere(listModelNode);
diff --git a/tests/unit/unittest/mocklistmodeleditorview.h b/tests/unit/unittest/mocklistmodeleditorview.h
index 1de8e1edea0..0f6ff38742e 100644
--- a/tests/unit/unittest/mocklistmodeleditorview.h
+++ b/tests/unit/unittest/mocklistmodeleditorview.h
@@ -26,10 +26,25 @@ public:
const QmlDesigner::NodeAbstractProperty &oldPropertyParent,
AbstractView::PropertyChangeFlags propertyChange),
(override));
+
MOCK_METHOD(void,
propertiesRemoved,
(const QList<QmlDesigner::AbstractProperty> &propertyList),
(override));
+ MOCK_METHOD(void,
+ propertiesAboutToBeRemoved,
+ (const QList<QmlDesigner::AbstractProperty> &propertyList),
+ (override));
+
+ MOCK_METHOD(void,
+ bindingPropertiesChanged,
+ (const QList<QmlDesigner::BindingProperty> &propertyList,
+ PropertyChangeFlags propertyChange),
+ (override));
+ MOCK_METHOD(void,
+ bindingPropertiesAboutToBeChanged,
+ (const QList<QmlDesigner::BindingProperty> &propertyList),
+ (override));
MOCK_METHOD(void,
nodeRemoved,
@@ -37,4 +52,5 @@ public:
const QmlDesigner::NodeAbstractProperty &parentProperty,
AbstractView::PropertyChangeFlags propertyChange),
(override));
+ MOCK_METHOD(void, nodeAboutToBeRemoved, (const QmlDesigner::ModelNode &removedNode), (override));
};
diff --git a/tests/unit/unittest/model-test.cpp b/tests/unit/unittest/model-test.cpp
new file mode 100644
index 00000000000..7de2618aa93
--- /dev/null
+++ b/tests/unit/unittest/model-test.cpp
@@ -0,0 +1,491 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "googletest.h"
+
+#include "mocklistmodeleditorview.h"
+#include "modelresourcemanagementmock.h"
+#include "projectstoragemock.h"
+
+#include <designercore/include/bindingproperty.h>
+#include <designercore/include/model.h>
+#include <designercore/include/modelnode.h>
+#include <designercore/include/nodeabstractproperty.h>
+#include <designercore/include/nodelistproperty.h>
+#include <designercore/include/nodeproperty.h>
+#include <designercore/include/signalhandlerproperty.h>
+#include <designercore/include/variantproperty.h>
+
+namespace {
+using QmlDesigner::AbstractProperty;
+using QmlDesigner::ModelNode;
+using QmlDesigner::ModelNodes;
+using QmlDesigner::ModelResourceSet;
+
+template<typename Matcher>
+auto HasPropertyName(const Matcher &matcher)
+{
+ return Property(&AbstractProperty::name, matcher);
+}
+
+class Model : public ::testing::Test
+{
+protected:
+ Model()
+ {
+ model.attachView(&viewMock);
+ rootNode = viewMock.rootModelNode();
+ ON_CALL(resourceManagementMock, removeNode(_)).WillByDefault([](const auto &node) {
+ return ModelResourceSet{{node}, {}, {}};
+ });
+ ON_CALL(resourceManagementMock, removeProperty(_)).WillByDefault([](const auto &property) {
+ return ModelResourceSet{{}, {property}, {}};
+ });
+ }
+
+ ~Model() { model.detachView(&viewMock); }
+
+ auto createNodeWithParent(const ModelNode &parentNode)
+ {
+ auto node = viewMock.createModelNode("QtQuick.Item");
+ parentNode.defaultNodeAbstractProperty().reparentHere(node);
+
+ return node;
+ }
+
+ auto createProperty(const ModelNode &parentNode, QmlDesigner::PropertyName name)
+ {
+ auto property = parentNode.variantProperty(name);
+ property.setValue(4);
+ return property;
+ }
+
+protected:
+ NiceMock<MockListModelEditorView> viewMock;
+ NiceMock<ProjectStorageMockWithQtQtuick> projectStorageMock;
+ NiceMock<ModelResourceManagementMock> resourceManagementMock;
+ QmlDesigner::Model model{projectStorageMock,
+ "QtQuick.Item",
+ -1,
+ -1,
+ nullptr,
+ std::make_unique<ModelResourceManagementMockWrapper>(
+ resourceManagementMock)};
+ ModelNode rootNode;
+};
+
+TEST_F(Model, ModelNodeDestroyIsCallingModelResourceManagementRemoveNode)
+{
+ auto node = createNodeWithParent(rootNode);
+
+ EXPECT_CALL(resourceManagementMock, removeNode(node));
+
+ node.destroy();
+}
+
+TEST_F(Model, ModelNodeRemoveProperyIsCallingModelResourceManagementRemoveProperty)
+{
+ auto property = rootNode.variantProperty("foo");
+ property.setValue(4);
+
+ EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
+
+ rootNode.removeProperty("foo");
+}
+
+TEST_F(Model, NodeAbstractPropertyReparentHereIsCallingModelResourceManagementRemoveProperty)
+{
+ auto node = createNodeWithParent(rootNode);
+ auto property = rootNode.variantProperty("foo");
+ property.setValue(4);
+
+ EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
+
+ rootNode.nodeListProperty("foo").reparentHere(node);
+}
+
+TEST_F(Model, NodePropertySetModelNodeIsCallingModelResourceManagementRemoveProperty)
+{
+ auto node = createNodeWithParent(rootNode);
+ auto property = rootNode.variantProperty("foo");
+ property.setValue(4);
+
+ EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
+
+ rootNode.nodeProperty("foo").setModelNode(node);
+}
+
+TEST_F(Model, VariantPropertySetValueIsCallingModelResourceManagementRemoveProperty)
+{
+ auto property = rootNode.bindingProperty("foo");
+ property.setExpression("blah");
+
+ EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
+
+ rootNode.variantProperty("foo").setValue(7);
+}
+
+TEST_F(Model,
+ VariantPropertySetDynamicTypeNameAndEnumerationIsCallingModelResourceManagementRemoveProperty)
+{
+ auto property = rootNode.bindingProperty("foo");
+ property.setExpression("blah");
+
+ EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
+
+ rootNode.variantProperty("foo").setDynamicTypeNameAndEnumeration("int", "Ha");
+}
+
+TEST_F(Model, VariantPropertySetDynamicTypeNameAndValueIsCallingModelResourceManagementRemoveProperty)
+{
+ auto property = rootNode.bindingProperty("foo");
+ property.setExpression("blah");
+
+ EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
+
+ rootNode.variantProperty("foo").setDynamicTypeNameAndValue("int", 7);
+}
+
+TEST_F(Model, BindingPropertySetExpressionIsCallingModelResourceManagementRemoveProperty)
+{
+ auto property = rootNode.variantProperty("foo");
+ property.setValue(4);
+
+ EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
+
+ rootNode.bindingProperty("foo").setExpression("blah");
+}
+
+TEST_F(Model,
+ BindingPropertySetDynamicTypeNameAndExpressionIsCallingModelResourceManagementRemoveProperty)
+{
+ auto property = rootNode.variantProperty("foo");
+ property.setValue(4);
+
+ EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
+
+ rootNode.bindingProperty("foo").setDynamicTypeNameAndExpression("int", "blah");
+}
+
+TEST_F(Model, SignalHandlerPropertySetSourceIsCallingModelResourceManagementRemoveProperty)
+{
+ auto property = rootNode.bindingProperty("foo");
+ property.setExpression("blah");
+
+ EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
+
+ rootNode.signalHandlerProperty("foo").setSource("blah");
+}
+
+TEST_F(Model, SignalDeclarationPropertySetSignatureIsCallingModelResourceManagementRemoveProperty)
+{
+ auto property = rootNode.bindingProperty("foo");
+ property.setExpression("blah");
+
+ EXPECT_CALL(resourceManagementMock, removeProperty(Eq(property)));
+
+ rootNode.signalDeclarationProperty("foo").setSignature("blah");
+}
+
+TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewNodeAboutToBeRemoved)
+{
+ auto node = createNodeWithParent(rootNode);
+ auto node2 = createNodeWithParent(rootNode);
+ ON_CALL(resourceManagementMock, removeNode(node))
+ .WillByDefault(Return(ModelResourceSet{{node, node2}, {}, {}}));
+
+ EXPECT_CALL(viewMock, nodeAboutToBeRemoved(Eq(node)));
+ EXPECT_CALL(viewMock, nodeAboutToBeRemoved(Eq(node2)));
+
+ node.destroy();
+}
+
+TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewNodeRemoved)
+{
+ auto node = createNodeWithParent(rootNode);
+ auto node2 = createNodeWithParent(rootNode);
+ ON_CALL(resourceManagementMock, removeNode(node))
+ .WillByDefault(Return(ModelResourceSet{{node, node2}, {}, {}}));
+
+ EXPECT_CALL(viewMock, nodeRemoved(Eq(node), _, _));
+ EXPECT_CALL(viewMock, nodeRemoved(Eq(node2), _, _));
+
+ node.destroy();
+}
+
+TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewNodeRemovedWithValidNodes)
+{
+ auto node = createNodeWithParent(rootNode);
+ auto node2 = createNodeWithParent(rootNode);
+ ON_CALL(resourceManagementMock, removeNode(node))
+ .WillByDefault(Return(ModelResourceSet{{node, node2, ModelNode{}}, {}, {}}));
+
+ EXPECT_CALL(viewMock, nodeRemoved(Eq(node), _, _));
+ EXPECT_CALL(viewMock, nodeRemoved(Eq(node2), _, _));
+
+ node.destroy();
+}
+
+TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewPropertiesAboutToBeRemoved)
+{
+ auto node = createNodeWithParent(rootNode);
+ auto property = createProperty(rootNode, "foo");
+ auto property2 = createProperty(rootNode, "bar");
+ ON_CALL(resourceManagementMock, removeNode(node))
+ .WillByDefault(Return(ModelResourceSet{{node}, {property, property2}, {}}));
+
+ EXPECT_CALL(viewMock, propertiesAboutToBeRemoved(ElementsAre(Eq(property))));
+ EXPECT_CALL(viewMock, propertiesAboutToBeRemoved(ElementsAre(Eq(property2))));
+
+ node.destroy();
+}
+
+TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewPropertiesRemoved)
+{
+ auto node = createNodeWithParent(rootNode);
+ auto property = createProperty(rootNode, "foo");
+ auto property2 = createProperty(rootNode, "bar");
+ ON_CALL(resourceManagementMock, removeNode(node))
+ .WillByDefault(Return(ModelResourceSet{{node}, {property, property2}, {}}));
+
+ EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property))));
+ EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property2))));
+
+ node.destroy();
+}
+
+TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewPropertiesRemovedOnlyWithValidProperties)
+{
+ auto node = createNodeWithParent(rootNode);
+ auto property = createProperty(rootNode, "foo");
+ auto property2 = createProperty(rootNode, "bar");
+ ON_CALL(resourceManagementMock, removeNode(node))
+ .WillByDefault(Return(ModelResourceSet{{node}, {property, property2, {}}, {}}));
+
+ EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property))));
+ EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property2))));
+
+ node.destroy();
+}
+
+TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewBindingPropertiesAboutToBeChanged)
+{
+ auto node = createNodeWithParent(rootNode);
+ auto property = rootNode.bindingProperty("foo");
+ auto property2 = rootNode.bindingProperty("bar");
+ ON_CALL(resourceManagementMock, removeNode(node))
+ .WillByDefault(Return(ModelResourceSet{{node}, {}, {{property, "yi"}, {property2, "er"}}}));
+
+ EXPECT_CALL(viewMock, bindingPropertiesAboutToBeChanged(ElementsAre(Eq(property))));
+ EXPECT_CALL(viewMock, bindingPropertiesAboutToBeChanged(ElementsAre(Eq(property2))));
+
+ node.destroy();
+}
+
+TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewBindingPropertiesChanged)
+{
+ auto node = createNodeWithParent(rootNode);
+ auto property = rootNode.bindingProperty("foo");
+ auto property2 = rootNode.bindingProperty("bar");
+ ON_CALL(resourceManagementMock, removeNode(node))
+ .WillByDefault(Return(ModelResourceSet{{node}, {}, {{property, "yi"}, {property2, "er"}}}));
+
+ EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property)), _));
+ EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property2)), _));
+
+ node.destroy();
+}
+
+TEST_F(Model, ModelNodeDestroyIsCallingAbstractViewBindingPropertiesChangedOnlyWithValidProperties)
+{
+ auto node = createNodeWithParent(rootNode);
+ auto property = rootNode.bindingProperty("foo");
+ auto property2 = rootNode.bindingProperty("bar");
+ ON_CALL(resourceManagementMock, removeNode(node))
+ .WillByDefault(Return(
+ ModelResourceSet{{node}, {}, {{property, "yi"}, {property2, "er"}, {{}, "san"}}}));
+
+ EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property)), _));
+ EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property2)), _));
+
+ node.destroy();
+}
+
+TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewNodeAboutToBeRemoved)
+{
+ auto property = createProperty(rootNode, "foo");
+ auto node = createNodeWithParent(rootNode);
+ auto node2 = createNodeWithParent(rootNode);
+ ON_CALL(resourceManagementMock, removeProperty(property))
+ .WillByDefault(Return(ModelResourceSet{{node, node2}, {property}, {}}));
+
+ EXPECT_CALL(viewMock, nodeAboutToBeRemoved(Eq(node)));
+ EXPECT_CALL(viewMock, nodeAboutToBeRemoved(Eq(node2)));
+
+ rootNode.removeProperty("foo");
+}
+
+TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewNodeRemoved)
+{
+ auto property = createProperty(rootNode, "foo");
+ auto node = createNodeWithParent(rootNode);
+ auto node2 = createNodeWithParent(rootNode);
+ ON_CALL(resourceManagementMock, removeProperty(property))
+ .WillByDefault(Return(ModelResourceSet{{node, node2}, {property}, {}}));
+
+ EXPECT_CALL(viewMock, nodeRemoved(Eq(node), _, _));
+ EXPECT_CALL(viewMock, nodeRemoved(Eq(node2), _, _));
+
+ rootNode.removeProperty("foo");
+}
+
+TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewNodeRemovedWithValidNodes)
+{
+ auto property = createProperty(rootNode, "foo");
+ auto node = createNodeWithParent(rootNode);
+ auto node2 = createNodeWithParent(rootNode);
+ ON_CALL(resourceManagementMock, removeProperty(property))
+ .WillByDefault(Return(ModelResourceSet{{node, node2, ModelNode{}}, {property}, {}}));
+
+ EXPECT_CALL(viewMock, nodeRemoved(Eq(node), _, _));
+ EXPECT_CALL(viewMock, nodeRemoved(Eq(node2), _, _));
+
+ rootNode.removeProperty("foo");
+}
+
+TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewPropertiesAboutToBeRemoved)
+{
+ auto property = createProperty(rootNode, "yi");
+ auto property2 = createProperty(rootNode, "er");
+ ON_CALL(resourceManagementMock, removeProperty(property))
+ .WillByDefault(Return(ModelResourceSet{{}, {property, property2}, {}}));
+
+ EXPECT_CALL(viewMock, propertiesAboutToBeRemoved(ElementsAre(Eq(property))));
+ EXPECT_CALL(viewMock, propertiesAboutToBeRemoved(ElementsAre(Eq(property2))));
+
+ rootNode.removeProperty("yi");
+}
+
+TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewPropertiesRemoved)
+{
+ auto property = createProperty(rootNode, "yi");
+ auto property2 = createProperty(rootNode, "er");
+ ON_CALL(resourceManagementMock, removeProperty(property))
+ .WillByDefault(Return(ModelResourceSet{{}, {property, property2}, {}}));
+
+ EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property))));
+ EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property2))));
+
+ rootNode.removeProperty("yi");
+}
+
+TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewPropertiesRemovedOnlyWithValidProperties)
+{
+ auto property = createProperty(rootNode, "yi");
+ auto property2 = createProperty(rootNode, "er");
+ ON_CALL(resourceManagementMock, removeProperty(property))
+ .WillByDefault(Return(ModelResourceSet{{}, {property, property2, {}}, {}}));
+
+ EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property))));
+ EXPECT_CALL(viewMock, propertiesRemoved(ElementsAre(Eq(property2))));
+
+ rootNode.removeProperty("yi");
+}
+
+TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewBindingPropertiesAboutToBeChanged)
+{
+ auto property = createProperty(rootNode, "yi");
+ auto property1 = rootNode.bindingProperty("foo");
+ auto property2 = rootNode.bindingProperty("bar");
+ ON_CALL(resourceManagementMock, removeProperty(property))
+ .WillByDefault(
+ Return(ModelResourceSet{{}, {property}, {{property1, "yi"}, {property2, "er"}}}));
+
+ EXPECT_CALL(viewMock, bindingPropertiesAboutToBeChanged(ElementsAre(Eq(property1))));
+ EXPECT_CALL(viewMock, bindingPropertiesAboutToBeChanged(ElementsAre(Eq(property2))));
+
+ rootNode.removeProperty("yi");
+}
+
+TEST_F(Model, ModelNodeRemovePropertyIsCallingAbstractViewBindingPropertiesChanged)
+{
+ auto property = createProperty(rootNode, "yi");
+ auto property1 = rootNode.bindingProperty("foo");
+ auto property2 = rootNode.bindingProperty("bar");
+ ON_CALL(resourceManagementMock, removeProperty(property))
+ .WillByDefault(
+ Return(ModelResourceSet{{}, {property}, {{property1, "yi"}, {property2, "er"}}}));
+
+ EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property1)), _));
+ EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property2)), _));
+
+ rootNode.removeProperty("yi");
+}
+
+TEST_F(Model,
+ ModelNodeRemovePropertyIsCallingAbstractViewBindingPropertiesChangedOnlyWithValidProperties)
+{
+ auto property = createProperty(rootNode, "yi");
+ auto property1 = rootNode.bindingProperty("foo");
+ auto property2 = rootNode.bindingProperty("bar");
+ ON_CALL(resourceManagementMock, removeProperty(property))
+ .WillByDefault(
+ Return(ModelResourceSet{{}, {property}, {{property1, "yi"}, {property2, "er"}, {}}}));
+
+ EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property1)), _));
+ EXPECT_CALL(viewMock, bindingPropertiesChanged(ElementsAre(Eq(property2)), _));
+
+ rootNode.removeProperty("yi");
+}
+
+TEST_F(Model, ByDefaultRemoveModelNodeRemovesNode)
+{
+ model.detachView(&viewMock);
+ QmlDesigner::Model newModel{projectStorageMock, "QtQuick.Item"};
+ newModel.attachView(&viewMock);
+ auto node = createNodeWithParent(viewMock.rootModelNode());
+
+ EXPECT_CALL(viewMock, nodeAboutToBeRemoved(Eq(node)));
+
+ node.destroy();
+}
+
+TEST_F(Model, ByDefaultRemovePropertiesRemovesProperty)
+{
+ model.detachView(&viewMock);
+ QmlDesigner::Model newModel{projectStorageMock, "QtQuick.Item"};
+ newModel.attachView(&viewMock);
+ rootNode = viewMock.rootModelNode();
+ auto property = createProperty(rootNode, "yi");
+
+ EXPECT_CALL(viewMock, propertiesAboutToBeRemoved(ElementsAre(Eq(property))));
+
+ rootNode.removeProperty("yi");
+}
+
+TEST_F(Model, ByDefaultRemoveModelNodeInFactoryMethodCallsRemovesNode)
+{
+ model.detachView(&viewMock);
+ auto newModel = QmlDesigner::Model::create(projectStorageMock, "QtQuick.Item");
+ newModel->attachView(&viewMock);
+ auto node = createNodeWithParent(viewMock.rootModelNode());
+
+ EXPECT_CALL(viewMock, nodeAboutToBeRemoved(Eq(node)));
+
+ node.destroy();
+}
+
+TEST_F(Model, ByDefaultRemovePropertiesInFactoryMethodCallsRemoveProperty)
+{
+ model.detachView(&viewMock);
+ auto newModel = QmlDesigner::Model::create(projectStorageMock, "QtQuick.Item");
+ newModel->attachView(&viewMock);
+ rootNode = viewMock.rootModelNode();
+ auto property = createProperty(rootNode, "yi");
+
+ EXPECT_CALL(viewMock, propertiesAboutToBeRemoved(ElementsAre(Eq(property))));
+
+ rootNode.removeProperty("yi");
+}
+
+} // namespace
diff --git a/tests/unit/unittest/modelresourcemanagementmock.h b/tests/unit/unittest/modelresourcemanagementmock.h
new file mode 100644
index 00000000000..0b98adfcff0
--- /dev/null
+++ b/tests/unit/unittest/modelresourcemanagementmock.h
@@ -0,0 +1,42 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "googletest.h"
+
+#include <model/modelresourcemanagementinterface.h>
+#include <modelnode.h>
+
+class ModelResourceManagementMock : public QmlDesigner::ModelResourceManagementInterface
+{
+public:
+ MOCK_METHOD(QmlDesigner::ModelResourceSet,
+ removeNode,
+ (const QmlDesigner::ModelNode &),
+ (const, override));
+ MOCK_METHOD(QmlDesigner::ModelResourceSet,
+ removeProperty,
+ (const QmlDesigner::AbstractProperty &),
+ (const, override));
+};
+
+class ModelResourceManagementMockWrapper : public QmlDesigner::ModelResourceManagementInterface
+{
+public:
+ ModelResourceManagementMockWrapper(ModelResourceManagementMock &mock)
+ : mock{mock}
+ {}
+
+ QmlDesigner::ModelResourceSet removeNode(const QmlDesigner::ModelNode &node) const override
+ {
+ return mock.removeNode(node);
+ }
+
+ QmlDesigner::ModelResourceSet removeProperty(const QmlDesigner::AbstractProperty &property) const override
+ {
+ return mock.removeProperty(property);
+ }
+
+ ModelResourceManagementMock &mock;
+};
diff --git a/tests/unit/unittest/modulescanner-test.cpp b/tests/unit/unittest/modulescanner-test.cpp
new file mode 100644
index 00000000000..554e3fc8398
--- /dev/null
+++ b/tests/unit/unittest/modulescanner-test.cpp
@@ -0,0 +1,179 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "externaldependenciesmock.h"
+#include "googletest.h"
+
+#include <projectstorage/modulescanner.h>
+
+#include <QDebug>
+
+namespace {
+
+QLatin1String qmlModulesPath(TESTDATA_DIR "/qml");
+
+template<typename Matcher>
+auto UrlProperty(const Matcher &matcher)
+{
+ return Property(&QmlDesigner::Import::url, matcher);
+}
+
+template<typename Matcher>
+auto VersionProperty(const Matcher &matcher)
+{
+ return Property(&QmlDesigner::Import::version, matcher);
+}
+
+template<typename Matcher>
+auto CorePropertiesHave(const Matcher &matcher)
+{
+ return AllOf(Contains(AllOf(UrlProperty("QtQuick"), matcher)),
+ Contains(AllOf(UrlProperty("QtQuick.Controls"), matcher)),
+ Contains(AllOf(UrlProperty("QtQuick3D"), matcher)),
+ Contains(AllOf(UrlProperty("QtQuick3D.Helpers"), matcher)),
+ Contains(AllOf(UrlProperty("QtQuick3D.Particles3D"), matcher)));
+}
+
+template<typename Matcher>
+auto NonCorePropertiesHave(const Matcher &matcher)
+{
+ return Not(Contains(AllOf(UrlProperty(AnyOf(Eq("QtQuick"),
+ Eq("QtQuick.Controls"),
+ Eq("QtQuick3D"),
+ Eq("QtQuick3D.Helpers"),
+ Eq("QtQuick3D.Particles3D"))),
+ matcher)));
+}
+
+MATCHER(HasDuplicates, std::string(negation ? "hasn't duplicates" : "has dublicates"))
+{
+ auto values = arg;
+ std::sort(values.begin(), values.begin());
+ auto found = std::adjacent_find(values.begin(), values.end());
+
+ return found != values.end();
+}
+
+class ModuleScanner : public testing::Test
+{
+protected:
+ NiceMock<ExternalDependenciesMock> externalDependenciesMock;
+ QmlDesigner::ModuleScanner scanner{[](QStringView moduleName) {
+ return moduleName.endsWith(u"impl");
+ },
+ QmlDesigner::VersionScanning::No,
+ externalDependenciesMock};
+};
+
+TEST_F(ModuleScanner, ReturnEmptyOptionalForEmptyPath)
+{
+ scanner.scan(QStringList{""});
+
+ ASSERT_THAT(scanner.modules(), IsEmpty());
+}
+
+TEST_F(ModuleScanner, ReturnEmptyOptionalForNullStringPath)
+{
+ scanner.scan(QStringList{QString{}});
+
+ ASSERT_THAT(scanner.modules(), IsEmpty());
+}
+
+TEST_F(ModuleScanner, ReturnEmptyOptionalForEmptyPaths)
+{
+ scanner.scan(QStringList{});
+
+ ASSERT_THAT(scanner.modules(), IsEmpty());
+}
+
+TEST_F(ModuleScanner, GetQtQuick)
+{
+ scanner.scan(QStringList{qmlModulesPath});
+
+ ASSERT_THAT(scanner.modules(), Contains(UrlProperty("QtQuick")));
+}
+
+TEST_F(ModuleScanner, SkipEmptyModules)
+{
+ scanner.scan(QStringList{qmlModulesPath});
+
+ ASSERT_THAT(scanner.modules(), Not(Contains(UrlProperty(IsEmpty()))));
+}
+
+TEST_F(ModuleScanner, UseSkipFunction)
+{
+ scanner.scan(QStringList{qmlModulesPath});
+
+ ASSERT_THAT(scanner.modules(), Not(Contains(UrlProperty(EndsWith(QStringView{u"impl"})))));
+}
+
+TEST_F(ModuleScanner, Version)
+{
+ QmlDesigner::ModuleScanner scanner{[](QStringView moduleName) {
+ return moduleName.endsWith(u"impl");
+ },
+ QmlDesigner::VersionScanning::Yes,
+ externalDependenciesMock};
+
+ scanner.scan(QStringList{TESTDATA_DIR "/modulescanner"});
+
+ ASSERT_THAT(scanner.modules(), ElementsAre(AllOf(UrlProperty("Example"), VersionProperty("1.3"))));
+
+}
+
+TEST_F(ModuleScanner, NoVersion)
+{
+ QmlDesigner::ModuleScanner scanner{[](QStringView moduleName) {
+ return moduleName.endsWith(u"impl");
+ },
+ QmlDesigner::VersionScanning::No,
+ externalDependenciesMock};
+
+ scanner.scan(QStringList{TESTDATA_DIR "/modulescanner"});
+
+ ASSERT_THAT(scanner.modules(),
+ ElementsAre(AllOf(UrlProperty("Example"), VersionProperty(QString{}))));
+}
+
+TEST_F(ModuleScanner, Duplicates)
+{
+ scanner.scan(QStringList{qmlModulesPath});
+
+ ASSERT_THAT(scanner.modules(), Not(HasDuplicates()));
+}
+
+TEST_F(ModuleScanner, DontAddModulesAgain)
+{
+ scanner.scan(QStringList{qmlModulesPath});
+
+ scanner.scan(QStringList{qmlModulesPath});
+
+ ASSERT_THAT(scanner.modules(), Not(HasDuplicates()));
+}
+
+TEST_F(ModuleScanner, SetNoVersionForQtQuickVersion)
+{
+ scanner.scan(QStringList{qmlModulesPath});
+
+ ASSERT_THAT(scanner.modules(), CorePropertiesHave(VersionProperty(QString{})));
+}
+
+TEST_F(ModuleScanner, SetVersionForQtQuickVersion)
+{
+ ON_CALL(externalDependenciesMock, qtQuickVersion()).WillByDefault(Return(QString{"6.4"}));
+
+ scanner.scan(QStringList{qmlModulesPath});
+
+ ASSERT_THAT(scanner.modules(), CorePropertiesHave(VersionProperty(u"6.4")));
+}
+
+TEST_F(ModuleScanner, DontSetVersionForNonQtQuickVersion)
+{
+ ON_CALL(externalDependenciesMock, qtQuickVersion()).WillByDefault(Return(QString{"6.4"}));
+
+ scanner.scan(QStringList{qmlModulesPath});
+
+ ASSERT_THAT(scanner.modules(), NonCorePropertiesHave(VersionProperty(QString{})));
+}
+
+} // namespace
diff --git a/tests/unit/unittest/nodelistproperty-test.cpp b/tests/unit/unittest/nodelistproperty-test.cpp
index edeeaee9c21..36a8dcb6df7 100644
--- a/tests/unit/unittest/nodelistproperty-test.cpp
+++ b/tests/unit/unittest/nodelistproperty-test.cpp
@@ -3,6 +3,7 @@
#include "abstractviewmock.h"
#include "googletest.h"
+#include "projectstoragemock.h"
#include <model.h>
#include <modelnode.h>
@@ -13,6 +14,10 @@
namespace {
using QmlDesigner::ModelNode;
+using QmlDesigner::ModuleId;
+using QmlDesigner::PropertyDeclarationId;
+using QmlDesigner::TypeId;
+namespace Info = QmlDesigner::Storage::Info;
class NodeListProperty : public testing::Test
{
@@ -38,6 +43,29 @@ protected:
~NodeListProperty() { model->detachView(&abstractViewMock); }
+ void setModuleId(Utils::SmallStringView moduleName, ModuleId moduleId)
+ {
+ ON_CALL(projectStorageMock, moduleId(Eq(moduleName))).WillByDefault(Return(moduleId));
+ }
+
+ void setType(ModuleId moduleId,
+ Utils::SmallStringView typeName,
+ Utils::SmallString defaultPeopertyName)
+ {
+ static int typeIdNumber = 0;
+ TypeId typeId = TypeId::create(++typeIdNumber);
+
+ static int defaultPropertyIdNumber = 0;
+ PropertyDeclarationId defaultPropertyId = PropertyDeclarationId::create(
+ ++defaultPropertyIdNumber);
+
+ ON_CALL(projectStorageMock, typeId(Eq(moduleId), Eq(typeName), _)).WillByDefault(Return(typeId));
+ ON_CALL(projectStorageMock, type(Eq(typeId)))
+ .WillByDefault(Return(Info::Type{defaultPropertyId, {}}));
+ ON_CALL(projectStorageMock, propertyName(Eq(defaultPropertyId)))
+ .WillByDefault(Return(defaultPeopertyName));
+ }
+
std::vector<ModelNode> nodes() const
{
return std::vector<ModelNode>{nodeListProperty.begin(), nodeListProperty.end()};
@@ -49,7 +77,9 @@ protected:
}
protected:
- std::unique_ptr<QmlDesigner::Model> model{std::make_unique<QmlDesigner::Model>("QtQuick.Item")};
+ NiceMock<ProjectStorageMockWithQtQtuick> projectStorageMock;
+ std::unique_ptr<QmlDesigner::Model> model{
+ std::make_unique<QmlDesigner::Model>(projectStorageMock, "QtQuick.Item")};
NiceMock<AbstractViewMock> abstractViewMock;
QmlDesigner::NodeListProperty nodeListProperty;
ModelNode node1;
diff --git a/tests/unit/unittest/projectstorage-test.cpp b/tests/unit/unittest/projectstorage-test.cpp
index 07745826912..7ff1df47c9e 100644
--- a/tests/unit/unittest/projectstorage-test.cpp
+++ b/tests/unit/unittest/projectstorage-test.cpp
@@ -122,12 +122,12 @@ MATCHER_P3(IsExportedType,
minorVersion,
std::string(negation ? "isn't " : "is ")
+ PrintToString(Storage::Synchronization::ExportedType{
- name, Storage::Synchronization::Version{majorVersion, minorVersion}}))
+ name, Storage::Version{majorVersion, minorVersion}}))
{
const Storage::Synchronization::ExportedType &type = arg;
return type.name == name
- && type.version == Storage::Synchronization::Version{majorVersion, minorVersion};
+ && type.version == Storage::Version{majorVersion, minorVersion};
}
MATCHER_P4(IsExportedType,
@@ -137,12 +137,12 @@ MATCHER_P4(IsExportedType,
minorVersion,
std::string(negation ? "isn't " : "is ")
+ PrintToString(Storage::Synchronization::ExportedType{
- moduleId, name, Storage::Synchronization::Version{majorVersion, minorVersion}}))
+ moduleId, name, Storage::Version{majorVersion, minorVersion}}))
{
const Storage::Synchronization::ExportedType &type = arg;
return type.moduleId == moduleId && type.name == name
- && type.version == Storage::Synchronization::Version{majorVersion, minorVersion};
+ && type.version == Storage::Version{majorVersion, minorVersion};
}
MATCHER_P3(
@@ -284,33 +284,33 @@ protected:
{
SynchronizationPackage package;
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId1);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId1);
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId2);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId1);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId1);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId2);
package.moduleDependencies.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1);
package.moduleDependencies.emplace_back(qtQuickNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1);
package.moduleDependencies.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId2);
package.updatedModuleDependencySourceIds.push_back(sourceId1);
package.updatedModuleDependencySourceIds.push_back(sourceId2);
- importsSourceId1.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId1);
- importsSourceId1.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId1);
+ importsSourceId1.emplace_back(qmlModuleId, Storage::Version{}, sourceId1);
+ importsSourceId1.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId1);
moduleDependenciesSourceId1.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1);
moduleDependenciesSourceId1.emplace_back(qtQuickNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1);
- importsSourceId2.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId2);
+ importsSourceId2.emplace_back(qmlModuleId, Storage::Version{}, sourceId2);
moduleDependenciesSourceId2.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId2);
package.types.push_back(Storage::Synchronization::Type{
@@ -365,10 +365,10 @@ protected:
sourceId2,
{Storage::Synchronization::ExportedType{qmlModuleId,
"Object",
- Storage::Synchronization::Version{2}},
+ Storage::Version{2}},
Storage::Synchronization::ExportedType{qmlModuleId,
"Obj",
- Storage::Synchronization::Version{2}},
+ Storage::Version{2}},
Storage::Synchronization::ExportedType{qmlNativeModuleId, "QObject"}}});
package.updatedSourceIds = {sourceId1, sourceId2};
@@ -380,15 +380,15 @@ protected:
{
SynchronizationPackage package;
- package.imports.emplace_back(QMLModuleId, Storage::Synchronization::Version{}, sourceId1);
+ package.imports.emplace_back(QMLModuleId, Storage::Version{}, sourceId1);
package.moduleDependencies.emplace_back(QMLModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1);
package.updatedModuleDependencySourceIds.push_back(sourceId1);
- importsSourceId1.emplace_back(QMLModuleId, Storage::Synchronization::Version{}, sourceId1);
+ importsSourceId1.emplace_back(QMLModuleId, Storage::Version{}, sourceId1);
moduleDependenciesSourceId1.emplace_back(QMLModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1);
package.types.push_back(
@@ -417,36 +417,36 @@ protected:
{
auto package{createSimpleSynchronizationPackage()};
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId3);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.moduleDependencies.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId3);
package.moduleDependencies.emplace_back(qtQuickNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId3);
package.updatedModuleDependencySourceIds.push_back(sourceId3);
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId4);
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId4);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId4);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId4);
package.moduleDependencies.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId4);
package.updatedModuleDependencySourceIds.push_back(sourceId4);
- importsSourceId3.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId3);
- importsSourceId3.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ importsSourceId3.emplace_back(qmlModuleId, Storage::Version{}, sourceId3);
+ importsSourceId3.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
moduleDependenciesSourceId3.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId3);
moduleDependenciesSourceId3.emplace_back(qtQuickNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId3);
- importsSourceId4.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId4);
- importsSourceId4.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId4);
+ importsSourceId4.emplace_back(qmlModuleId, Storage::Version{}, sourceId4);
+ importsSourceId4.emplace_back(pathToModuleId, Storage::Version{}, sourceId4);
moduleDependenciesSourceId4.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId4);
package.types[1].propertyDeclarations.push_back(
@@ -498,35 +498,35 @@ protected:
{
SynchronizationPackage package;
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId1);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId1);
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId2);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId1);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId1);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId2);
package.moduleDependencies.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1);
package.moduleDependencies.emplace_back(qtQuickNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1);
package.moduleDependencies.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId2);
package.updatedModuleDependencySourceIds.push_back(sourceId1);
package.updatedModuleDependencySourceIds.push_back(sourceId2);
- importsSourceId1.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId1);
- importsSourceId1.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId1);
+ importsSourceId1.emplace_back(qmlModuleId, Storage::Version{}, sourceId1);
+ importsSourceId1.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId1);
moduleDependenciesSourceId1.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1);
moduleDependenciesSourceId1.emplace_back(qtQuickNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1);
- importsSourceId2.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId2);
+ importsSourceId2.emplace_back(qmlModuleId, Storage::Version{}, sourceId2);
moduleDependenciesSourceId2.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId2);
package.types.push_back(Storage::Synchronization::Type{
@@ -554,52 +554,52 @@ protected:
sourceId2,
{Storage::Synchronization::ExportedType{qmlModuleId,
"Object",
- Storage::Synchronization::Version{2}},
+ Storage::Version{2}},
Storage::Synchronization::ExportedType{qmlModuleId,
"Obj",
- Storage::Synchronization::Version{2}},
+ Storage::Version{2}},
Storage::Synchronization::ExportedType{qmlNativeModuleId, "QObject"}}});
package.updatedSourceIds = {sourceId1, sourceId2};
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId3);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.moduleDependencies.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId3);
package.moduleDependencies.emplace_back(qtQuickNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId3);
package.updatedModuleDependencySourceIds.push_back(sourceId3);
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId4);
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId4);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId4);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId4);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId4);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId4);
package.moduleDependencies.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId4);
package.moduleDependencies.emplace_back(qtQuickNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId4);
package.updatedModuleDependencySourceIds.push_back(sourceId4);
- importsSourceId3.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId3);
- importsSourceId3.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ importsSourceId3.emplace_back(qmlModuleId, Storage::Version{}, sourceId3);
+ importsSourceId3.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
moduleDependenciesSourceId3.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId3);
moduleDependenciesSourceId3.emplace_back(qtQuickNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId3);
- importsSourceId4.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId4);
- importsSourceId4.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId4);
- importsSourceId4.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId4);
+ importsSourceId4.emplace_back(qmlModuleId, Storage::Version{}, sourceId4);
+ importsSourceId4.emplace_back(pathToModuleId, Storage::Version{}, sourceId4);
+ importsSourceId4.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId4);
moduleDependenciesSourceId4.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId4);
moduleDependenciesSourceId4.emplace_back(qtQuickNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId4);
package.types[1].propertyDeclarations.push_back(
@@ -646,7 +646,7 @@ protected:
sourceId5,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Children",
- Storage::Synchronization::Version{2}},
+ Storage::Version{2}},
Storage::Synchronization::ExportedType{qtQuickNativeModuleId, "QChildren"}},
{Storage::Synchronization::PropertyDeclaration{"items",
Storage::Synchronization::ImportedType{
@@ -658,21 +658,21 @@ protected:
Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly}}});
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId5);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId5);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId5);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId5);
package.moduleDependencies.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId5);
package.moduleDependencies.emplace_back(qtQuickNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId5);
- importsSourceId5.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId5);
- importsSourceId5.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId5);
+ importsSourceId5.emplace_back(qmlModuleId, Storage::Version{}, sourceId5);
+ importsSourceId5.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId5);
moduleDependenciesSourceId5.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId5);
moduleDependenciesSourceId5.emplace_back(qtQuickNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId5);
package.updatedModuleDependencySourceIds.push_back(sourceId5);
package.updatedSourceIds.push_back(sourceId5);
@@ -685,7 +685,7 @@ protected:
sourceId6,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Children2",
- Storage::Synchronization::Version{2}},
+ Storage::Version{2}},
Storage::Synchronization::ExportedType{qtQuickNativeModuleId, "QChildren2"}},
{Storage::Synchronization::PropertyDeclaration{"items",
Storage::Synchronization::ImportedType{
@@ -697,14 +697,14 @@ protected:
Storage::PropertyDeclarationTraits::IsList
| Storage::PropertyDeclarationTraits::IsReadOnly}}});
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId6);
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId6);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId6);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId6);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId6);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId6);
package.moduleDependencies.emplace_back(qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId6);
package.moduleDependencies.emplace_back(qtQuickNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId6);
package.updatedModuleDependencySourceIds.push_back(sourceId6);
package.updatedSourceIds.push_back(sourceId6);
@@ -727,8 +727,8 @@ protected:
{
auto package{createSynchronizationPackageWithAliases()};
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId5);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId5);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId5);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId5);
package.types.push_back(Storage::Synchronization::Type{
"QAliasItem2",
@@ -769,10 +769,10 @@ protected:
sourceId1,
{Storage::Synchronization::ExportedType{qmlModuleId,
"Object",
- Storage::Synchronization::Version{1}},
+ Storage::Version{1}},
Storage::Synchronization::ExportedType{qmlModuleId,
"Obj",
- Storage::Synchronization::Version{1, 2}},
+ Storage::Version{1, 2}},
Storage::Synchronization::ExportedType{qmlModuleId, "BuiltInObj"},
Storage::Synchronization::ExportedType{qmlNativeModuleId, "QObject"}}});
package.types.push_back(Storage::Synchronization::Type{
@@ -783,10 +783,10 @@ protected:
sourceId1,
{Storage::Synchronization::ExportedType{qmlModuleId,
"Object",
- Storage::Synchronization::Version{2, 0}},
+ Storage::Version{2, 0}},
Storage::Synchronization::ExportedType{qmlModuleId,
"Obj",
- Storage::Synchronization::Version{2, 3}},
+ Storage::Version{2, 3}},
Storage::Synchronization::ExportedType{qmlNativeModuleId, "QObject2"}}});
package.types.push_back(Storage::Synchronization::Type{
"QObject3",
@@ -796,10 +796,10 @@ protected:
sourceId1,
{Storage::Synchronization::ExportedType{qmlModuleId,
"Object",
- Storage::Synchronization::Version{2, 11}},
+ Storage::Version{2, 11}},
Storage::Synchronization::ExportedType{qmlModuleId,
"Obj",
- Storage::Synchronization::Version{2, 11}},
+ Storage::Version{2, 11}},
Storage::Synchronization::ExportedType{qmlNativeModuleId, "QObject3"}}});
package.types.push_back(Storage::Synchronization::Type{
"QObject4",
@@ -809,13 +809,13 @@ protected:
sourceId1,
{Storage::Synchronization::ExportedType{qmlModuleId,
"Object",
- Storage::Synchronization::Version{3, 4}},
+ Storage::Version{3, 4}},
Storage::Synchronization::ExportedType{qmlModuleId,
"Obj",
- Storage::Synchronization::Version{3, 4}},
+ Storage::Version{3, 4}},
Storage::Synchronization::ExportedType{qmlModuleId,
"BuiltInObj",
- Storage::Synchronization::Version{3, 4}},
+ Storage::Version{3, 4}},
Storage::Synchronization::ExportedType{qmlNativeModuleId, "QObject4"}}});
package.updatedSourceIds.push_back(sourceId1);
@@ -829,7 +829,7 @@ protected:
{
SynchronizationPackage package;
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId1);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{}, sourceId1);
package.types.push_back(Storage::Synchronization::Type{
"QObject",
@@ -839,7 +839,7 @@ protected:
sourceId1,
{Storage::Synchronization::ExportedType{qmlModuleId,
"Object",
- Storage::Synchronization::Version{}}},
+ Storage::Version{}}},
{Storage::Synchronization::PropertyDeclaration{"data",
Storage::Synchronization::ImportedType{"Object"},
Storage::PropertyDeclarationTraits::IsList},
@@ -858,7 +858,7 @@ protected:
sourceId1,
{Storage::Synchronization::ExportedType{qmlModuleId,
"Object2",
- Storage::Synchronization::Version{}}},
+ Storage::Version{}}},
{Storage::Synchronization::PropertyDeclaration{
"data2",
Storage::Synchronization::ImportedType{"Object3"},
@@ -878,7 +878,7 @@ protected:
sourceId1,
{Storage::Synchronization::ExportedType{qmlModuleId,
"Object3",
- Storage::Synchronization::Version{}}},
+ Storage::Version{}}},
{Storage::Synchronization::PropertyDeclaration{"data3",
Storage::Synchronization::ImportedType{
"Object2"},
@@ -902,7 +902,7 @@ protected:
{
SynchronizationPackage package;
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{1}, sourceId1);
+ package.imports.emplace_back(qmlModuleId, Storage::Version{1}, sourceId1);
package.updatedModuleIds.push_back(qtQuickModuleId);
package.types.push_back(Storage::Synchronization::Type{
"QQuickItem",
@@ -912,12 +912,12 @@ protected:
sourceId1,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{1, 0}}}});
+ Storage::Version{1, 0}}}});
package.updatedModuleIds.push_back(qmlModuleId);
package.moduleExportedImports.emplace_back(qtQuickModuleId,
qmlModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
Storage::Synchronization::IsAutoVersion::Yes);
package.types.push_back(Storage::Synchronization::Type{
"QObject",
@@ -927,12 +927,12 @@ protected:
sourceId2,
{Storage::Synchronization::ExportedType{qmlModuleId,
"Object",
- Storage::Synchronization::Version{1, 0}}}});
+ Storage::Version{1, 0}}}});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{1}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{1}, sourceId3);
package.moduleExportedImports.emplace_back(qtQuick3DModuleId,
qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
Storage::Synchronization::IsAutoVersion::Yes);
package.updatedModuleIds.push_back(qtQuick3DModuleId);
package.types.push_back(Storage::Synchronization::Type{
@@ -943,9 +943,9 @@ protected:
sourceId3,
{Storage::Synchronization::ExportedType{qtQuick3DModuleId,
"Item3D",
- Storage::Synchronization::Version{1, 0}}}});
+ Storage::Version{1, 0}}}});
- package.imports.emplace_back(qtQuick3DModuleId, Storage::Synchronization::Version{1}, sourceId4);
+ package.imports.emplace_back(qtQuick3DModuleId, Storage::Version{1}, sourceId4);
package.types.push_back(Storage::Synchronization::Type{
"MyItem",
Storage::Synchronization::ImportedType{"Object"},
@@ -954,7 +954,7 @@ protected:
sourceId4,
{Storage::Synchronization::ExportedType{myModuleModuleId,
"MyItem",
- Storage::Synchronization::Version{1, 0}}}});
+ Storage::Version{1, 0}}}});
package.updatedSourceIds = {sourceId1, sourceId2, sourceId3, sourceId4};
@@ -1439,12 +1439,12 @@ TEST_F(ProjectStorage, SynchronizeTypesOverwritesSources)
package.types[0].sourceId = sourceId3;
package.types[1].sourceId = sourceId4;
Storage::Synchronization::Imports newImports;
- newImports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId3);
- newImports.emplace_back(qmlNativeModuleId, Storage::Synchronization::Version{}, sourceId3);
- newImports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
- newImports.emplace_back(qtQuickNativeModuleId, Storage::Synchronization::Version{}, sourceId3);
- newImports.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId4);
- newImports.emplace_back(qmlNativeModuleId, Storage::Synchronization::Version{}, sourceId4);
+ newImports.emplace_back(qmlModuleId, Storage::Version{}, sourceId3);
+ newImports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId3);
+ newImports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
+ newImports.emplace_back(qtQuickNativeModuleId, Storage::Version{}, sourceId3);
+ newImports.emplace_back(qmlModuleId, Storage::Version{}, sourceId4);
+ newImports.emplace_back(qmlNativeModuleId, Storage::Version{}, sourceId4);
storage.synchronize(SynchronizationPackage{newImports,
package.types,
@@ -1560,7 +1560,7 @@ TEST_F(ProjectStorage, SynchronizeTypesAddQualifiedPrototype)
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1}};
package.types.push_back(Storage::Synchronization::Type{
"QQuickObject",
@@ -1606,7 +1606,7 @@ TEST_F(ProjectStorage, SynchronizeTypesAddQualifiedExtension)
package.types[0].extension = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1}};
package.types.push_back(Storage::Synchronization::Type{
"QQuickObject",
@@ -1828,7 +1828,7 @@ TEST_F(ProjectStorage, SynchronizeTypesAddPropertyDeclarationQualifiedType)
package.types[0].propertyDeclarations[0].typeName = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1}};
package.types.push_back(
Storage::Synchronization::Type{"QQuickObject",
@@ -2018,7 +2018,7 @@ TEST_F(ProjectStorage, UsingNonExistingQualifiedExportedPropertyTypeWithWrongNam
package.types[0].propertyDeclarations[0].typeName = Storage::Synchronization::QualifiedImportedType{
"QObject2",
Storage::Synchronization::Import{qmlNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1}};
package.types.pop_back();
package.imports = importsSourceId1;
@@ -2031,7 +2031,7 @@ TEST_F(ProjectStorage, UsingNonExistingQualifiedExportedPropertyTypeWithWrongMod
auto package{createSimpleSynchronizationPackage()};
package.types[0].propertyDeclarations[0].typeName = Storage::Synchronization::QualifiedImportedType{
"QObject",
- Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}};
+ Storage::Synchronization::Import{qmlModuleId, Storage::Version{}, sourceId1}};
package.types.pop_back();
package.imports = importsSourceId1;
@@ -2900,7 +2900,7 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeAliasDeclarationsTypeName)
storage.synchronize(package);
package.types[2].propertyDeclarations[2].typeName = Storage::Synchronization::ImportedType{
"Obj2"};
- importsSourceId3.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId3);
+ importsSourceId3.emplace_back(pathToModuleId, Storage::Version{}, sourceId3);
storage.synchronize(SynchronizationPackage{importsSourceId3, {package.types[2]}, {sourceId3}});
@@ -3049,7 +3049,7 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeAliasTargetPropertyDeclarationTypeN
storage.synchronize(package);
package.types[1].propertyDeclarations[0].typeName = Storage::Synchronization::ImportedType{
"Item"};
- importsSourceId2.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId2);
+ importsSourceId2.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2);
storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}});
@@ -3117,7 +3117,7 @@ TEST_F(ProjectStorage, SynchronizeTypesRemoveTypeWithAliasTargetPropertyDeclarat
auto package{createSynchronizationPackageWithAliases()};
package.types[2].propertyDeclarations[2].typeName = Storage::Synchronization::ImportedType{
"Object2"};
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId3);
storage.synchronize(package);
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{sourceId4}}),
@@ -3129,7 +3129,7 @@ TEST_F(ProjectStorage, SynchronizeTypesRemoveTypeAndAliasPropertyDeclaration)
auto package{createSynchronizationPackageWithAliases()};
package.types[2].propertyDeclarations[2].typeName = Storage::Synchronization::ImportedType{
"Object2"};
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId3);
storage.synchronize(package);
package.types[2].propertyDeclarations.pop_back();
@@ -3250,8 +3250,8 @@ TEST_F(ProjectStorage, RelinkAliasProperty)
auto package{createSynchronizationPackageWithAliases()};
package.types[1].propertyDeclarations[0].typeName = Storage::Synchronization::ImportedType{
"Object2"};
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId2);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId2);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2);
storage.synchronize(package);
package.types[3].exportedTypes[0].moduleId = qtQuickModuleId;
@@ -3282,11 +3282,11 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForQualifiedImportedTypeName)
auto package{createSynchronizationPackageWithAliases()};
package.types[1].propertyDeclarations[0].typeName = Storage::Synchronization::QualifiedImportedType{
"Object2",
- Storage::Synchronization::Import{pathToModuleId, Storage::Synchronization::Version{}, sourceId2}};
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId2);
+ Storage::Synchronization::Import{pathToModuleId, Storage::Version{}, sourceId2}};
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2);
storage.synchronize(package);
package.types[3].exportedTypes[0].moduleId = qtQuickModuleId;
- importsSourceId4.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId4);
+ importsSourceId4.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId4);
ASSERT_THROW(storage.synchronize(
SynchronizationPackage{importsSourceId4, {package.types[3]}, {sourceId4}}),
@@ -3299,8 +3299,8 @@ TEST_F(ProjectStorage,
auto package{createSynchronizationPackageWithAliases()};
package.types[1].propertyDeclarations[0].typeName = Storage::Synchronization::QualifiedImportedType{
"Object2",
- Storage::Synchronization::Import{pathToModuleId, Storage::Synchronization::Version{}, sourceId2}};
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId2);
+ Storage::Synchronization::Import{pathToModuleId, Storage::Version{}, sourceId2}};
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2);
package.types.push_back(Storage::Synchronization::Type{
"QObject2",
Storage::Synchronization::ImportedType{},
@@ -3366,8 +3366,8 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedType)
auto package{createSynchronizationPackageWithAliases()};
package.types[1].propertyDeclarations[0].typeName = Storage::Synchronization::ImportedType{
"Object2"};
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId2);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId2);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2);
storage.synchronize(package);
package.types[3].exportedTypes[0].moduleId = qtQuickModuleId;
@@ -3386,12 +3386,12 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedTypeAndPropertyType)
auto package{createSynchronizationPackageWithAliases()};
package.types[1].propertyDeclarations[0].typeName = Storage::Synchronization::ImportedType{
"Object2"};
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId2);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId2);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2);
storage.synchronize(package);
package.types[0].prototype = Storage::Synchronization::ImportedType{};
- importsSourceId1.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId1);
- importsSourceId4.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId4);
+ importsSourceId1.emplace_back(pathToModuleId, Storage::Version{}, sourceId1);
+ importsSourceId4.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId4);
package.types[0].propertyDeclarations[0].typeName = Storage::Synchronization::ImportedType{
"Object2"};
package.types[3].propertyDeclarations[0].typeName = Storage::Synchronization::ImportedType{
@@ -3409,12 +3409,12 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyForDeletedTypeAndPropertyTypeName
auto package{createSynchronizationPackageWithAliases()};
package.types[1].propertyDeclarations[0].typeName = Storage::Synchronization::ImportedType{
"Object2"};
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId2);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2);
storage.synchronize(package);
package.types[3].exportedTypes[0].moduleId = qtQuickModuleId;
package.types[1].propertyDeclarations[0].typeName = Storage::Synchronization::ImportedType{
"QObject"};
- importsSourceId4.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId4);
+ importsSourceId4.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId4);
storage.synchronize(SynchronizationPackage{importsSourceId2 + importsSourceId4,
{package.types[1], package.types[3]},
@@ -3432,8 +3432,8 @@ TEST_F(ProjectStorage, DoNotRelinkPropertyTypeDoesNotExists)
auto package{createSynchronizationPackageWithAliases()};
package.types[1].propertyDeclarations[0].typeName = Storage::Synchronization::ImportedType{
"Object2"};
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId2);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId2);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2);
storage.synchronize(package);
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{sourceId4}}),
@@ -3445,7 +3445,7 @@ TEST_F(ProjectStorage, DoNotRelinkAliasPropertyTypeDoesNotExists)
auto package{createSynchronizationPackageWithAliases2()};
package.types[1].propertyDeclarations[0].typeName = Storage::Synchronization::ImportedType{
"Object2"};
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId2);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2);
storage.synchronize(package);
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{sourceId1}}),
@@ -3523,7 +3523,7 @@ TEST_F(ProjectStorage, ChangeQualifiedPrototypeTypeModuleIdThrows)
auto package{createSimpleSynchronizationPackage()};
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{
"Object",
- Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}};
+ Storage::Synchronization::Import{qmlModuleId, Storage::Version{}, sourceId1}};
storage.synchronize(package);
package.types[1].exportedTypes[0].moduleId = qtQuickModuleId;
@@ -3538,7 +3538,7 @@ TEST_F(ProjectStorage, ChangeQualifiedExtensionTypeModuleIdThrows)
std::swap(package.types.front().extension, package.types.front().prototype);
package.types[0].extension = Storage::Synchronization::QualifiedImportedType{
"Object",
- Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}};
+ Storage::Synchronization::Import{qmlModuleId, Storage::Version{}, sourceId1}};
storage.synchronize(package);
package.types[1].exportedTypes[0].moduleId = qtQuickModuleId;
@@ -3552,13 +3552,13 @@ TEST_F(ProjectStorage, ChangeQualifiedPrototypeTypeModuleId)
auto package{createSimpleSynchronizationPackage()};
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{
"Object",
- Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}};
+ Storage::Synchronization::Import{qmlModuleId, Storage::Version{}, sourceId1}};
storage.synchronize(package);
package.types[1].exportedTypes[0].moduleId = qtQuickModuleId;
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1}};
storage.synchronize(SynchronizationPackage{importsSourceId1 + importsSourceId2,
@@ -3579,13 +3579,13 @@ TEST_F(ProjectStorage, ChangeQualifiedExtensionTypeModuleId)
std::swap(package.types.front().extension, package.types.front().prototype);
package.types[0].extension = Storage::Synchronization::QualifiedImportedType{
"Object",
- Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}};
+ Storage::Synchronization::Import{qmlModuleId, Storage::Version{}, sourceId1}};
storage.synchronize(package);
package.types[1].exportedTypes[0].moduleId = qtQuickModuleId;
package.types[0].extension = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1}};
storage.synchronize(SynchronizationPackage{importsSourceId1 + importsSourceId2,
@@ -3688,9 +3688,9 @@ TEST_F(ProjectStorage, ThrowForPrototypeChainCycles)
sourceId3,
{Storage::Synchronization::ExportedType{pathToModuleId, "Object2"},
Storage::Synchronization::ExportedType{pathToModuleId, "Obj2"}}});
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId2);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId3);
ASSERT_THROW(storage.synchronize(SynchronizationPackage{package.imports,
package.types,
@@ -3713,9 +3713,9 @@ TEST_F(ProjectStorage, ThrowForExtensionChainCycles)
sourceId3,
{Storage::Synchronization::ExportedType{pathToModuleId, "Object2"},
Storage::Synchronization::ExportedType{pathToModuleId, "Obj2"}}});
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId2);
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
- package.imports.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId2);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
+ package.imports.emplace_back(pathToModuleId, Storage::Version{}, sourceId3);
ASSERT_THROW(storage.synchronize(SynchronizationPackage{package.imports,
package.types,
@@ -3748,7 +3748,7 @@ TEST_F(ProjectStorage, ThrowForTypeIdAndPrototypeIdAreTheSameForRelinking)
storage.synchronize(package);
package.types[1].prototype = Storage::Synchronization::ImportedType{"Item"};
package.types[1].typeName = "QObject2";
- importsSourceId2.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId2);
+ importsSourceId2.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2);
ASSERT_THROW(storage.synchronize(
SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}),
@@ -3762,7 +3762,7 @@ TEST_F(ProjectStorage, ThrowForTypeIdAndExtenssionIdAreTheSameForRelinking)
storage.synchronize(package);
package.types[1].extension = Storage::Synchronization::ImportedType{"Item"};
package.types[1].typeName = "QObject2";
- importsSourceId2.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId2);
+ importsSourceId2.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2);
ASSERT_THROW(storage.synchronize(
SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}),
@@ -3793,7 +3793,7 @@ TEST_F(ProjectStorage, RecursiveAliasesChangePropertyType)
storage.synchronize(package);
package.types[1].propertyDeclarations[0].typeName = Storage::Synchronization::ImportedType{
"Object2"};
- importsSourceId2.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId2);
+ importsSourceId2.emplace_back(pathToModuleId, Storage::Version{}, sourceId2);
storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}});
@@ -3879,7 +3879,7 @@ TEST_F(ProjectStorage, UpdateAliasesAfterChangePropertyToAlias)
package.types[1].propertyDeclarations.clear();
package.types[1].propertyDeclarations.push_back(Storage::Synchronization::PropertyDeclaration{
"objects", Storage::Synchronization::ImportedType{"Object2"}, "objects"});
- importsSourceId2.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId2);
+ importsSourceId2.emplace_back(pathToModuleId, Storage::Version{}, sourceId2);
storage.synchronize(SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}});
@@ -3903,7 +3903,7 @@ TEST_F(ProjectStorage, CheckForProtoTypeCycleThrows)
package.types[1].propertyDeclarations.clear();
package.types[1].propertyDeclarations.push_back(Storage::Synchronization::PropertyDeclaration{
"objects", Storage::Synchronization::ImportedType{"AliasItem2"}, "objects"});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId2);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2);
ASSERT_THROW(storage.synchronize(package), QmlDesigner::AliasChainCycle);
}
@@ -3915,7 +3915,7 @@ TEST_F(ProjectStorage, CheckForProtoTypeCycleAfterUpdateThrows)
package.types[1].propertyDeclarations.clear();
package.types[1].propertyDeclarations.push_back(Storage::Synchronization::PropertyDeclaration{
"objects", Storage::Synchronization::ImportedType{"AliasItem2"}, "objects"});
- importsSourceId2.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId2);
+ importsSourceId2.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2);
ASSERT_THROW(storage.synchronize(
SynchronizationPackage{importsSourceId2, {package.types[1]}, {sourceId2}}),
@@ -3927,7 +3927,7 @@ TEST_F(ProjectStorage, QualifiedPrototype)
auto package{createSimpleSynchronizationPackage()};
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{
"Object",
- Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}};
+ Storage::Synchronization::Import{qmlModuleId, Storage::Version{}, sourceId1}};
package.types.push_back(
Storage::Synchronization::Type{"QQuickObject",
Storage::Synchronization::ImportedType{},
@@ -3936,7 +3936,7 @@ TEST_F(ProjectStorage, QualifiedPrototype)
sourceId3,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Object"}}});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -3955,7 +3955,7 @@ TEST_F(ProjectStorage, QualifiedExtension)
std::swap(package.types.front().extension, package.types.front().prototype);
package.types[0].extension = Storage::Synchronization::QualifiedImportedType{
"Object",
- Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}};
+ Storage::Synchronization::Import{qmlModuleId, Storage::Version{}, sourceId1}};
package.types.push_back(
Storage::Synchronization::Type{"QQuickObject",
Storage::Synchronization::ImportedType{},
@@ -3964,7 +3964,7 @@ TEST_F(ProjectStorage, QualifiedExtension)
sourceId3,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Object"}}});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -3983,7 +3983,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeUpperDownTheModuleChainThrows)
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1}};
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
@@ -3996,7 +3996,7 @@ TEST_F(ProjectStorage, QualifiedExtensionUpperDownTheModuleChainThrows)
package.types[0].extension = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1}};
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
@@ -4008,7 +4008,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeUpperInTheModuleChain)
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1}};
package.types.push_back(
Storage::Synchronization::Type{"QQuickObject",
@@ -4018,7 +4018,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeUpperInTheModuleChain)
sourceId3,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Object"}}});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -4038,7 +4038,7 @@ TEST_F(ProjectStorage, QualifiedExtensionUpperInTheModuleChain)
package.types[0].extension = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1}};
package.types.push_back(
Storage::Synchronization::Type{"QQuickObject",
@@ -4048,7 +4048,7 @@ TEST_F(ProjectStorage, QualifiedExtensionUpperInTheModuleChain)
sourceId3,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Object"}}});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -4066,7 +4066,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithWrongVersionThrows)
auto package{createSimpleSynchronizationPackage()};
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{
"Object",
- Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{4}, sourceId1}};
+ Storage::Synchronization::Import{qmlModuleId, Storage::Version{4}, sourceId1}};
package.types.push_back(
Storage::Synchronization::Type{"QQuickObject",
Storage::Synchronization::ImportedType{},
@@ -4075,7 +4075,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithWrongVersionThrows)
sourceId3,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Object"}}});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.updatedSourceIds.push_back(sourceId3);
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
@@ -4087,7 +4087,7 @@ TEST_F(ProjectStorage, QualifiedExtensionWithWrongVersionThrows)
std::swap(package.types.front().extension, package.types.front().prototype);
package.types[0].extension = Storage::Synchronization::QualifiedImportedType{
"Object",
- Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{4}, sourceId1}};
+ Storage::Synchronization::Import{qmlModuleId, Storage::Version{4}, sourceId1}};
package.types.push_back(
Storage::Synchronization::Type{"QQuickObject",
Storage::Synchronization::ImportedType{},
@@ -4096,7 +4096,7 @@ TEST_F(ProjectStorage, QualifiedExtensionWithWrongVersionThrows)
sourceId3,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Object"}}});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.updatedSourceIds.push_back(sourceId3);
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
@@ -4105,7 +4105,7 @@ TEST_F(ProjectStorage, QualifiedExtensionWithWrongVersionThrows)
TEST_F(ProjectStorage, QualifiedPrototypeWithVersion)
{
auto package{createSimpleSynchronizationPackage()};
- package.imports[0].version = Storage::Synchronization::Version{2};
+ package.imports[0].version = Storage::Version{2};
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{"Object",
package.imports[0]};
package.types.push_back(
@@ -4116,7 +4116,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersion)
sourceId3,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Object"}}});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -4133,7 +4133,7 @@ TEST_F(ProjectStorage, QualifiedExtensionWithVersion)
{
auto package{createSimpleSynchronizationPackage()};
std::swap(package.types.front().extension, package.types.front().prototype);
- package.imports[0].version = Storage::Synchronization::Version{2};
+ package.imports[0].version = Storage::Version{2};
package.types[0].extension = Storage::Synchronization::QualifiedImportedType{"Object",
package.imports[0]};
package.types.push_back(
@@ -4144,7 +4144,7 @@ TEST_F(ProjectStorage, QualifiedExtensionWithVersion)
sourceId3,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Object"}}});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -4160,10 +4160,10 @@ TEST_F(ProjectStorage, QualifiedExtensionWithVersion)
TEST_F(ProjectStorage, QualifiedPrototypeWithVersionInTheProtoTypeChain)
{
auto package{createSimpleSynchronizationPackage()};
- package.imports[1].version = Storage::Synchronization::Version{2};
+ package.imports[1].version = Storage::Version{2};
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{"Object",
package.imports[1]};
- package.types[0].exportedTypes[0].version = Storage::Synchronization::Version{2};
+ package.types[0].exportedTypes[0].version = Storage::Version{2};
package.types.push_back(Storage::Synchronization::Type{
"QQuickObject",
Storage::Synchronization::ImportedType{},
@@ -4172,8 +4172,8 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersionInTheProtoTypeChain)
sourceId3,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Object",
- Storage::Synchronization::Version{2}}}});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ Storage::Version{2}}}});
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -4190,10 +4190,10 @@ TEST_F(ProjectStorage, QualifiedExtensionWithVersionInTheProtoTypeChain)
{
auto package{createSimpleSynchronizationPackage()};
std::swap(package.types.front().extension, package.types.front().prototype);
- package.imports[1].version = Storage::Synchronization::Version{2};
+ package.imports[1].version = Storage::Version{2};
package.types[0].extension = Storage::Synchronization::QualifiedImportedType{"Object",
package.imports[1]};
- package.types[0].exportedTypes[0].version = Storage::Synchronization::Version{2};
+ package.types[0].exportedTypes[0].version = Storage::Version{2};
package.types.push_back(Storage::Synchronization::Type{
"QQuickObject",
Storage::Synchronization::ImportedType{},
@@ -4202,8 +4202,8 @@ TEST_F(ProjectStorage, QualifiedExtensionWithVersionInTheProtoTypeChain)
sourceId3,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Object",
- Storage::Synchronization::Version{2}}}});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ Storage::Version{2}}}});
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -4222,7 +4222,7 @@ TEST_F(ProjectStorage, QualifiedPrototypeWithVersionDownTheProtoTypeChainThrows)
package.types[0].prototype = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{2},
+ Storage::Version{2},
sourceId1}};
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
@@ -4235,7 +4235,7 @@ TEST_F(ProjectStorage, QualifiedExtensionWithVersionDownTheProtoTypeChainThrows)
package.types[0].extension = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{2},
+ Storage::Version{2},
sourceId1}};
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
@@ -4246,7 +4246,7 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeName)
auto package{createSimpleSynchronizationPackage()};
package.types[0].propertyDeclarations[0].typeName = Storage::Synchronization::QualifiedImportedType{
"Object",
- Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}};
+ Storage::Synchronization::Import{qmlModuleId, Storage::Version{}, sourceId1}};
package.types.push_back(
Storage::Synchronization::Type{"QQuickObject",
Storage::Synchronization::ImportedType{},
@@ -4255,7 +4255,7 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeName)
sourceId3,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Object"}}});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -4274,7 +4274,7 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameDownTheModuleChainThr
package.types[0].propertyDeclarations[0].typeName = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1}};
ASSERT_THROW(storage.synchronize(package), QmlDesigner::TypeNameDoesNotExists);
@@ -4286,7 +4286,7 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameInTheModuleChain)
package.types[0].propertyDeclarations[0].typeName = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1}};
package.types.push_back(
Storage::Synchronization::Type{"QQuickObject",
@@ -4296,7 +4296,7 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameInTheModuleChain)
sourceId3,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Object"}}});
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId3);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId3);
package.updatedSourceIds.push_back(sourceId3);
storage.synchronize(package);
@@ -4314,8 +4314,8 @@ TEST_F(ProjectStorage, QualifiedPropertyDeclarationTypeNameWithVersion)
auto package{createSimpleSynchronizationPackage()};
package.types[0].propertyDeclarations[0].typeName = Storage::Synchronization::QualifiedImportedType{
"Object",
- Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{2}, sourceId1}};
- package.imports.emplace_back(qmlModuleId, Storage::Synchronization::Version{2}, sourceId1);
+ Storage::Synchronization::Import{qmlModuleId, Storage::Version{2}, sourceId1}};
+ package.imports.emplace_back(qmlModuleId, Storage::Version{2}, sourceId1);
storage.synchronize(package);
@@ -4332,7 +4332,7 @@ TEST_F(ProjectStorage, ChangePropertyTypeModuleIdWithQualifiedTypeThrows)
auto package{createSimpleSynchronizationPackage()};
package.types[0].propertyDeclarations[0].typeName = Storage::Synchronization::QualifiedImportedType{
"Object",
- Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}};
+ Storage::Synchronization::Import{qmlModuleId, Storage::Version{}, sourceId1}};
storage.synchronize(package);
package.types[1].exportedTypes[0].moduleId = qtQuickModuleId;
@@ -4346,15 +4346,15 @@ TEST_F(ProjectStorage, ChangePropertyTypeModuleIdWithQualifiedType)
auto package{createSimpleSynchronizationPackage()};
package.types[0].propertyDeclarations[0].typeName = Storage::Synchronization::QualifiedImportedType{
"Object",
- Storage::Synchronization::Import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1}};
+ Storage::Synchronization::Import{qmlModuleId, Storage::Version{}, sourceId1}};
storage.synchronize(package);
package.types[0].propertyDeclarations[0].typeName = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
sourceId1}};
package.types[1].exportedTypes[0].moduleId = qtQuickModuleId;
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{}, sourceId2);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{}, sourceId2);
storage.synchronize(package);
@@ -4475,9 +4475,9 @@ TEST_F(ProjectStorage, FetchByMajorVersionForImportedType)
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{1},
+ Storage::Version{1},
sourceId2};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4492,7 +4492,7 @@ TEST_F(ProjectStorage, FetchByMajorVersionForQualifiedImportedType)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{1},
+ Storage::Version{1},
sourceId2};
Storage::Synchronization::Type type{
"Item",
@@ -4502,7 +4502,7 @@ TEST_F(ProjectStorage, FetchByMajorVersionForQualifiedImportedType)
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4523,9 +4523,9 @@ TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForImportedType)
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{1, 2},
+ Storage::Version{1, 2},
sourceId2};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4540,7 +4540,7 @@ TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForQualifiedImportedTyp
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{1, 2},
+ Storage::Version{1, 2},
sourceId2};
Storage::Synchronization::Type type{
"Item",
@@ -4550,7 +4550,7 @@ TEST_F(ProjectStorage, FetchByMajorVersionAndMinorVersionForQualifiedImportedTyp
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4572,9 +4572,9 @@ TEST_F(ProjectStorage,
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{1, 1},
+ Storage::Version{1, 1},
sourceId2};
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}),
@@ -4587,7 +4587,7 @@ TEST_F(ProjectStorage,
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{1, 1},
+ Storage::Version{1, 1},
sourceId2};
Storage::Synchronization::Type type{
"Item",
@@ -4597,7 +4597,7 @@ TEST_F(ProjectStorage,
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}),
QmlDesigner::TypeNameDoesNotExists);
@@ -4615,9 +4615,9 @@ TEST_F(ProjectStorage, FetchLowMinorVersionForImportedTypeThrows)
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{1, 1},
+ Storage::Version{1, 1},
sourceId2};
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}),
@@ -4629,7 +4629,7 @@ TEST_F(ProjectStorage, FetchLowMinorVersionForQualifiedImportedTypeThrows)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{1, 1},
+ Storage::Version{1, 1},
sourceId2};
Storage::Synchronization::Type type{
"Item",
@@ -4639,7 +4639,7 @@ TEST_F(ProjectStorage, FetchLowMinorVersionForQualifiedImportedTypeThrows)
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}),
QmlDesigner::TypeNameDoesNotExists);
@@ -4657,9 +4657,9 @@ TEST_F(ProjectStorage, FetchHigherMinorVersionForImportedType)
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{1, 3},
+ Storage::Version{1, 3},
sourceId2};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4674,7 +4674,7 @@ TEST_F(ProjectStorage, FetchHigherMinorVersionForQualifiedImportedType)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{1, 3},
+ Storage::Version{1, 3},
sourceId2};
Storage::Synchronization::Type type{
"Item",
@@ -4684,7 +4684,7 @@ TEST_F(ProjectStorage, FetchHigherMinorVersionForQualifiedImportedType)
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4705,9 +4705,9 @@ TEST_F(ProjectStorage, FetchDifferentMajorVersionForImportedTypeThrows)
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{3, 1},
+ Storage::Version{3, 1},
sourceId2};
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}),
@@ -4719,7 +4719,7 @@ TEST_F(ProjectStorage, FetchDifferentMajorVersionForQualifiedImportedTypeThrows)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{3, 1},
+ Storage::Version{3, 1},
sourceId2};
Storage::Synchronization::Type type{
"Item",
@@ -4729,7 +4729,7 @@ TEST_F(ProjectStorage, FetchDifferentMajorVersionForQualifiedImportedTypeThrows)
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
ASSERT_THROW(storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}}),
QmlDesigner::TypeNameDoesNotExists);
@@ -4747,9 +4747,9 @@ TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForImportedType)
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{2, 3},
+ Storage::Version{2, 3},
sourceId2};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4764,7 +4764,7 @@ TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForQualifiedImportedType)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{2, 3},
+ Storage::Version{2, 3},
sourceId2};
Storage::Synchronization::Type type{
"Item",
@@ -4774,7 +4774,7 @@ TEST_F(ProjectStorage, FetchOtherTypeByDifferentVersionForQualifiedImportedType)
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4795,8 +4795,8 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithoutVersionForImportedType
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
- Storage::Synchronization::Import import{qmlModuleId, Storage::Synchronization::Version{}, sourceId2};
+ Storage::Version{}}}};
+ Storage::Synchronization::Import import{qmlModuleId, Storage::Version{}, sourceId2};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4809,7 +4809,7 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithoutVersionForQualifiedImp
{
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- Storage::Synchronization::Import import{qmlModuleId, Storage::Synchronization::Version{}, sourceId2};
+ Storage::Synchronization::Import import{qmlModuleId, Storage::Version{}, sourceId2};
Storage::Synchronization::Type type{
"Item",
Storage::Synchronization::QualifiedImportedType{"Obj", import},
@@ -4818,7 +4818,7 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithoutVersionForQualifiedImp
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4839,9 +4839,9 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithMajorVersionForImportedTy
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{2},
+ Storage::Version{2},
sourceId2};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4856,7 +4856,7 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithMajorVersionForQualifiedI
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{2},
+ Storage::Version{2},
sourceId2};
Storage::Synchronization::Type type{
"Item",
@@ -4866,7 +4866,7 @@ TEST_F(ProjectStorage, FetchHighestVersionForImportWithMajorVersionForQualifiedI
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4887,8 +4887,8 @@ TEST_F(ProjectStorage, FetchExportedTypeWithoutVersionFirstForImportedType)
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
- Storage::Synchronization::Import import{qmlModuleId, Storage::Synchronization::Version{}, sourceId2};
+ Storage::Version{}}}};
+ Storage::Synchronization::Import import{qmlModuleId, Storage::Version{}, sourceId2};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4901,7 +4901,7 @@ TEST_F(ProjectStorage, FetchExportedTypeWithoutVersionFirstForQualifiedImportedT
{
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- Storage::Synchronization::Import import{qmlModuleId, Storage::Synchronization::Version{}, sourceId2};
+ Storage::Synchronization::Import import{qmlModuleId, Storage::Version{}, sourceId2};
Storage::Synchronization::Type type{
"Item",
Storage::Synchronization::QualifiedImportedType{"BuiltInObj", import},
@@ -4910,7 +4910,7 @@ TEST_F(ProjectStorage, FetchExportedTypeWithoutVersionFirstForQualifiedImportedT
sourceId2,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{}}}};
+ Storage::Version{}}}};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId2}});
@@ -4929,12 +4929,12 @@ TEST_F(ProjectStorage, EnsureThatPropertiesForRemovedTypesAreNotAnymoreRelinked)
sourceId1,
{Storage::Synchronization::ExportedType{qmlModuleId,
"Object",
- Storage::Synchronization::Version{}}},
+ Storage::Version{}}},
{Storage::Synchronization::PropertyDeclaration{"data",
Storage::Synchronization::ImportedType{
"Object"},
Storage::PropertyDeclarationTraits::IsList}}};
- Storage::Synchronization::Import import{qmlModuleId, Storage::Synchronization::Version{}, sourceId1};
+ Storage::Synchronization::Import import{qmlModuleId, Storage::Version{}, sourceId1};
storage.synchronize(SynchronizationPackage{{import}, {type}, {sourceId1}});
ASSERT_NO_THROW(storage.synchronize(SynchronizationPackage{{sourceId1}}));
@@ -4969,7 +4969,7 @@ TEST_F(ProjectStorage, MinimalUpdates)
sourceId1,
{Storage::Synchronization::ExportedType{qtQuickModuleId,
"Item",
- Storage::Synchronization::Version{2, 0}},
+ Storage::Version{2, 0}},
Storage::Synchronization::ExportedType{qtQuickNativeModuleId, "QQuickItem"}},
{},
{},
@@ -5190,7 +5190,7 @@ TEST_F(ProjectStorage, ThrowForUpdatingWithInvalidProjectSourceIdInProjectData)
QmlDesigner::ProjectDataHasInvalidProjectSourceId);
}
-TEST_F(ProjectStorage, FetchProjectDatasByModuleIds)
+TEST_F(ProjectStorage, FetchProjectDatasByDirectorySourceIds)
{
Storage::Synchronization::ProjectData projectData1{qmlProjectSourceId,
sourceId1,
@@ -5212,7 +5212,7 @@ TEST_F(ProjectStorage, FetchProjectDatasByModuleIds)
ASSERT_THAT(projectDatas, UnorderedElementsAre(projectData1, projectData2, projectData3));
}
-TEST_F(ProjectStorage, FetchProjectDatasByModuleId)
+TEST_F(ProjectStorage, FetchProjectDatasByDirectorySourceId)
{
Storage::Synchronization::ProjectData projectData1{qmlProjectSourceId,
sourceId1,
@@ -5234,6 +5234,28 @@ TEST_F(ProjectStorage, FetchProjectDatasByModuleId)
ASSERT_THAT(projectData, UnorderedElementsAre(projectData1, projectData2));
}
+TEST_F(ProjectStorage, FetchProjectDataBySourceIds)
+{
+ Storage::Synchronization::ProjectData projectData1{qmlProjectSourceId,
+ sourceId1,
+ qmlModuleId,
+ Storage::Synchronization::FileType::QmlDocument};
+ Storage::Synchronization::ProjectData projectData2{qmlProjectSourceId,
+ sourceId2,
+ qmlModuleId,
+ Storage::Synchronization::FileType::QmlDocument};
+ Storage::Synchronization::ProjectData projectData3{qtQuickProjectSourceId,
+ sourceId3,
+ qtQuickModuleId,
+ Storage::Synchronization::FileType::QmlTypes};
+ storage.synchronize(SynchronizationPackage{{qmlProjectSourceId, qtQuickProjectSourceId},
+ {projectData1, projectData2, projectData3}});
+
+ auto projectData = storage.fetchProjectData({sourceId2});
+
+ ASSERT_THAT(projectData, Eq(projectData2));
+}
+
TEST_F(ProjectStorage, ExcludeExportedTypes)
{
auto package{createSimpleSynchronizationPackage()};
@@ -5297,7 +5319,7 @@ TEST_F(ProjectStorage, ModuleExportedImportWithDifferentVersions)
package.imports.back().version.major.value = 2;
package.types[2].exportedTypes.front().version.major.value = 2;
package.moduleExportedImports.back().isAutoVersion = Storage::Synchronization::IsAutoVersion::No;
- package.moduleExportedImports.back().version = Storage::Synchronization::Version{1};
+ package.moduleExportedImports.back().version = Storage::Version{1};
storage.synchronize(std::move(package));
@@ -5334,7 +5356,7 @@ TEST_F(ProjectStorage, ModuleExportedImportWithIndirectDifferentVersions)
package.types[0].exportedTypes.front().version.major.value = 2;
package.types[2].exportedTypes.front().version.major.value = 2;
package.moduleExportedImports[0].isAutoVersion = Storage::Synchronization::IsAutoVersion::No;
- package.moduleExportedImports[0].version = Storage::Synchronization::Version{1};
+ package.moduleExportedImports[0].version = Storage::Version{1};
storage.synchronize(std::move(package));
@@ -5367,14 +5389,14 @@ TEST_F(ProjectStorage, ModuleExportedImportPreventCollisionIfModuleIsIndirectlyR
{
ModuleId qtQuick4DModuleId{storage.moduleId("QtQuick4D")};
auto package{createModuleExportedImportSynchronizationPackage()};
- package.imports.emplace_back(qtQuickModuleId, Storage::Synchronization::Version{1}, sourceId5);
+ package.imports.emplace_back(qtQuickModuleId, Storage::Version{1}, sourceId5);
package.moduleExportedImports.emplace_back(qtQuick4DModuleId,
qtQuickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
Storage::Synchronization::IsAutoVersion::Yes);
package.moduleExportedImports.emplace_back(qtQuick4DModuleId,
qmlModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
Storage::Synchronization::IsAutoVersion::Yes);
package.updatedModuleIds.push_back(qtQuick4DModuleId);
package.types.push_back(Storage::Synchronization::Type{
@@ -5385,8 +5407,8 @@ TEST_F(ProjectStorage, ModuleExportedImportPreventCollisionIfModuleIsIndirectlyR
sourceId5,
{Storage::Synchronization::ExportedType{qtQuick4DModuleId,
"Item4D",
- Storage::Synchronization::Version{1, 0}}}});
- package.imports.emplace_back(qtQuick4DModuleId, Storage::Synchronization::Version{1}, sourceId4);
+ Storage::Version{1, 0}}}});
+ package.imports.emplace_back(qtQuick4DModuleId, Storage::Version{1}, sourceId4);
storage.synchronize(std::move(package));
@@ -5426,15 +5448,15 @@ TEST_F(ProjectStorage, DistinguishBetweenImportKinds)
ModuleId qml1ModuleId{storage.moduleId("Qml1")};
ModuleId qml11ModuleId{storage.moduleId("Qml11")};
auto package{createSimpleSynchronizationPackage()};
- package.moduleDependencies.emplace_back(qmlModuleId, Storage::Synchronization::Version{}, sourceId1);
+ package.moduleDependencies.emplace_back(qmlModuleId, Storage::Version{}, sourceId1);
package.moduleDependencies.emplace_back(qml1ModuleId,
- Storage::Synchronization::Version{1},
+ Storage::Version{1},
sourceId1);
- package.imports.emplace_back(qml1ModuleId, Storage::Synchronization::Version{}, sourceId1);
+ package.imports.emplace_back(qml1ModuleId, Storage::Version{}, sourceId1);
package.moduleDependencies.emplace_back(qml11ModuleId,
- Storage::Synchronization::Version{1, 1},
+ Storage::Version{1, 1},
sourceId1);
- package.imports.emplace_back(qml11ModuleId, Storage::Synchronization::Version{1, 1}, sourceId1);
+ package.imports.emplace_back(qml11ModuleId, Storage::Version{1, 1}, sourceId1);
storage.synchronize(std::move(package));
@@ -5459,7 +5481,7 @@ TEST_F(ProjectStorage, ModuleExportedImportDistinguishBetweenDependencyAndImport
{
auto package{createModuleExportedImportSynchronizationPackage()};
package.moduleDependencies.emplace_back(qtQuick3DModuleId,
- Storage::Synchronization::Version{1},
+ Storage::Version{1},
sourceId4);
storage.synchronize(std::move(package));
@@ -5495,7 +5517,7 @@ TEST_F(ProjectStorage, ModuleExportedImportWithQualifiedImportedType)
package.types.back().prototype = Storage::Synchronization::QualifiedImportedType{
"Object",
Storage::Synchronization::Import{qtQuick3DModuleId,
- Storage::Synchronization::Version{1},
+ Storage::Version{1},
sourceId4}};
storage.synchronize(std::move(package));
@@ -5637,7 +5659,7 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeIndirectAliasDeclarationTypeName)
storage.synchronize(package);
package.types[2].propertyDeclarations[1].typeName = Storage::Synchronization::ImportedType{
"Obj2"};
- importsSourceId3.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId3);
+ importsSourceId3.emplace_back(pathToModuleId, Storage::Version{}, sourceId3);
storage.synchronize(SynchronizationPackage{
importsSourceId3, {package.types[2]}, {sourceId3}, moduleDependenciesSourceId3, {sourceId3}});
@@ -5663,7 +5685,7 @@ TEST_F(ProjectStorage, SynchronizeTypesChangeIndirectAliasDeclarationTailsTypeNa
storage.synchronize(package);
package.types[4].propertyDeclarations[1].typeName = Storage::Synchronization::ImportedType{
"Obj2"};
- importsSourceId5.emplace_back(pathToModuleId, Storage::Synchronization::Version{}, sourceId5);
+ importsSourceId5.emplace_back(pathToModuleId, Storage::Version{}, sourceId5);
storage.synchronize(SynchronizationPackage{
importsSourceId5, {package.types[4]}, {sourceId5}, moduleDependenciesSourceId5, {sourceId5}});
@@ -5925,7 +5947,7 @@ TEST_F(ProjectStorage, GetTypeId)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(qmlModuleId, "Object", Storage::Synchronization::Version{});
+ auto typeId = storage.typeId(qmlModuleId, "Object", Storage::Version{});
ASSERT_THAT(typeId, fetchTypeId(sourceId1, "QObject4"));
}
@@ -5935,7 +5957,7 @@ TEST_F(ProjectStorage, GetNoTypeIdForNonExistingTypeName)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(qmlModuleId, "Object2", Storage::Synchronization::Version{});
+ auto typeId = storage.typeId(qmlModuleId, "Object2", Storage::Version{});
ASSERT_FALSE(typeId);
}
@@ -5945,7 +5967,7 @@ TEST_F(ProjectStorage, GetNoTypeIdForInvalidModuleId)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(ModuleId{}, "Object", Storage::Synchronization::Version{});
+ auto typeId = storage.typeId(ModuleId{}, "Object", Storage::Version{});
ASSERT_FALSE(typeId);
}
@@ -5955,7 +5977,7 @@ TEST_F(ProjectStorage, GetNoTypeIdForWrongModuleId)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(qtQuick3DModuleId, "Object", Storage::Synchronization::Version{});
+ auto typeId = storage.typeId(qtQuick3DModuleId, "Object", Storage::Version{});
ASSERT_FALSE(typeId);
}
@@ -5965,7 +5987,7 @@ TEST_F(ProjectStorage, GetTypeIdWithMajorVersion)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(qmlModuleId, "Object", Storage::Synchronization::Version{2});
+ auto typeId = storage.typeId(qmlModuleId, "Object", Storage::Version{2});
ASSERT_THAT(typeId, fetchTypeId(sourceId1, "QObject3"));
}
@@ -5975,7 +5997,7 @@ TEST_F(ProjectStorage, GetNoTypeIdWithMajorVersionForNonExistingTypeName)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(qmlModuleId, "Object2", Storage::Synchronization::Version{2});
+ auto typeId = storage.typeId(qmlModuleId, "Object2", Storage::Version{2});
ASSERT_FALSE(typeId);
}
@@ -5985,7 +6007,7 @@ TEST_F(ProjectStorage, GetNoTypeIdWithMajorVersionForInvalidModuleId)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(ModuleId{}, "Object", Storage::Synchronization::Version{2});
+ auto typeId = storage.typeId(ModuleId{}, "Object", Storage::Version{2});
ASSERT_FALSE(typeId);
}
@@ -5995,7 +6017,7 @@ TEST_F(ProjectStorage, GetNoTypeIdWithMajorVersionForWrongModuleId)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(qtQuick3DModuleId, "Object", Storage::Synchronization::Version{2});
+ auto typeId = storage.typeId(qtQuick3DModuleId, "Object", Storage::Version{2});
ASSERT_FALSE(typeId);
}
@@ -6005,7 +6027,7 @@ TEST_F(ProjectStorage, GetNoTypeIdWithMajorVersionForWrongVersion)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(qmlModuleId, "Object", Storage::Synchronization::Version{4});
+ auto typeId = storage.typeId(qmlModuleId, "Object", Storage::Version{4});
ASSERT_FALSE(typeId);
}
@@ -6015,7 +6037,7 @@ TEST_F(ProjectStorage, GetTypeIdWithCompleteVersion)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(qmlModuleId, "Object", Storage::Synchronization::Version{2, 0});
+ auto typeId = storage.typeId(qmlModuleId, "Object", Storage::Version{2, 0});
ASSERT_THAT(typeId, fetchTypeId(sourceId1, "QObject2"));
}
@@ -6025,7 +6047,7 @@ TEST_F(ProjectStorage, GetNoTypeIdWithCompleteVersionWithHigherMinorVersion)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(qmlModuleId, "Object", Storage::Synchronization::Version{2, 12});
+ auto typeId = storage.typeId(qmlModuleId, "Object", Storage::Version{2, 12});
ASSERT_THAT(typeId, fetchTypeId(sourceId1, "QObject3"));
}
@@ -6035,7 +6057,7 @@ TEST_F(ProjectStorage, GetNoTypeIdWithCompleteVersionForNonExistingTypeName)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(qmlModuleId, "Object2", Storage::Synchronization::Version{2, 0});
+ auto typeId = storage.typeId(qmlModuleId, "Object2", Storage::Version{2, 0});
ASSERT_FALSE(typeId);
}
@@ -6045,7 +6067,7 @@ TEST_F(ProjectStorage, GetNoTypeIdWithCompleteVersionForInvalidModuleId)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(ModuleId{}, "Object", Storage::Synchronization::Version{2, 0});
+ auto typeId = storage.typeId(ModuleId{}, "Object", Storage::Version{2, 0});
ASSERT_FALSE(typeId);
}
@@ -6055,7 +6077,7 @@ TEST_F(ProjectStorage, GetNoTypeIdWithCompleteVersionForWrongModuleId)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(qtQuick3DModuleId, "Object", Storage::Synchronization::Version{2, 0});
+ auto typeId = storage.typeId(qtQuick3DModuleId, "Object", Storage::Version{2, 0});
ASSERT_FALSE(typeId);
}
@@ -6065,7 +6087,7 @@ TEST_F(ProjectStorage, GetNoTypeIdWithCompleteVersionForWrongMajorVersion)
auto package{createSynchronizationPackageWithVersions()};
storage.synchronize(package);
- auto typeId = storage.typeId(qmlModuleId, "Object", Storage::Synchronization::Version{4, 0});
+ auto typeId = storage.typeId(qmlModuleId, "Object", Storage::Version{4, 0});
ASSERT_FALSE(typeId);
}
diff --git a/tests/unit/unittest/projectstoragemock.cpp b/tests/unit/unittest/projectstoragemock.cpp
new file mode 100644
index 00000000000..8e4928377f4
--- /dev/null
+++ b/tests/unit/unittest/projectstoragemock.cpp
@@ -0,0 +1,89 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "projectstoragemock.h"
+
+namespace QmlDesigner {
+namespace {
+
+template<typename BasicId>
+void incrementBasicId(BasicId &id)
+{
+ id = BasicId::create(id.internalId() + 1);
+}
+
+ModuleId createModule(ProjectStorageMock &mock, Utils::SmallStringView moduleName)
+{
+ static ModuleId moduleId;
+ incrementBasicId(moduleId);
+
+ ON_CALL(mock, moduleId(Eq(moduleName))).WillByDefault(Return(moduleId));
+
+ return moduleId;
+}
+
+TypeId createType(ProjectStorageMock &mock,
+ ModuleId moduleId,
+ Utils::SmallStringView typeName,
+ Utils::SmallString defaultPropertyName,
+ Storage::TypeTraits typeTraits,
+ TypeId baseTypeId = TypeId{})
+{
+ static TypeId typeId;
+ incrementBasicId(typeId);
+
+ static PropertyDeclarationId defaultPropertyId;
+ incrementBasicId(defaultPropertyId);
+
+ ON_CALL(mock, typeId(Eq(moduleId), Eq(typeName), _)).WillByDefault(Return(typeId));
+ ON_CALL(mock, type(Eq(typeId)))
+ .WillByDefault(Return(Storage::Info::Type{defaultPropertyId, typeTraits}));
+ ON_CALL(mock, propertyName(Eq(defaultPropertyId))).WillByDefault(Return(defaultPropertyName));
+
+ if (baseTypeId)
+ ON_CALL(mock, isBasedOn(Eq(typeId), Eq(baseTypeId))).WillByDefault(Return(true));
+
+ return typeId;
+}
+
+TypeId createObject(ProjectStorageMock &mock,
+ ModuleId moduleId,
+ Utils::SmallStringView typeName,
+ Utils::SmallString defaultPropertyName,
+ TypeId baseTypeId = TypeId{})
+{
+ return createType(
+ mock, moduleId, typeName, defaultPropertyName, Storage::TypeTraits::Reference, baseTypeId);
+}
+void setupIsBasedOn(ProjectStorageMock &mock)
+{
+ auto call = [&](TypeId typeId, auto... ids) -> bool {
+ return (mock.isBasedOn(typeId, ids) || ...);
+ };
+ ON_CALL(mock, isBasedOn(_, _, _)).WillByDefault(call);
+ ON_CALL(mock, isBasedOn(_, _, _, _)).WillByDefault(call);
+ ON_CALL(mock, isBasedOn(_, _, _, _, _)).WillByDefault(call);
+ ON_CALL(mock, isBasedOn(_, _, _, _, _, _)).WillByDefault(call);
+ ON_CALL(mock, isBasedOn(_, _, _, _, _, _, _)).WillByDefault(call);
+ ON_CALL(mock, isBasedOn(_, _, _, _, _, _, _, _)).WillByDefault(call);
+}
+
+} // namespace
+} // namespace QmlDesigner
+
+void ProjectStorageMock::setupQtQtuick()
+{
+ QmlDesigner::setupIsBasedOn(*this);
+
+ auto qmlModuleId = QmlDesigner::createModule(*this, "QML");
+ auto qtQmlModelsModuleId = QmlDesigner::createModule(*this, "QtQml.Models");
+ auto qtQuickModuleId = QmlDesigner::createModule(*this, "QtQuick");
+
+ auto qtObjectId = QmlDesigner::createObject(*this, qmlModuleId, "QtObject", "children");
+
+ QmlDesigner::createObject(*this, qtQmlModelsModuleId, "ListModel", "children", qtObjectId);
+ QmlDesigner::createObject(*this, qtQmlModelsModuleId, "ListElement", "children", qtObjectId);
+
+ auto itemId = QmlDesigner::createObject(*this, qtQuickModuleId, "Item", "data", qtObjectId);
+ QmlDesigner::createObject(*this, qtQuickModuleId, "ListView", "data", itemId);
+}
diff --git a/tests/unit/unittest/projectstoragemock.h b/tests/unit/unittest/projectstoragemock.h
index 6d2caaa811b..cb30521c959 100644
--- a/tests/unit/unittest/projectstoragemock.h
+++ b/tests/unit/unittest/projectstoragemock.h
@@ -1,4 +1,4 @@
-// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#pragma once
@@ -14,12 +14,109 @@
class ProjectStorageMock : public QmlDesigner::ProjectStorageInterface
{
public:
+ void setupQtQtuick();
+
MOCK_METHOD(void,
synchronize,
(QmlDesigner::Storage::Synchronization::SynchronizationPackage package),
(override));
- MOCK_METHOD(QmlDesigner::ModuleId, moduleId, (Utils::SmallStringView), (const, override));
+ MOCK_METHOD(QmlDesigner::ModuleId, moduleId, (::Utils::SmallStringView), (const, override));
+
+ MOCK_METHOD(std::optional<QmlDesigner::Storage::Info::PropertyDeclaration>,
+ propertyDeclaration,
+ (QmlDesigner::PropertyDeclarationId propertyDeclarationId),
+ (const, override));
+
+ MOCK_METHOD(QmlDesigner::TypeId,
+ typeId,
+ (QmlDesigner::ModuleId moduleId,
+ ::Utils::SmallStringView exportedTypeName,
+ QmlDesigner::Storage::Version version),
+ (const, override));
+
+ MOCK_METHOD(QmlDesigner::PropertyDeclarationIds,
+ propertyDeclarationIds,
+ (QmlDesigner::TypeId typeId),
+ (const, override));
+ MOCK_METHOD(QmlDesigner::PropertyDeclarationIds,
+ localPropertyDeclarationIds,
+ (QmlDesigner::TypeId typeId),
+ (const, override));
+ MOCK_METHOD(QmlDesigner::PropertyDeclarationId,
+ propertyDeclarationId,
+ (QmlDesigner::TypeId typeId, ::Utils::SmallStringView propertyName),
+ (const, override));
+ MOCK_METHOD(std::optional<QmlDesigner::Storage::Info::Type>,
+ type,
+ (QmlDesigner::TypeId typeId),
+ (const, override));
+ MOCK_METHOD(std::vector<::Utils::SmallString>,
+ signalDeclarationNames,
+ (QmlDesigner::TypeId typeId),
+ (const, override));
+ MOCK_METHOD(std::vector<::Utils::SmallString>,
+ functionDeclarationNames,
+ (QmlDesigner::TypeId typeId),
+ (const, override));
+ MOCK_METHOD(std::optional<::Utils::SmallString>,
+ propertyName,
+ (QmlDesigner::PropertyDeclarationId propertyDeclarationId),
+ (const, override));
+ MOCK_METHOD(QmlDesigner::TypeIds, prototypeAndSelfIds, (QmlDesigner::TypeId type), (const, override));
+ MOCK_METHOD(QmlDesigner::TypeIds, prototypeIds, (QmlDesigner::TypeId type), (const, override));
+ MOCK_METHOD(bool, isBasedOn, (QmlDesigner::TypeId typeId, QmlDesigner::TypeId), (const, override));
+ MOCK_METHOD(bool,
+ isBasedOn,
+ (QmlDesigner::TypeId typeId, QmlDesigner::TypeId, QmlDesigner::TypeId),
+ (const, override));
+ MOCK_METHOD(bool,
+ isBasedOn,
+ (QmlDesigner::TypeId typeId, QmlDesigner::TypeId, QmlDesigner::TypeId, QmlDesigner::TypeId),
+ (const, override));
+ MOCK_METHOD(bool,
+ isBasedOn,
+ (QmlDesigner::TypeId typeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId),
+ (const, override));
+ MOCK_METHOD(bool,
+ isBasedOn,
+ (QmlDesigner::TypeId typeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId),
+ (const, override));
+ MOCK_METHOD(bool,
+ isBasedOn,
+ (QmlDesigner::TypeId typeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId),
+ (const, override));
+ MOCK_METHOD(bool,
+ isBasedOn,
+ (QmlDesigner::TypeId typeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId,
+ QmlDesigner::TypeId),
+ (const, override));
+
+ MOCK_METHOD(const QmlDesigner::Storage::Info::CommonTypeCache<QmlDesigner::ProjectStorageInterface> &,
+ commonTypeCache,
+ (),
+ (const, override));
MOCK_METHOD(QmlDesigner::FileStatus,
fetchFileStatus,
@@ -31,23 +128,28 @@ public:
(QmlDesigner::SourceId sourceId),
(const, override));
+ MOCK_METHOD(std::optional<QmlDesigner::Storage::Synchronization::ProjectData>,
+ fetchProjectData,
+ (QmlDesigner::SourceId sourceId),
+ (const, override));
+
MOCK_METHOD(QmlDesigner::SourceContextId,
fetchSourceContextId,
- (Utils::SmallStringView SourceContextPath),
+ (::Utils::SmallStringView SourceContextPath),
());
MOCK_METHOD(QmlDesigner::SourceId,
fetchSourceId,
- (QmlDesigner::SourceContextId SourceContextId, Utils::SmallStringView sourceName),
+ (QmlDesigner::SourceContextId SourceContextId, ::Utils::SmallStringView sourceName),
());
MOCK_METHOD(QmlDesigner::SourceContextId,
fetchSourceContextIdUnguarded,
- (Utils::SmallStringView SourceContextPath),
+ (::Utils::SmallStringView SourceContextPath),
());
MOCK_METHOD(QmlDesigner::SourceId,
fetchSourceIdUnguarded,
- (QmlDesigner::SourceContextId SourceContextId, Utils::SmallStringView sourceName),
+ (QmlDesigner::SourceContextId SourceContextId, ::Utils::SmallStringView sourceName),
());
- MOCK_METHOD(Utils::PathString,
+ MOCK_METHOD(::Utils::PathString,
fetchSourceContextPath,
(QmlDesigner::SourceContextId sourceContextId));
MOCK_METHOD(QmlDesigner::Cache::SourceNameAndSourceContextId,
@@ -57,3 +159,8 @@ public:
MOCK_METHOD(std::vector<QmlDesigner::Cache::Source>, fetchAllSources, (), ());
};
+class ProjectStorageMockWithQtQtuick : public ProjectStorageMock
+{
+public:
+ ProjectStorageMockWithQtQtuick() { setupQtQtuick(); }
+};
diff --git a/tests/unit/unittest/projectstoragepathwatchermock.h b/tests/unit/unittest/projectstoragepathwatchermock.h
index 2c47291256a..97ebb65e45e 100644
--- a/tests/unit/unittest/projectstoragepathwatchermock.h
+++ b/tests/unit/unittest/projectstoragepathwatchermock.h
@@ -10,10 +10,15 @@
class ProjectStoragePathWatcherMock : public QmlDesigner::ProjectStoragePathWatcherInterface
{
public:
- MOCK_METHOD(void, updateIdPaths, (const std::vector<QmlDesigner::IdPaths> &idPaths), ());
- MOCK_METHOD(void, removeIds, (const QmlDesigner::ProjectPartIds &ids), ());
+ MOCK_METHOD(void, updateIdPaths, (const std::vector<QmlDesigner::IdPaths> &idPaths), (override));
+ MOCK_METHOD(void,
+ updateContextIdPaths,
+ (const std::vector<QmlDesigner::IdPaths> &idPaths,
+ const QmlDesigner::SourceContextIds &sourceContextIds),
+ (override));
+ MOCK_METHOD(void, removeIds, (const QmlDesigner::ProjectPartIds &ids), (override));
MOCK_METHOD(void,
setNotifier,
(QmlDesigner::ProjectStoragePathWatcherNotifierInterface * notifier),
- ());
+ (override));
};
diff --git a/tests/unit/unittest/projectstorageupdater-test.cpp b/tests/unit/unittest/projectstorageupdater-test.cpp
index da7e2f3adba..f2f52d401f9 100644
--- a/tests/unit/unittest/projectstorageupdater-test.cpp
+++ b/tests/unit/unittest/projectstorageupdater-test.cpp
@@ -31,7 +31,7 @@ using QmlDesigner::Storage::Synchronization::IsAutoVersion;
using QmlDesigner::Storage::Synchronization::ModuleExportedImport;
using QmlDesigner::Storage::Synchronization::ProjectData;
using QmlDesigner::Storage::Synchronization::SynchronizationPackage;
-using QmlDesigner::Storage::Synchronization::Version;
+using QmlDesigner::Storage::Version;
MATCHER_P5(IsStorageType,
typeName,
@@ -71,12 +71,12 @@ MATCHER_P4(IsExportedType,
minorVersion,
std::string(negation ? "isn't " : "is ")
+ PrintToString(Storage::Synchronization::ExportedType{
- moduleId, name, Storage::Synchronization::Version{majorVersion, minorVersion}}))
+ moduleId, name, Storage::Version{majorVersion, minorVersion}}))
{
const Storage::Synchronization::ExportedType &type = arg;
return type.moduleId == moduleId && type.name == name
- && type.version == Storage::Synchronization::Version{majorVersion, minorVersion};
+ && type.version == Storage::Version{majorVersion, minorVersion};
}
MATCHER_P3(IsFileStatus,
@@ -160,7 +160,7 @@ public:
setContent(u"/path/First2.qml", qmlDocument2);
setContent(u"/path/Second.qml", qmlDocument3);
setContent(u"/path/example.qmltypes", qmltypes1);
- setContent(u"/path/types/example2.qmltypes", qmltypes2);
+ setContent(u"/path/example2.qmltypes", qmltypes2);
setContent(u"/path/one/First.qml", qmlDocument1);
setContent(u"/path/one/Second.qml", qmlDocument2);
setContent(u"/path/two/Third.qml", qmlDocument3);
@@ -252,6 +252,10 @@ public:
{
ON_CALL(projectStorageMock, fetchProjectDatas(Eq(directoryPathSourceId)))
.WillByDefault(Return(projectDatas));
+ for (const ProjectData &projectData : projectDatas) {
+ ON_CALL(projectStorageMock, fetchProjectData(Eq(projectData.sourceId)))
+ .WillByDefault(Return(std::optional{projectData}));
+ }
}
void setContent(QStringView path, const QString &content)
@@ -275,15 +279,18 @@ protected:
QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>> sourcePathCache{
storage};
NiceMock<ProjectStoragePathWatcherMock> patchWatcherMock;
+ QmlDesigner::ProjectPartId projectPartId = QmlDesigner::ProjectPartId::create(1);
+ QmlDesigner::ProjectPartId otherProjectPartId = QmlDesigner::ProjectPartId::create(0);
QmlDesigner::ProjectStorageUpdater updater{fileSystemMock,
projectStorageMock,
fileStatusCache,
sourcePathCache,
qmlDocumentParserMock,
qmlTypesParserMock,
- patchWatcherMock};
+ patchWatcherMock,
+ projectPartId};
SourceId qmltypesPathSourceId = sourcePathCache.sourceId("/path/example.qmltypes");
- SourceId qmltypes2PathSourceId = sourcePathCache.sourceId("/path/types/example2.qmltypes");
+ SourceId qmltypes2PathSourceId = sourcePathCache.sourceId("/path/example2.qmltypes");
SourceId qmlDirPathSourceId = sourcePathCache.sourceId("/path/qmldir");
SourceId directoryPathSourceId = sourcePathCache.sourceId("/path/.");
SourceId qmlDocumentSourceId1 = sourcePathCache.sourceId("/path/First.qml");
@@ -321,19 +328,19 @@ protected:
Storage::Synchronization::Type secondType;
Storage::Synchronization::Type thirdType;
Storage::Synchronization::Import import1{qmlModuleId,
- Storage::Synchronization::Version{2, 3},
+ Storage::Version{2, 3},
qmlDocumentSourceId1};
Storage::Synchronization::Import import2{qmlModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
qmlDocumentSourceId2};
Storage::Synchronization::Import import3{qmlModuleId,
- Storage::Synchronization::Version{2},
+ Storage::Version{2},
qmlDocumentSourceId3};
Storage::Synchronization::Import import4{qmlModuleId,
- Storage::Synchronization::Version{2, 3},
+ Storage::Version{2, 3},
qmltypesPathSourceId};
Storage::Synchronization::Import import5{qmlModuleId,
- Storage::Synchronization::Version{2, 3},
+ Storage::Version{2, 3},
qmltypes2PathSourceId};
QString qmldirContent{"module Example\ntypeinfo example.qmltypes\n"};
QString qmltypes1{"Module {\ndependencies: [module1]}"};
@@ -341,7 +348,20 @@ protected:
QStringList directories = {"/path"};
QStringList directories2 = {"/path/one", "/path/two"};
QStringList directories3 = {"/path/one", "/path/two", "/path/three"};
- QmlDesigner::ProjectPartId projectPartId = QmlDesigner::ProjectPartId::create(1);
+ QmlDesigner::ProjectChunkId directoryProjectChunkId{projectPartId,
+ QmlDesigner::SourceType::Directory};
+ QmlDesigner::ProjectChunkId qmldirProjectChunkId{projectPartId, QmlDesigner::SourceType::QmlDir};
+ QmlDesigner::ProjectChunkId qmlDocumentProjectChunkId{projectPartId, QmlDesigner::SourceType::Qml};
+ QmlDesigner::ProjectChunkId qmltypesProjectChunkId{projectPartId,
+ QmlDesigner::SourceType::QmlTypes};
+ QmlDesigner::ProjectChunkId otherDirectoryProjectChunkId{otherProjectPartId,
+ QmlDesigner::SourceType::Directory};
+ QmlDesigner::ProjectChunkId otherQmldirProjectChunkId{otherProjectPartId,
+ QmlDesigner::SourceType::QmlDir};
+ QmlDesigner::ProjectChunkId otherQmlDocumentProjectChunkId{otherProjectPartId,
+ QmlDesigner::SourceType::Qml};
+ QmlDesigner::ProjectChunkId otherQmltypesProjectChunkId{otherProjectPartId,
+ QmlDesigner::SourceType::QmlTypes};
SourceId path1SourceId = sourcePathCache.sourceId("/path/one/.");
SourceId path2SourceId = sourcePathCache.sourceId("/path/two/.");
SourceId path3SourceId = sourcePathCache.sourceId("/path/three/.");
@@ -409,12 +429,12 @@ TEST_F(ProjectStorageUpdater, ParseQmlTypes)
{
QString qmldir{R"(module Example
typeinfo example.qmltypes
- typeinfo types/example2.qmltypes)"};
+ typeinfo example2.qmltypes)"};
setContent(u"/path/qmldir", qmldir);
QString qmltypes{"Module {\ndependencies: []}"};
QString qmltypes2{"Module {\ndependencies: [foo]}"};
setContent(u"/path/example.qmltypes", qmltypes);
- setContent(u"/path/types/example2.qmltypes", qmltypes2);
+ setContent(u"/path/example2.qmltypes", qmltypes2);
EXPECT_CALL(qmlTypesParserMock,
parse(qmltypes, _, _, Field(&ProjectData::moduleId, exampleCppNativeModuleId)));
@@ -436,7 +456,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeIsEmptyForNoChange)
TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
{
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{2, 3},
+ Storage::Version{2, 3},
qmltypesPathSourceId};
QString qmltypes{"Module {\ndependencies: []}"};
setQmlFileNames(u"/path", {});
@@ -473,7 +493,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlTypes)
TEST_F(ProjectStorageUpdater, SynchronizeQmlTypesThrowsIfQmltpesDoesNotExists)
{
Storage::Synchronization::Import import{qmlModuleId,
- Storage::Synchronization::Version{2, 3},
+ Storage::Version{2, 3},
qmltypesPathSourceId};
setFilesDontExists({qmltypesPathSourceId});
@@ -974,18 +994,6 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsDontUpdateIfUpToDate)
updater.update(directories, {});
}
-TEST_F(ProjectStorageUpdater, UpdateQmldirDocuments)
-{
- QString qmldir{R"(module Example
- FirstType 1.1 First.qml
- FirstType 2.2 First2.qml
- SecondType 2.2 Second.qml)"};
- setContent(u"/path/qmldir", qmldir);
- setFilesDontChanged({qmlDocumentSourceId3});
-
- updater.pathsWithIdsChanged({});
-}
-
TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChanged)
{
setProjectDatas(
@@ -1072,6 +1080,73 @@ TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasNotChangedAndSomeUpdatedF
updater.update(directories, {});
}
+TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileNotChangedAndSomeRemovedFiles)
+{
+ setQmlFileNames(u"/path", {"First2.qml"});
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmlDocumentSourceId1, exampleModuleId, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, exampleModuleId, FileType::QmlDocument}});
+ setFilesDontChanged({qmlDirPathSourceId, qmltypes2PathSourceId, qmlDocumentSourceId2});
+ setFilesRemoved({qmltypesPathSourceId, qmlDocumentSourceId1});
+
+ ASSERT_THROW(updater.update(directories, {}), QmlDesigner::CannotParseQmlTypesFile);
+}
+
+TEST_F(ProjectStorageUpdater, SynchronizIfQmldirFileHasChangedAndSomeRemovedFiles)
+{
+ QString qmldir{R"(module Example
+ FirstType 2.2 First2.qml
+ typeinfo example2.qmltypes)"};
+ setContent(u"/path/qmldir", qmldir);
+ setQmlFileNames(u"/path", {"First2.qml"});
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmlDocumentSourceId1, exampleModuleId, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, exampleModuleId, FileType::QmlDocument}});
+ setFilesDontChanged({qmltypes2PathSourceId, qmlDocumentSourceId2});
+ setFilesRemoved({qmltypesPathSourceId, qmlDocumentSourceId1});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, IsEmpty()),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(AllOf(
+ IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Minimal),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(pathModuleId, "First2", -1, -1),
+ IsExportedType(exampleModuleId, "FirstType", 2, 2)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmltypesPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmltypesPathSourceId, qmlDocumentSourceId1)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmltypes2PathSourceId,
+ exampleCppNativeModuleId,
+ FileType::QmlTypes))))));
+
+ updater.update(directories, {});
+}
+
TEST_F(ProjectStorageUpdater, UpdateQmlTypesFilesIsEmpty)
{
EXPECT_CALL(projectStorageMock,
@@ -1111,7 +1186,7 @@ TEST_F(ProjectStorageUpdater, UpdateQmlTypesFiles)
FileType::QmlTypes))),
Field(&SynchronizationPackage::updatedProjectSourceIds, IsEmpty()))));
- updater.update({}, {"/path/example.qmltypes", "/path/types/example2.qmltypes"});
+ updater.update({}, {"/path/example.qmltypes", "/path/example2.qmltypes"});
}
TEST_F(ProjectStorageUpdater, DontUpdateQmlTypesFilesIfUnchanged)
@@ -1135,7 +1210,7 @@ TEST_F(ProjectStorageUpdater, DontUpdateQmlTypesFilesIfUnchanged)
FileType::QmlTypes))),
Field(&SynchronizationPackage::updatedProjectSourceIds, IsEmpty()))));
- updater.update({}, {"/path/example.qmltypes", "/path/types/example2.qmltypes"});
+ updater.update({}, {"/path/example.qmltypes", "/path/example2.qmltypes"});
}
TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithDifferentVersionButSameTypeNameAndFileName)
@@ -1246,7 +1321,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirDependencies)
depends Qml
depends QML
typeinfo example.qmltypes
- typeinfo types/example2.qmltypes
+ typeinfo example2.qmltypes
)"};
setContent(u"/path/qmldir", qmldir);
@@ -1254,16 +1329,16 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirDependencies)
synchronize(
AllOf(Field(&SynchronizationPackage::moduleDependencies,
UnorderedElementsAre(Import{qmlCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
qmltypesPathSourceId},
Import{builtinCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
qmltypesPathSourceId},
Import{qmlCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
qmltypes2PathSourceId},
Import{builtinCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
qmltypes2PathSourceId})),
Field(&SynchronizationPackage::updatedModuleDependencySourceIds,
UnorderedElementsAre(qmltypesPathSourceId, qmltypes2PathSourceId)))));
@@ -1278,7 +1353,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirDependenciesWithDoubleEntries)
depends QML
depends Qml
typeinfo example.qmltypes
- typeinfo types/example2.qmltypes
+ typeinfo example2.qmltypes
)"};
setContent(u"/path/qmldir", qmldir);
@@ -1286,16 +1361,16 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirDependenciesWithDoubleEntries)
synchronize(
AllOf(Field(&SynchronizationPackage::moduleDependencies,
UnorderedElementsAre(Import{qmlCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
qmltypesPathSourceId},
Import{builtinCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
qmltypesPathSourceId},
Import{qmlCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
qmltypes2PathSourceId},
Import{builtinCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
qmltypes2PathSourceId})),
Field(&SynchronizationPackage::updatedModuleDependencySourceIds,
UnorderedElementsAre(qmltypesPathSourceId, qmltypes2PathSourceId)))));
@@ -1310,7 +1385,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirDependenciesWithCollidingImports)
depends QML
import Qml
typeinfo example.qmltypes
- typeinfo types/example2.qmltypes
+ typeinfo example2.qmltypes
)"};
setContent(u"/path/qmldir", qmldir);
@@ -1318,16 +1393,16 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirDependenciesWithCollidingImports)
synchronize(
AllOf(Field(&SynchronizationPackage::moduleDependencies,
UnorderedElementsAre(Import{qmlCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
qmltypesPathSourceId},
Import{builtinCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
qmltypesPathSourceId},
Import{qmlCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
qmltypes2PathSourceId},
Import{builtinCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
qmltypes2PathSourceId})),
Field(&SynchronizationPackage::updatedModuleDependencySourceIds,
UnorderedElementsAre(qmltypesPathSourceId, qmltypes2PathSourceId)))));
@@ -1339,7 +1414,7 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirWithNoDependencies)
{
QString qmldir{R"(module Example
typeinfo example.qmltypes
- typeinfo types/example2.qmltypes
+ typeinfo example2.qmltypes
)"};
setContent(u"/path/qmldir", qmldir);
@@ -1367,27 +1442,27 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirImports)
Field(&SynchronizationPackage::moduleExportedImports,
UnorderedElementsAre(ModuleExportedImport{exampleModuleId,
qmlModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::Yes},
ModuleExportedImport{exampleCppNativeModuleId,
qmlCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::No},
ModuleExportedImport{exampleModuleId,
builtinModuleId,
- Storage::Synchronization::Version{2, 1},
+ Storage::Version{2, 1},
IsAutoVersion::No},
ModuleExportedImport{exampleCppNativeModuleId,
builtinCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::No},
ModuleExportedImport{exampleModuleId,
quickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::No},
ModuleExportedImport{exampleCppNativeModuleId,
quickCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::No})),
Field(&SynchronizationPackage::updatedModuleIds, ElementsAre(exampleModuleId)))));
@@ -1424,27 +1499,27 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirImportsWithDoubleEntries)
Field(&SynchronizationPackage::moduleExportedImports,
UnorderedElementsAre(ModuleExportedImport{exampleModuleId,
qmlModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::Yes},
ModuleExportedImport{exampleCppNativeModuleId,
qmlCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::No},
ModuleExportedImport{exampleModuleId,
builtinModuleId,
- Storage::Synchronization::Version{2, 1},
+ Storage::Version{2, 1},
IsAutoVersion::No},
ModuleExportedImport{exampleCppNativeModuleId,
builtinCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::No},
ModuleExportedImport{exampleModuleId,
quickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::No},
ModuleExportedImport{exampleCppNativeModuleId,
quickCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::No})),
Field(&SynchronizationPackage::updatedModuleIds, ElementsAre(exampleModuleId)))));
@@ -1466,27 +1541,27 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmldirOptionalImports)
Field(&SynchronizationPackage::moduleExportedImports,
UnorderedElementsAre(ModuleExportedImport{exampleModuleId,
qmlModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::Yes},
ModuleExportedImport{exampleCppNativeModuleId,
qmlCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::No},
ModuleExportedImport{exampleModuleId,
builtinModuleId,
- Storage::Synchronization::Version{2, 1},
+ Storage::Version{2, 1},
IsAutoVersion::No},
ModuleExportedImport{exampleCppNativeModuleId,
builtinCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::No},
ModuleExportedImport{exampleModuleId,
quickModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::No},
ModuleExportedImport{exampleCppNativeModuleId,
quickCppNativeModuleId,
- Storage::Synchronization::Version{},
+ Storage::Version{},
IsAutoVersion::No})),
Field(&SynchronizationPackage::updatedModuleIds, ElementsAre(exampleModuleId)))));
@@ -1500,7 +1575,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherDirectories)
QmlDesigner::SourceType::Directory,
{path1SourceId, path2SourceId, path3SourceId}})));
- updater.update(directories3, {}, projectPartId);
+ updater.update(directories3, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherDirectoryDoesNotExists)
@@ -1512,7 +1587,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherDirectoryDoesNotExists)
QmlDesigner::SourceType::Directory,
{path1SourceId, path3SourceId}})));
- updater.update(directories3, {}, projectPartId);
+ updater.update(directories3, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherDirectoryDoesNotChanged)
@@ -1524,7 +1599,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherDirectoryDoesNotChanged)
QmlDesigner::SourceType::Directory,
{path1SourceId, path2SourceId}})));
- updater.update(directories2, {}, projectPartId);
+ updater.update(directories2, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherDirectoryRemoved)
@@ -1535,7 +1610,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherDirectoryRemoved)
updateIdPaths(Contains(
IdPaths{projectPartId, QmlDesigner::SourceType::Directory, {path2SourceId}})));
- updater.update(directories2, {}, projectPartId);
+ updater.update(directories2, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmldirs)
@@ -1545,7 +1620,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmldirs)
QmlDesigner::SourceType::QmlDir,
{qmldir1SourceId, qmldir2SourceId, qmldir3SourceId}})));
- updater.update(directories3, {}, projectPartId);
+ updater.update(directories3, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmldirDoesNotExists)
@@ -1557,7 +1632,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmldirDoesNotExists)
QmlDesigner::SourceType::QmlDir,
{qmldir1SourceId, qmldir3SourceId}})));
- updater.update(directories3, {}, projectPartId);
+ updater.update(directories3, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmldirDoesNotChanged)
@@ -1569,7 +1644,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmldirDoesNotChanged)
QmlDesigner::SourceType::QmlDir,
{qmldir1SourceId, qmldir2SourceId}})));
- updater.update(directories2, {}, projectPartId);
+ updater.update(directories2, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmldirRemoved)
@@ -1580,7 +1655,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmldirRemoved)
updateIdPaths(Contains(
IdPaths{projectPartId, QmlDesigner::SourceType::QmlDir, {qmldir2SourceId}})));
- updater.update(directories2, {}, projectPartId);
+ updater.update(directories2, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmlFiles)
@@ -1597,7 +1672,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmlFiles)
QmlDesigner::SourceType::Qml,
{firstSourceId, secondSourceId, thirdSourceId}})));
- updater.update(directories2, {}, projectPartId);
+ updater.update(directories2, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherOnlyQmlFilesDontChanged)
@@ -1615,7 +1690,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherOnlyQmlFilesDontChanged)
QmlDesigner::SourceType::Qml,
{firstSourceId, secondSourceId, thirdSourceId}})));
- updater.update(directories2, {}, projectPartId);
+ updater.update(directories2, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherOnlyQmlFilesChanged)
@@ -1633,7 +1708,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherOnlyQmlFilesChanged)
QmlDesigner::SourceType::Qml,
{firstSourceId, secondSourceId, thirdSourceId}})));
- updater.update(directories2, {}, projectPartId);
+ updater.update(directories2, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmlFilesAndDirectoriesDontChanged)
@@ -1656,7 +1731,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmlFilesAndDirectoriesDontChanged
QmlDesigner::SourceType::Qml,
{firstSourceId, secondSourceId, thirdSourceId}})));
- updater.update(directories2, {}, projectPartId);
+ updater.update(directories2, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmltypesFilesInQmldir)
@@ -1675,7 +1750,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmltypesFilesInQmldir)
QmlDesigner::SourceType::QmlTypes,
{qmltypes1SourceId, qmltypes2SourceId}})));
- updater.update(directories2, {}, projectPartId);
+ updater.update(directories2, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherOnlyQmltypesFilesInQmldirDontChanged)
@@ -1693,7 +1768,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherOnlyQmltypesFilesInQmldirDontChan
QmlDesigner::SourceType::QmlTypes,
{qmltypes1SourceId, qmltypes2SourceId}})));
- updater.update(directories2, {}, projectPartId);
+ updater.update(directories2, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherOnlyQmltypesFilesChanged)
@@ -1710,7 +1785,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherOnlyQmltypesFilesChanged)
QmlDesigner::SourceType::QmlTypes,
{qmltypes1SourceId, qmltypes2SourceId}})));
- updater.update(directories2, {}, projectPartId);
+ updater.update(directories2, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmltypesFilesAndDirectoriesDontChanged)
@@ -1731,7 +1806,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherQmltypesFilesAndDirectoriesDontCh
QmlDesigner::SourceType::QmlTypes,
{qmltypes1SourceId, qmltypes2SourceId}})));
- updater.update(directories2, {}, projectPartId);
+ updater.update(directories2, {});
}
TEST_F(ProjectStorageUpdater, UpdatePathWatcherBuiltinQmltypesFiles)
@@ -1746,7 +1821,7 @@ TEST_F(ProjectStorageUpdater, UpdatePathWatcherBuiltinQmltypesFiles)
QmlDesigner::SourceType::QmlTypes,
{qmltypes1SourceId, qmltypes2SourceId}})));
- updater.update({}, {builtinQmltyplesPath1, builtinQmltyplesPath2}, projectPartId);
+ updater.update({}, {builtinQmltyplesPath1, builtinQmltyplesPath2});
}
TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithoutQmldir)
@@ -1942,4 +2017,1427 @@ TEST_F(ProjectStorageUpdater, SynchronizeQmlDocumentsWithoutQmldirRemovesQmlDocu
updater.update(directories, {});
}
+TEST_F(ProjectStorageUpdater, WatcherUpdatesDirectories)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesChanged({directoryPathSourceId});
+ setFilesDontChanged({qmlDirPathSourceId});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import2, import3)),
+ Field(
+ &SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2),
+ IsExportedType(pathModuleId, "First2", -1, -1)))),
+ AllOf(IsStorageType("Second.qml",
+ Storage::Synchronization::ImportedType{"Object3"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId3,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2),
+ IsExportedType(pathModuleId, "Second", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1, qmlDocumentSourceId2, qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(directoryPathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21),
+ IsFileStatus(qmlDocumentSourceId3, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId3,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.pathsWithIdsChanged({{directoryProjectChunkId, {directoryPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesRemovedDirectory)
+{
+ setFilesRemoved({directoryPathSourceId,
+ qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId3, ModuleId{}, FileType::QmlDocument}});
+
+ EXPECT_CALL(projectStorageMock,
+ synchronize(AllOf(Field(&SynchronizationPackage::imports, IsEmpty()),
+ Field(&SynchronizationPackage::types, IsEmpty()),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(directoryPathSourceId,
+ qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses, UnorderedElementsAre()),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
+
+ updater.pathsWithIdsChanged({{directoryProjectChunkId, {directoryPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherWatchesDirectoriesAfterDirectoryChanges)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesChanged({directoryPathSourceId});
+ setFilesDontChanged({qmlDirPathSourceId});
+ auto directorySourceContextId = sourcePathCache.sourceContextId(directoryPathSourceId);
+
+ EXPECT_CALL(patchWatcherMock,
+ updateContextIdPaths(
+ UnorderedElementsAre(
+ IdPaths{projectPartId, QmlDesigner::SourceType::Directory, {directoryPathSourceId}},
+ IdPaths{projectPartId, QmlDesigner::SourceType::QmlDir, {qmlDirPathSourceId}},
+ IdPaths{projectPartId,
+ QmlDesigner::SourceType::Qml,
+ {qmlDocumentSourceId1, qmlDocumentSourceId2, qmlDocumentSourceId3}},
+ IdPaths{projectPartId, QmlDesigner::SourceType::QmlTypes, {}}),
+ UnorderedElementsAre(directorySourceContextId)));
+
+ updater.pathsWithIdsChanged({{directoryProjectChunkId, {directoryPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherDontUpdatesDirectoriesForOtherProject)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+
+ EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty()));
+
+ updater.pathsWithIdsChanged({{otherDirectoryProjectChunkId, {directoryPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesDirectoriesAndQmldir)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesChanged({directoryPathSourceId, qmlDirPathSourceId});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import2, import3)),
+ Field(
+ &SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2),
+ IsExportedType(pathModuleId, "First2", -1, -1)))),
+ AllOf(IsStorageType("Second.qml",
+ Storage::Synchronization::ImportedType{"Object3"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId3,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2),
+ IsExportedType(pathModuleId, "Second", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(directoryPathSourceId,
+ qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(directoryPathSourceId, 1, 21),
+ IsFileStatus(qmlDirPathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21),
+ IsFileStatus(qmlDocumentSourceId3, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId3,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.pathsWithIdsChanged({{directoryProjectChunkId, {directoryPathSourceId}},
+ {qmldirProjectChunkId, {qmlDirPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherWatchesDirectoriesAfterQmldirChanges)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+ auto directorySourceContextId = sourcePathCache.sourceContextId(qmlDirPathSourceId);
+
+ EXPECT_CALL(patchWatcherMock,
+ updateContextIdPaths(
+ UnorderedElementsAre(
+ IdPaths{projectPartId, QmlDesigner::SourceType::Directory, {directoryPathSourceId}},
+ IdPaths{projectPartId, QmlDesigner::SourceType::QmlDir, {qmlDirPathSourceId}},
+ IdPaths{projectPartId,
+ QmlDesigner::SourceType::Qml,
+ {qmlDocumentSourceId1, qmlDocumentSourceId2, qmlDocumentSourceId3}},
+ IdPaths{projectPartId, QmlDesigner::SourceType::QmlTypes, {}}),
+ UnorderedElementsAre(directorySourceContextId)));
+
+ updater.pathsWithIdsChanged({{qmldirProjectChunkId, {qmlDirPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherDontUpdatesQmldirForOtherProject)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+
+ EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty()));
+
+ updater.pathsWithIdsChanged({{otherQmldirProjectChunkId, {qmlDirPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesAddOnlyQmlDocumentInDirectory)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesChanged({directoryPathSourceId});
+ setFilesDontChanged({qmlDirPathSourceId, qmlDocumentSourceId1});
+ setFilesAdded({qmlDocumentSourceId2});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument}});
+ setQmlFileNames(u"/path", {"First.qml", "First2.qml"});
+
+ EXPECT_CALL(projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import2)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Minimal),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(
+ IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(
+ IsExportedType(pathModuleId, "First2", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(directoryPathSourceId, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDocumentSourceId2, 1, 21),
+ IsFileStatus(directoryPathSourceId, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.pathsWithIdsChanged({{directoryProjectChunkId, {directoryPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesRemovesQmlDocument)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ )"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesChanged({qmlDirPathSourceId});
+ setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2});
+ setFilesRemoved({qmlDocumentSourceId3});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId3, ModuleId{}, FileType::QmlDocument}});
+ setQmlFileNames(u"/path", {"First.qml", "First2.qml"});
+
+ EXPECT_CALL(projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, IsEmpty()),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Minimal),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(
+ IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Minimal),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(
+ IsExportedType(exampleModuleId, "FirstType", 2, 2),
+ IsExportedType(pathModuleId, "First2", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.pathsWithIdsChanged({{directoryProjectChunkId, {directoryPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesRemovesQmlDocumentInQmldirOnly)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ )"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesChanged({qmlDirPathSourceId});
+ setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}});
+ setQmlFileNames(u"/path", {"First.qml", "First2.qml"});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, IsEmpty()),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Minimal),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Minimal),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(pathModuleId, "First2", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.pathsWithIdsChanged({{qmldirProjectChunkId, {qmlDirPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesDirectoriesAddQmlDocumentToQmldir)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ )"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesChanged({qmlDirPathSourceId});
+ setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}});
+ setQmlFileNames(u"/path", {"First.qml", "First2.qml"});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, IsEmpty()),
+ Field(
+ &SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Minimal),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Minimal),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2),
+ IsExportedType(pathModuleId, "First2", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.pathsWithIdsChanged({{qmldirProjectChunkId, {qmlDirPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesDirectoriesRemoveQmlDocumentFromQmldir)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ )"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesDontChanged({qmlDocumentSourceId1, qmlDocumentSourceId2});
+ setFilesChanged({qmlDirPathSourceId});
+ setProjectDatas(directoryPathSourceId,
+ {{directoryPathSourceId, qmlDocumentSourceId1, ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, ModuleId{}, FileType::QmlDocument}});
+ setQmlFileNames(u"/path", {"First.qml", "First2.qml"});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, IsEmpty()),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Minimal),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Minimal),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(pathModuleId, "First2", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.pathsWithIdsChanged({{qmldirProjectChunkId, {qmlDirPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesDirectoriesDontUpdateQmlDocumentsIfUpToDate)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesDontChanged({qmlDocumentSourceId3});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import2)),
+ Field(
+ &SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2),
+ IsExportedType(pathModuleId, "First2", -1, -1)))),
+ AllOf(IsStorageType("Second.qml",
+ Storage::Synchronization::ImportedType{},
+ TypeTraits::Reference,
+ qmlDocumentSourceId3,
+ Storage::Synchronization::ChangeLevel::Minimal),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2),
+ IsExportedType(pathModuleId, "Second", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId3,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.pathsWithIdsChanged({{directoryProjectChunkId, {directoryPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesQmldirsDontUpdateQmlDocumentsIfUpToDate)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesDontChanged({qmlDocumentSourceId3});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import2)),
+ Field(
+ &SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2),
+ IsExportedType(pathModuleId, "First2", -1, -1)))),
+ AllOf(IsStorageType("Second.qml",
+ Storage::Synchronization::ImportedType{},
+ TypeTraits::Reference,
+ qmlDocumentSourceId3,
+ Storage::Synchronization::ChangeLevel::Minimal),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2),
+ IsExportedType(pathModuleId, "Second", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId3,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.pathsWithIdsChanged({{qmldirProjectChunkId, {qmlDirPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesDirectoryButNotQmldir)
+{
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmlDocumentSourceId1, exampleModuleId, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, exampleModuleId, FileType::QmlDocument}});
+ setFilesDontChanged({qmlDirPathSourceId});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports,
+ UnorderedElementsAre(import1, import2, import4, import5)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ Eq(objectType),
+ Eq(itemType),
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Synchronization::Type::exportedTypes, IsEmpty())),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Synchronization::Type::exportedTypes, IsEmpty())))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmltypesPathSourceId,
+ qmltypes2PathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 1, 21),
+ IsFileStatus(qmltypes2PathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmltypesPathSourceId,
+ qmltypes2PathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
+
+ updater.pathsWithIdsChanged({{directoryProjectChunkId, {directoryPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesQmlDocuments)
+{
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import2)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Synchronization::Type::exportedTypes, IsEmpty())),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Synchronization::Type::exportedTypes, IsEmpty())))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
+
+ updater.pathsWithIdsChanged(
+ {{qmlDocumentProjectChunkId, {qmlDocumentSourceId1, qmlDocumentSourceId2}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesRemovedQmlDocuments)
+{
+ setFilesRemoved({qmlDocumentSourceId2});
+
+ EXPECT_CALL(projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(AllOf(
+ IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Synchronization::Type::exportedTypes, IsEmpty())))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDocumentSourceId1, 1, 21))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
+
+ updater.pathsWithIdsChanged(
+ {{qmlDocumentProjectChunkId, {qmlDocumentSourceId1, qmlDocumentSourceId2}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherDontWatchesDirectoriesAfterQmlDocumentChanges)
+{
+ EXPECT_CALL(patchWatcherMock, updateContextIdPaths(_, _)).Times(0);
+
+ updater.pathsWithIdsChanged({{qmlDocumentProjectChunkId, {qmlDirPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherDontUpdatesQmlDocumentsForOtherProjects)
+{
+ EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty()));
+
+ updater.pathsWithIdsChanged(
+ {{otherQmlDocumentProjectChunkId, {qmlDocumentSourceId1, qmlDocumentSourceId2}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesQmltypes)
+{
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}});
+ setFilesDontChanged(
+ {directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2});
+
+ EXPECT_CALL(projectStorageMock,
+ synchronize(
+ AllOf(Field(&SynchronizationPackage::imports,
+ UnorderedElementsAre(import4, import5)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(Eq(objectType), Eq(itemType))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmltypesPathSourceId, qmltypes2PathSourceId)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmltypesPathSourceId, 1, 21),
+ IsFileStatus(qmltypes2PathSourceId, 1, 21))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmltypesPathSourceId, qmltypes2PathSourceId)),
+ Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
+
+ updater.pathsWithIdsChanged(
+ {{qmltypesProjectChunkId, {qmltypesPathSourceId, qmltypes2PathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesRemovedQmltypesWithoutUpdatedQmldir)
+{
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}});
+ setFilesDontChanged(
+ {directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2});
+ setFilesRemoved({qmltypesPathSourceId});
+
+ EXPECT_CALL(projectStorageMock, synchronize(_)).Times(0);
+
+ updater.pathsWithIdsChanged(
+ {{qmltypesProjectChunkId, {qmltypesPathSourceId, qmltypes2PathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesRemovedQmltypesWithUpdatedQmldir)
+{
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}});
+ setFilesDontChanged(
+ {directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2});
+ setFilesRemoved({qmltypesPathSourceId});
+ updater.pathsWithIdsChanged(
+ {{qmltypesProjectChunkId, {qmltypesPathSourceId, qmltypes2PathSourceId}}});
+ QString qmldir{R"(module Example
+ typeinfo example2.qmltypes)"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesChanged({qmlDirPathSourceId});
+ setQmlFileNames(u"/path", {});
+
+ EXPECT_CALL(projectStorageMock,
+ synchronize(
+ AllOf(Field(&SynchronizationPackage::imports, UnorderedElementsAre(import5)),
+ Field(&SynchronizationPackage::types, UnorderedElementsAre(Eq(itemType))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmltypesPathSourceId,
+ qmltypes2PathSourceId)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21),
+ IsFileStatus(qmltypes2PathSourceId, 1, 21))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmltypesPathSourceId,
+ qmltypes2PathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmltypes2PathSourceId,
+ exampleCppNativeModuleId,
+ FileType::QmlTypes))))));
+
+ updater.pathsWithIdsChanged({{qmldirProjectChunkId, {qmlDirPathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherDontWatchesDirectoriesAfterQmltypesChanges)
+{
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}});
+ setFilesDontChanged(
+ {directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2});
+
+ EXPECT_CALL(patchWatcherMock, updateContextIdPaths(_, _)).Times(0);
+
+ updater.pathsWithIdsChanged(
+ {{qmltypesProjectChunkId, {qmltypesPathSourceId, qmltypes2PathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherDontUpdatesQmltypesForOtherProjects)
+{
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}});
+ setFilesDontChanged(
+ {directoryPathSourceId, qmlDirPathSourceId, qmlDocumentSourceId1, qmlDocumentSourceId2});
+
+ EXPECT_CALL(projectStorageMock, synchronize(PackageIsEmpty()));
+
+ updater.pathsWithIdsChanged(
+ {{otherQmltypesProjectChunkId, {qmltypesPathSourceId, qmltypes2PathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesDirectoriesAndButNotIncludedQmlDocument)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesChanged({directoryPathSourceId});
+ setFilesDontChanged({qmlDirPathSourceId});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import2, import3)),
+ Field(
+ &SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2),
+ IsExportedType(pathModuleId, "First2", -1, -1)))),
+ AllOf(IsStorageType("Second.qml",
+ Storage::Synchronization::ImportedType{"Object3"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId3,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2),
+ IsExportedType(pathModuleId, "Second", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1, qmlDocumentSourceId2, qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(directoryPathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21),
+ IsFileStatus(qmlDocumentSourceId3, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId3,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.pathsWithIdsChanged({{directoryProjectChunkId, {directoryPathSourceId}},
+ {qmlDocumentProjectChunkId,
+ {qmlDocumentSourceId1, qmlDocumentSourceId2, qmlDocumentSourceId3}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesQmldirAndButNotIncludedQmlDocument)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesDontChanged({directoryPathSourceId});
+ setFilesChanged({qmlDirPathSourceId});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import2, import3)),
+ Field(
+ &SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2),
+ IsExportedType(pathModuleId, "First2", -1, -1)))),
+ AllOf(IsStorageType("Second.qml",
+ Storage::Synchronization::ImportedType{"Object3"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId3,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2),
+ IsExportedType(pathModuleId, "Second", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21),
+ IsFileStatus(qmlDocumentSourceId3, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId3,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.pathsWithIdsChanged({{qmldirProjectChunkId, {qmlDirPathSourceId}},
+ {qmlDocumentProjectChunkId,
+ {qmlDocumentSourceId1, qmlDocumentSourceId2, qmlDocumentSourceId3}}});
+}
+
+TEST_F(ProjectStorageUpdater, WatcherUpdatesQmldirAndButNotIncludedQmltypes)
+{
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmlDocumentSourceId1, exampleModuleId, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId2, exampleModuleId, FileType::QmlDocument}});
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml
+ typeinfo example.qmltypes
+ typeinfo example2.qmltypes)"};
+ setContent(u"/path/qmldir", qmldir);
+ setFilesDontChanged({directoryPathSourceId});
+ setFilesChanged({qmlDirPathSourceId,
+ qmltypesPathSourceId,
+ qmltypes2PathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports,
+ UnorderedElementsAre(import1, import2, import3, import4, import5)),
+ Field(
+ &SynchronizationPackage::types,
+ UnorderedElementsAre(
+ Eq(objectType),
+ Eq(itemType),
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 1, 0),
+ IsExportedType(pathModuleId, "First", -1, -1)))),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "FirstType", 2, 2),
+ IsExportedType(pathModuleId, "First2", -1, -1)))),
+ AllOf(IsStorageType("Second.qml",
+ Storage::Synchronization::ImportedType{"Object3"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId3,
+ Storage::Synchronization::ChangeLevel::Full),
+ Field(&Storage::Synchronization::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(exampleModuleId, "SecondType", 2, 2),
+ IsExportedType(pathModuleId, "Second", -1, -1)))))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmltypesPathSourceId,
+ qmltypes2PathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDirPathSourceId,
+ qmltypesPathSourceId,
+ qmltypes2PathSourceId,
+ qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmlDocumentSourceId3)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDirPathSourceId, 1, 21),
+ IsFileStatus(qmltypesPathSourceId, 1, 21),
+ IsFileStatus(qmltypes2PathSourceId, 1, 21),
+ IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21),
+ IsFileStatus(qmlDocumentSourceId3, 1, 21))),
+ Field(&SynchronizationPackage::updatedProjectSourceIds,
+ UnorderedElementsAre(directoryPathSourceId)),
+ Field(&SynchronizationPackage::projectDatas,
+ UnorderedElementsAre(IsProjectData(directoryPathSourceId,
+ qmltypesPathSourceId,
+ exampleCppNativeModuleId,
+ FileType::QmlTypes),
+ IsProjectData(directoryPathSourceId,
+ qmltypes2PathSourceId,
+ exampleCppNativeModuleId,
+ FileType::QmlTypes),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId1,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId2,
+ ModuleId{},
+ FileType::QmlDocument),
+ IsProjectData(directoryPathSourceId,
+ qmlDocumentSourceId3,
+ ModuleId{},
+ FileType::QmlDocument))))));
+
+ updater.pathsWithIdsChanged(
+ {{qmldirProjectChunkId, {qmlDirPathSourceId}},
+ {qmltypesProjectChunkId, {qmltypesPathSourceId, qmltypes2PathSourceId}}});
+}
+
+TEST_F(ProjectStorageUpdater, ErrorsForWatcherUpdatesAreHandled)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+
+ ON_CALL(projectStorageMock, synchronize(_)).WillByDefault(Throw(QmlDesigner::ProjectStorageError{}));
+
+ ASSERT_NO_THROW(updater.pathsWithIdsChanged({{directoryProjectChunkId, {directoryPathSourceId}}}));
+}
+
+TEST_F(ProjectStorageUpdater, InputIsReusedNextCallIfAnErrorHappens)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}});
+ setFilesDontChanged({directoryPathSourceId, qmlDirPathSourceId});
+ ON_CALL(projectStorageMock, synchronize(_)).WillByDefault(Throw(QmlDesigner::ProjectStorageError{}));
+ updater.pathsWithIdsChanged(
+ {{qmltypesProjectChunkId, {qmltypesPathSourceId, qmltypes2PathSourceId}}});
+ ON_CALL(projectStorageMock, synchronize(_)).WillByDefault(Return());
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports,
+ UnorderedElementsAre(import1, import2, import4, import5)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ Eq(objectType),
+ Eq(itemType),
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Synchronization::Type::exportedTypes, IsEmpty())),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Synchronization::Type::exportedTypes, IsEmpty())))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmltypesPathSourceId,
+ qmltypes2PathSourceId)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21),
+ IsFileStatus(qmltypesPathSourceId, 1, 21),
+ IsFileStatus(qmltypes2PathSourceId, 1, 21))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmltypesPathSourceId,
+ qmltypes2PathSourceId)),
+ Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
+
+ updater.pathsWithIdsChanged(
+ {{qmlDocumentProjectChunkId, {qmlDocumentSourceId1, qmlDocumentSourceId2}}});
+}
+
+TEST_F(ProjectStorageUpdater, InputIsReusedNextCallIfAnErrorHappensAndQmltypesDuplicatesAreRemoved)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}});
+ setFilesDontChanged({directoryPathSourceId, qmlDirPathSourceId});
+ ON_CALL(projectStorageMock, synchronize(_)).WillByDefault(Throw(QmlDesigner::ProjectStorageError{}));
+ updater.pathsWithIdsChanged(
+ {{qmltypesProjectChunkId, {qmltypesPathSourceId, qmltypes2PathSourceId}}});
+ ON_CALL(projectStorageMock, synchronize(_)).WillByDefault(Return());
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports,
+ UnorderedElementsAre(import1, import2, import4, import5)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ Eq(objectType),
+ Eq(itemType),
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Synchronization::Type::exportedTypes, IsEmpty())),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Synchronization::Type::exportedTypes, IsEmpty())))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmltypesPathSourceId,
+ qmltypes2PathSourceId)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21),
+ IsFileStatus(qmltypesPathSourceId, 1, 21),
+ IsFileStatus(qmltypes2PathSourceId, 1, 21))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmltypesPathSourceId,
+ qmltypes2PathSourceId)),
+ Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
+
+ updater.pathsWithIdsChanged(
+ {{qmltypesProjectChunkId, {qmltypesPathSourceId, qmltypes2PathSourceId}},
+ {qmlDocumentProjectChunkId, {qmlDocumentSourceId1, qmlDocumentSourceId2}}});
+}
+
+TEST_F(ProjectStorageUpdater, InputIsReusedNextCallIfAnErrorHappensAndQmlDocumentDuplicatesAreRemoved)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmlDocumentSourceId1, QmlDesigner::ModuleId{}, FileType::QmlDocument},
+ {directoryPathSourceId, qmlDocumentSourceId1, QmlDesigner::ModuleId{}, FileType::QmlDocument}});
+ setFilesDontChanged({directoryPathSourceId, qmlDirPathSourceId});
+ ON_CALL(projectStorageMock, synchronize(_)).WillByDefault(Throw(QmlDesigner::ProjectStorageError{}));
+ updater.pathsWithIdsChanged(
+ {{qmlDocumentProjectChunkId, {qmlDocumentSourceId1, qmlDocumentSourceId2}}});
+ ON_CALL(projectStorageMock, synchronize(_)).WillByDefault(Return());
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports,
+ UnorderedElementsAre(import1, import2, import4, import5)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ Eq(objectType),
+ Eq(itemType),
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Synchronization::Type::exportedTypes, IsEmpty())),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Synchronization::Type::exportedTypes, IsEmpty())))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmltypesPathSourceId,
+ qmltypes2PathSourceId)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21),
+ IsFileStatus(qmltypesPathSourceId, 1, 21),
+ IsFileStatus(qmltypes2PathSourceId, 1, 21))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1,
+ qmlDocumentSourceId2,
+ qmltypesPathSourceId,
+ qmltypes2PathSourceId)),
+ Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
+
+ updater.pathsWithIdsChanged(
+ {{qmltypesProjectChunkId, {qmltypesPathSourceId, qmltypes2PathSourceId}},
+ {qmlDocumentProjectChunkId, {qmlDocumentSourceId1, qmlDocumentSourceId2}}});
+}
+
+TEST_F(ProjectStorageUpdater, InputIsClearedAfterSuccessfulUpdate)
+{
+ QString qmldir{R"(module Example
+ FirstType 1.0 First.qml
+ FirstType 2.2 First2.qml
+ SecondType 2.2 Second.qml)"};
+ setContent(u"/path/qmldir", qmldir);
+ setProjectDatas(
+ directoryPathSourceId,
+ {{directoryPathSourceId, qmltypesPathSourceId, exampleModuleId, FileType::QmlTypes},
+ {directoryPathSourceId, qmltypes2PathSourceId, exampleModuleId, FileType::QmlTypes}});
+ setFilesDontChanged({directoryPathSourceId, qmlDirPathSourceId});
+ updater.pathsWithIdsChanged(
+ {{qmltypesProjectChunkId, {qmltypesPathSourceId, qmltypes2PathSourceId}}});
+
+ EXPECT_CALL(
+ projectStorageMock,
+ synchronize(AllOf(
+ Field(&SynchronizationPackage::imports, UnorderedElementsAre(import1, import2)),
+ Field(&SynchronizationPackage::types,
+ UnorderedElementsAre(
+ AllOf(IsStorageType("First.qml",
+ Storage::Synchronization::ImportedType{"Object"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId1,
+ Storage::Synchronization::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Synchronization::Type::exportedTypes, IsEmpty())),
+ AllOf(IsStorageType("First2.qml",
+ Storage::Synchronization::ImportedType{"Object2"},
+ TypeTraits::Reference,
+ qmlDocumentSourceId2,
+ Storage::Synchronization::ChangeLevel::ExcludeExportedTypes),
+ Field(&Storage::Synchronization::Type::exportedTypes, IsEmpty())))),
+ Field(&SynchronizationPackage::updatedSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::fileStatuses,
+ UnorderedElementsAre(IsFileStatus(qmlDocumentSourceId1, 1, 21),
+ IsFileStatus(qmlDocumentSourceId2, 1, 21))),
+ Field(&SynchronizationPackage::updatedFileStatusSourceIds,
+ UnorderedElementsAre(qmlDocumentSourceId1, qmlDocumentSourceId2)),
+ Field(&SynchronizationPackage::projectDatas, IsEmpty()))));
+
+ updater.pathsWithIdsChanged(
+ {{qmlDocumentProjectChunkId, {qmlDocumentSourceId1, qmlDocumentSourceId2}}});
+}
+
} // namespace
diff --git a/tests/unit/unittest/qmldocumentparser-test.cpp b/tests/unit/unittest/qmldocumentparser-test.cpp
index 7ed83ef891e..a9103d06ea4 100644
--- a/tests/unit/unittest/qmldocumentparser-test.cpp
+++ b/tests/unit/unittest/qmldocumentparser-test.cpp
@@ -166,10 +166,11 @@ TEST_F(QmlDocumentParser, QualifiedPrototype)
auto type = parser.parse(text, imports, qmlFileSourceId, directoryPath);
ASSERT_THAT(type,
- HasPrototype(Storage::QualifiedImportedType("Item",
- Storage::Import{exampleModuleId,
- Storage::Version{2, 1},
- qmlFileSourceId})));
+ HasPrototype(
+ Storage::QualifiedImportedType("Item",
+ Storage::Import{exampleModuleId,
+ QmlDesigner::Storage::Version{2, 1},
+ qmlFileSourceId})));
}
TEST_F(QmlDocumentParser, Properties)
@@ -198,7 +199,7 @@ TEST_F(QmlDocumentParser, QualifiedProperties)
"foo",
Storage::QualifiedImportedType("Foo",
Storage::Import{exampleModuleId,
- Storage::Version{2, 1},
+ QmlDesigner::Storage::Version{2, 1},
qmlFileSourceId}),
QmlDesigner::Storage::PropertyDeclarationTraits::None)));
}
@@ -233,7 +234,7 @@ TEST_F(QmlDocumentParser, QualifiedEnumerationInProperties)
"foo",
Storage::QualifiedImportedType("Enumeration.Foo",
Storage::Import{exampleModuleId,
- Storage::Version{2, 1},
+ QmlDesigner::Storage::Version{2, 1},
qmlFileSourceId}),
QmlDesigner::Storage::PropertyDeclarationTraits::None)));
}
@@ -251,12 +252,13 @@ TEST_F(QmlDocumentParser, Imports)
qmlFileSourceId,
directoryPath);
- ASSERT_THAT(imports,
- UnorderedElementsAre(
- Storage::Import{directoryModuleId, Storage::Version{}, qmlFileSourceId},
- Storage::Import{fooDirectoryModuleId, Storage::Version{}, qmlFileSourceId},
- Storage::Import{qmlModuleId, Storage::Version{}, qmlFileSourceId},
- Storage::Import{qtQuickModuleId, Storage::Version{}, qmlFileSourceId}));
+ ASSERT_THAT(
+ imports,
+ UnorderedElementsAre(
+ Storage::Import{directoryModuleId, QmlDesigner::Storage::Version{}, qmlFileSourceId},
+ Storage::Import{fooDirectoryModuleId, QmlDesigner::Storage::Version{}, qmlFileSourceId},
+ Storage::Import{qmlModuleId, QmlDesigner::Storage::Version{}, qmlFileSourceId},
+ Storage::Import{qtQuickModuleId, QmlDesigner::Storage::Version{}, qmlFileSourceId}));
}
TEST_F(QmlDocumentParser, ImportsWithVersion)
@@ -272,12 +274,13 @@ TEST_F(QmlDocumentParser, ImportsWithVersion)
qmlFileSourceId,
directoryPath);
- ASSERT_THAT(imports,
- UnorderedElementsAre(
- Storage::Import{directoryModuleId, Storage::Version{}, qmlFileSourceId},
- Storage::Import{fooDirectoryModuleId, Storage::Version{}, qmlFileSourceId},
- Storage::Import{qmlModuleId, Storage::Version{}, qmlFileSourceId},
- Storage::Import{qtQuickModuleId, Storage::Version{2, 1}, qmlFileSourceId}));
+ ASSERT_THAT(
+ imports,
+ UnorderedElementsAre(
+ Storage::Import{directoryModuleId, QmlDesigner::Storage::Version{}, qmlFileSourceId},
+ Storage::Import{fooDirectoryModuleId, QmlDesigner::Storage::Version{}, qmlFileSourceId},
+ Storage::Import{qmlModuleId, QmlDesigner::Storage::Version{}, qmlFileSourceId},
+ Storage::Import{qtQuickModuleId, QmlDesigner::Storage::Version{2, 1}, qmlFileSourceId}));
}
TEST_F(QmlDocumentParser, ImportsWithExplictDirectory)
@@ -293,11 +296,11 @@ TEST_F(QmlDocumentParser, ImportsWithExplictDirectory)
qmlFileSourceId,
directoryPath);
- ASSERT_THAT(
- imports,
- UnorderedElementsAre(Storage::Import{directoryModuleId, Storage::Version{}, qmlFileSourceId},
- Storage::Import{qmlModuleId, Storage::Version{}, qmlFileSourceId},
- Storage::Import{qtQuickModuleId, Storage::Version{}, qmlFileSourceId}));
+ ASSERT_THAT(imports,
+ UnorderedElementsAre(
+ Storage::Import{directoryModuleId, QmlDesigner::Storage::Version{}, qmlFileSourceId},
+ Storage::Import{qmlModuleId, QmlDesigner::Storage::Version{}, qmlFileSourceId},
+ Storage::Import{qtQuickModuleId, QmlDesigner::Storage::Version{}, qmlFileSourceId}));
}
TEST_F(QmlDocumentParser, Functions)
@@ -373,13 +376,14 @@ TEST_F(QmlDocumentParser, DISABLED_DuplicateImportsAreRemoved)
qmlFileSourceId,
directoryPath);
- ASSERT_THAT(imports,
- UnorderedElementsAre(
- Storage::Import{directoryModuleId, Storage::Version{}, qmlFileSourceId},
- Storage::Import{fooDirectoryModuleId, Storage::Version{}, qmlFileSourceId},
- Storage::Import{qmlModuleId, Storage::Version{1, 0}, qmlFileSourceId},
- Storage::Import{qtQmlModuleId, Storage::Version{6, 0}, qmlFileSourceId},
- Storage::Import{qtQuickModuleId, Storage::Version{}, qmlFileSourceId}));
+ ASSERT_THAT(
+ imports,
+ UnorderedElementsAre(
+ Storage::Import{directoryModuleId, QmlDesigner::Storage::Version{}, qmlFileSourceId},
+ Storage::Import{fooDirectoryModuleId, QmlDesigner::Storage::Version{}, qmlFileSourceId},
+ Storage::Import{qmlModuleId, QmlDesigner::Storage::Version{1, 0}, qmlFileSourceId},
+ Storage::Import{qtQmlModuleId, QmlDesigner::Storage::Version{6, 0}, qmlFileSourceId},
+ Storage::Import{qtQuickModuleId, QmlDesigner::Storage::Version{}, qmlFileSourceId}));
}
TEST_F(QmlDocumentParser, AliasItemProperties)
@@ -510,7 +514,7 @@ TEST_F(QmlDocumentParser, QualifiedListProperty)
"foos",
Storage::QualifiedImportedType{"Foo",
Storage::Import{exampleModuleId,
- Storage::Version{2, 1},
+ QmlDesigner::Storage::Version{2, 1},
qmlFileSourceId}},
QmlDesigner::Storage::PropertyDeclarationTraits::IsList)));
}
diff --git a/tests/unit/unittest/qmlprojectmanager/CMakeLists.txt b/tests/unit/unittest/qmlprojectmanager/CMakeLists.txt
new file mode 100644
index 00000000000..9b5037fc527
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/CMakeLists.txt
@@ -0,0 +1,7 @@
+extend_qtc_test(unittest
+ DEPENDS
+ QmlProjectManagerLib
+ SOURCES
+ converters-test.cpp
+ projectitem-test.cpp
+)
diff --git a/tests/unit/unittest/qmlprojectmanager/converters-test.cpp b/tests/unit/unittest/qmlprojectmanager/converters-test.cpp
new file mode 100644
index 00000000000..efa2b647aeb
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/converters-test.cpp
@@ -0,0 +1,94 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "googletest.h" // IWYU pragma: keep
+
+#include <qmlprojectmanager/buildsystem/projectitem/converters.h>
+
+#include <QJsonDocument>
+
+namespace {
+constexpr QLatin1String localTestDataDir{UNITTEST_DIR "/qmlprojectmanager/data"};
+
+class DataSet : public testing::TestWithParam<QString>
+{
+public:
+ void setDataSource(const QString &dataSetName)
+ {
+ m_dataSetDirectory.setPath(localTestDataDir + "/converter/" + dataSetName);
+
+ m_qmlProjectFile = Utils::FilePath::fromString(
+ QString(m_dataSetDirectory.absolutePath()).append("/testfile.qmlproject"));
+ m_jsonToQmlProjectFile = Utils::FilePath::fromString(
+ QString(m_dataSetDirectory.absolutePath()).append("/testfile.jsontoqml"));
+ m_qmlProjectToJsonFile = Utils::FilePath::fromString(
+ QString(m_dataSetDirectory.absolutePath()).append("/testfile.qmltojson"));
+ }
+
+ QString qmlProjectContent() const
+ {
+ return (m_qmlProjectFile.fileContents()
+ ? QString::fromLatin1(m_qmlProjectFile.fileContents().value())
+ : QString{});
+ }
+ QString jsonToQmlProjectContent() const
+ {
+ return m_jsonToQmlProjectFile.fileContents()
+ ? QString::fromLatin1(m_jsonToQmlProjectFile.fileContents().value())
+ : QString{};
+ }
+ QString qmlProjectToJsonContent() const
+ {
+ return m_qmlProjectToJsonFile.fileContents()
+ ? QString::fromLatin1(m_qmlProjectToJsonFile.fileContents().value())
+ : QString{};
+ }
+
+ QString dataSetPath() const { return m_dataSetDirectory.absolutePath(); }
+ QString dataSetName() const { return m_dataSetDirectory.dirName(); }
+ Utils::FilePath qmlProjectFile() const { return m_qmlProjectFile; }
+ Utils::FilePath jsonToQmlProjectFile() const { return m_jsonToQmlProjectFile; }
+ Utils::FilePath qmlProjectToJsonFile() const { return m_qmlProjectToJsonFile; }
+
+private:
+ QDir m_dataSetDirectory;
+ Utils::FilePath m_qmlProjectFile;
+ Utils::FilePath m_jsonToQmlProjectFile;
+ Utils::FilePath m_qmlProjectToJsonFile;
+};
+
+INSTANTIATE_TEST_SUITE_P(ConverterTests,
+ DataSet,
+ ::testing::Values(QString("test-set-1"), QString("test-set-2")));
+
+TEST_P(DataSet, QmlProjectToJson)
+{
+ // GIVEN
+ setDataSource(GetParam());
+ QString targetContent = qmlProjectToJsonContent().replace("\r\n", "\n");
+ auto qmlFile = qmlProjectFile();
+
+ // WHEN
+ auto jsonObject = QmlProjectManager::Converters::qmlProjectTojson(qmlFile);
+
+ // THEN
+ QString convertedContent{QString::fromLatin1(QJsonDocument(jsonObject).toJson())};
+ ASSERT_THAT(convertedContent, Eq(targetContent));
+}
+
+TEST_P(DataSet, JsonToQmlProject)
+{
+ // GIVEN
+ setDataSource(GetParam());
+ QString targetContent = jsonToQmlProjectContent().replace("\r\n", "\n");
+ auto jsonContent = qmlProjectToJsonContent().toLatin1();
+
+ // WHEN
+ auto jsonObject{QJsonDocument::fromJson(jsonContent).object()};
+
+ // THEN
+ QString convertedContent = QmlProjectManager::Converters::jsonToQmlProject(jsonObject);
+ ASSERT_THAT(convertedContent, Eq(targetContent));
+}
+
+} // namespace
diff --git a/tests/unit/unittest/qmlprojectmanager/data/README.md b/tests/unit/unittest/qmlprojectmanager/data/README.md
new file mode 100644
index 00000000000..0edd94edd93
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/README.md
@@ -0,0 +1,32 @@
+# Test Set Information
+
+This document contains information about the purpose of each test sets.
+
+## Getter/Setter test data
+
+* **testfile-1.qmlproject**: QmlProject file with properly filled out object
+* **testfile-2.qmlproject**: QmlProject file with empty objects
+
+## Converter test data
+
+Test functions iterate over the "test-set-*" folders and run the tests by using the files inside them.
+
+* **testfile.qmlproject**: Original QmlProject file that'll be converted
+* **testfile.qmltojson**: JSON-converted version of the .qmlproject file
+* **testfile.jsontoqml**: QmlProject-converted version of the .qmltojson file
+
+### test-set-1
+
+* **purpose**: testing complex qmlproject file convertion
+* **origin**: custom project
+
+### test-set-2
+
+* **purpose**: testing fileselectors
+* **origin**: file selectors example from playground
+
+## File Filters test data
+
+Test data contains an example project folders that file filters will be initialized and tested.
+
+* **filelist.txt**: List of the files need to be found by the file filters.
diff --git a/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-1/testfile.jsontoqml b/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-1/testfile.jsontoqml
new file mode 100644
index 00000000000..5207599f994
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-1/testfile.jsontoqml
@@ -0,0 +1,98 @@
+\\ prop: json-converted
+\\ prop: auto-generated
+
+import QmlProject
+
+Project {
+ mainFile: "content/App.qml"
+ mainUiFile: "content/Screen01.ui.qml"
+ targetDirectory: "/opt/UntitledProject13"
+ widgetApp: true
+ importPaths: [ "imports","asset_imports" ]
+
+ qdsVersion: "4.0"
+ quickVersion: "6.2"
+ qt6Project: true
+ qtForMCUs: true
+
+ multilanguageSupport: true
+ primaryLanguage: "en"
+ supportedLanguages: [ "en" ]
+
+ Environment {
+ QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT: "1"
+ QT_AUTO_SCREEN_SCALE_FACTOR: "1"
+ QT_ENABLE_HIGHDPI_SCALING: "0"
+ QT_LOGGING_RULES: "qt.qml.connections=false"
+ QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
+ }
+
+ ShaderTool {
+ args: "-s --glsl "100 es,120,150" --hlsl 50 --msl 12"
+ files: [ "content/shaders/*" ]
+ }
+
+ QmlFiles {
+ directory: "content"
+ }
+
+ QmlFiles {
+ directory: "imports"
+ }
+
+ QmlFiles {
+ directory: "asset_imports"
+ }
+
+ JavaScriptFiles {
+ directory: "content"
+ }
+
+ JavaScriptFiles {
+ directory: "imports"
+ }
+
+ ImageFiles {
+ directory: "content"
+ }
+
+ ImageFiles {
+ directory: "asset_imports"
+ }
+
+ Files {
+ directory: "."
+ filters: "*.conf"
+ files: [ "qtquickcontrols2.conf" ]
+ }
+
+ Files {
+ directory: "."
+ filters: "*.ttf;*.otf;*.ctf"
+ }
+
+ Files {
+ directory: "asset_imports"
+ filters: "*.mesh"
+ }
+
+ Files {
+ directory: "."
+ filters: "qmldir"
+ }
+
+ Files {
+ directory: "."
+ filters: "*.glsl;*.glslv;*.glslf;*.vsh;*.fsh;*.vert;*.frag;*.trag"
+ }
+
+ Files {
+ directory: "."
+ filters: "*.mp3;*.wav"
+ }
+
+ Files {
+ directory: "."
+ filters: "*.mp4"
+ }
+}
diff --git a/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-1/testfile.qmlproject b/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-1/testfile.qmlproject
new file mode 100644
index 00000000000..1ff457cdd87
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-1/testfile.qmlproject
@@ -0,0 +1,110 @@
+import QmlProject
+
+Project {
+ mainFile: "content/App.qml"
+ mainUiFile: "content/Screen01.ui.qml"
+
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "content"
+ }
+
+ QmlFiles {
+ directory: "imports"
+ }
+
+ JavaScriptFiles {
+ directory: "content"
+ }
+
+ JavaScriptFiles {
+ directory: "imports"
+ }
+
+ ImageFiles {
+ directory: "content"
+ }
+
+ ImageFiles {
+ directory: "asset_imports"
+ }
+
+ Files {
+ filter: "*.conf"
+ files: ["qtquickcontrols2.conf"]
+ }
+
+ Files {
+ filter: "qmldir"
+ directory: "."
+ }
+
+ Files {
+ filter: "*.ttf;*.otf;*.ctf"
+ }
+
+ Files {
+ filter: "*.wav;*.mp3"
+ }
+
+ Files {
+ filter: "*.mp4"
+ }
+
+ Files {
+ filter: "*.glsl;*.glslv;*.glslf;*.vsh;*.fsh;*.vert;*.frag;*.trag"
+ }
+
+ Files {
+ filter: "*.mesh"
+ directory: "asset_imports"
+ }
+
+ Files {
+ filter: "*.qml"
+ directory: "asset_imports"
+ }
+
+ Environment {
+ QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
+ QT_AUTO_SCREEN_SCALE_FACTOR: "1"
+ QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT: "1"
+ QT_LOGGING_RULES: "qt.qml.connections=false"
+ QT_ENABLE_HIGHDPI_SCALING: "0"
+ /* Useful for debugging
+ QSG_VISUALIZE=batches
+ QSG_VISUALIZE=clip
+ QSG_VISUALIZE=changes
+ QSG_VISUALIZE=overdraw
+ */
+ }
+
+ qt6Project: true
+
+ /* List of plugin directories passed to QML runtime */
+ importPaths: [ "imports", "asset_imports" ]
+
+ /* Required for deployment */
+ targetDirectory: "/opt/UntitledProject13"
+
+ qdsVersion: "4.0"
+
+ quickVersion: "6.2"
+
+ /* If any modules the project imports require widgets (e.g. QtCharts), widgetApp must be true */
+ widgetApp: true
+
+ /* args: Specifies command line arguments for qsb tool to generate shaders.
+ files: Specifies target files for qsb tool. If path is included, it must be relative to this file.
+ Wildcard '*' can be used in the file name part of the path.
+ e.g. files: [ "content/shaders/*.vert", "*.frag" ] */
+ ShaderTool {
+ args: "-s --glsl \"100 es,120,150\" --hlsl 50 --msl 12"
+ files: [ "content/shaders/*" ]
+ }
+
+ multilanguageSupport: true
+ supportedLanguages: ["en"]
+ primaryLanguage: "en"
+
+}
diff --git a/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-1/testfile.qmltojson b/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-1/testfile.qmltojson
new file mode 100644
index 00000000000..9abc7a76c3c
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-1/testfile.qmltojson
@@ -0,0 +1,177 @@
+{
+ "deployment": {
+ "targetDirectory": "/opt/UntitledProject13"
+ },
+ "environment": {
+ "QML_COMPAT_RESOLVE_URLS_ON_ASSIGNMENT": "1",
+ "QT_AUTO_SCREEN_SCALE_FACTOR": "1",
+ "QT_ENABLE_HIGHDPI_SCALING": "0",
+ "QT_LOGGING_RULES": "qt.qml.connections=false",
+ "QT_QUICK_CONTROLS_CONF": "qtquickcontrols2.conf"
+ },
+ "fileGroups": {
+ "config": {
+ "directories": [
+ "."
+ ],
+ "files": [
+ {
+ "name": "qtquickcontrols2.conf"
+ }
+ ],
+ "filters": [
+ "*.conf"
+ ]
+ },
+ "font": {
+ "directories": [
+ "."
+ ],
+ "files": [
+ ],
+ "filters": [
+ "*.ttf",
+ "*.otf",
+ "*.ctf"
+ ]
+ },
+ "image": {
+ "directories": [
+ "content",
+ "asset_imports"
+ ],
+ "files": [
+ ],
+ "filters": [
+ "*.jpeg",
+ "*.jpg",
+ "*.png",
+ "*.svg",
+ "*.hdr",
+ ".ktx"
+ ]
+ },
+ "javaScript": {
+ "directories": [
+ "content",
+ "imports"
+ ],
+ "files": [
+ ],
+ "filters": [
+ "*.js",
+ "*.ts"
+ ]
+ },
+ "meshes": {
+ "directories": [
+ "asset_imports"
+ ],
+ "files": [
+ ],
+ "filters": [
+ "*.mesh"
+ ]
+ },
+ "qml": {
+ "directories": [
+ "content",
+ "imports",
+ "asset_imports"
+ ],
+ "files": [
+ ],
+ "filters": [
+ "*.qml"
+ ]
+ },
+ "qmldir": {
+ "directories": [
+ "."
+ ],
+ "files": [
+ ],
+ "filters": [
+ "qmldir"
+ ]
+ },
+ "shader": {
+ "directories": [
+ "."
+ ],
+ "files": [
+ ],
+ "filters": [
+ "*.glsl",
+ "*.glslv",
+ "*.glslf",
+ "*.vsh",
+ "*.fsh",
+ "*.vert",
+ "*.frag",
+ "*.trag"
+ ]
+ },
+ "sound": {
+ "directories": [
+ "."
+ ],
+ "files": [
+ ],
+ "filters": [
+ "*.mp3",
+ "*.wav"
+ ]
+ },
+ "video": {
+ "directories": [
+ "."
+ ],
+ "files": [
+ ],
+ "filters": [
+ "*.mp4"
+ ]
+ }
+ },
+ "fileVersion": 1,
+ "importPaths": [
+ "imports",
+ "asset_imports"
+ ],
+ "language": {
+ "multiLanguageSupport": true,
+ "primaryLanguage": "en",
+ "supportedLanguages": [
+ "en"
+ ]
+ },
+ "mcuConfig": {
+ },
+ "runConfig": {
+ "fileSelectors": [
+ ],
+ "mainFile": "content/App.qml",
+ "mainUiFile": "content/Screen01.ui.qml",
+ "widgetApp": true
+ },
+ "shaderTool": {
+ "args": [
+ "-s",
+ "--glsl",
+ "\"100 es,120,150\"",
+ "--hlsl",
+ "50",
+ "--msl",
+ "12"
+ ],
+ "files": [
+ "content/shaders/*"
+ ]
+ },
+ "versions": {
+ "designStudio": "4.0",
+ "qt": "6",
+ "qtQuick": "6.2"
+ }
+}
diff --git a/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-2/testfile.jsontoqml b/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-2/testfile.jsontoqml
new file mode 100644
index 00000000000..aaf8d0fdc0a
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-2/testfile.jsontoqml
@@ -0,0 +1,54 @@
+\\ prop: json-converted
+\\ prop: auto-generated
+
+import QmlProject
+
+Project {
+ mainFile: "fileSelectors.qml"
+ mainUiFile: ""
+ targetDirectory: "/opt/fileSelectors"
+ widgetApp: false
+ importPaths: [ "imports" ]
+
+ qdsVersion: ""
+ quickVersion: ""
+ qt6Project: false
+ qtForMCUs: true
+
+ multilanguageSupport: false
+ primaryLanguage: ""
+ supportedLanguages: [ ]
+
+ Environment {
+ QT_AUTO_SCREEN_SCALE_FACTOR: "1"
+ QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
+ }
+
+ ShaderTool {
+ args: ""
+ files: [ ]
+ }
+
+ QmlFiles {
+ directory: "."
+ }
+
+ JavaScriptFiles {
+ directory: "."
+ }
+
+ ImageFiles {
+ directory: "."
+ }
+
+ Files {
+ directory: "."
+ filters: "*.conf"
+ files: [ "qtquickcontrols2.conf" ]
+ }
+
+ Files {
+ directory: "."
+ filters: "qmldir"
+ }
+}
diff --git a/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-2/testfile.qmlproject b/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-2/testfile.qmlproject
new file mode 100644
index 00000000000..409b46bb7ff
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-2/testfile.qmlproject
@@ -0,0 +1,44 @@
+/* File generated by Qt Creator */
+
+import QmlProject 1.1
+
+Project {
+ mainFile: "fileSelectors.qml"
+
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "."
+ }
+
+ JavaScriptFiles {
+ directory: "."
+ }
+
+ ImageFiles {
+ directory: "."
+ }
+
+ Files {
+ filter: "*.conf"
+ files: ["qtquickcontrols2.conf"]
+ }
+
+ Files {
+ filter: "qmldir"
+ directory: "."
+ }
+
+ Environment {
+ QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
+ QT_AUTO_SCREEN_SCALE_FACTOR: "1"
+ }
+
+ /* List of plugin directories passed to QML runtime */
+ importPaths: [ "imports" ]
+
+ //fileSelectors: [ "WXGA", "darkTheme" ]
+ fileSelectors: [ "WXGA", "darkTheme", "ShowIndicator"]
+
+ /* Required for deployment */
+ targetDirectory: "/opt/fileSelectors"
+}
diff --git a/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-2/testfile.qmltojson b/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-2/testfile.qmltojson
new file mode 100644
index 00000000000..5635cf1f638
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/converter/test-set-2/testfile.qmltojson
@@ -0,0 +1,91 @@
+{
+ "deployment": {
+ "targetDirectory": "/opt/fileSelectors"
+ },
+ "environment": {
+ "QT_AUTO_SCREEN_SCALE_FACTOR": "1",
+ "QT_QUICK_CONTROLS_CONF": "qtquickcontrols2.conf"
+ },
+ "fileGroups": {
+ "config": {
+ "directories": [
+ "."
+ ],
+ "files": [
+ {
+ "name": "qtquickcontrols2.conf"
+ }
+ ],
+ "filters": [
+ "*.conf"
+ ]
+ },
+ "image": {
+ "directories": [
+ "."
+ ],
+ "files": [
+ ],
+ "filters": [
+ "*.jpeg",
+ "*.jpg",
+ "*.png",
+ "*.svg",
+ "*.hdr",
+ ".ktx"
+ ]
+ },
+ "javaScript": {
+ "directories": [
+ "."
+ ],
+ "files": [
+ ],
+ "filters": [
+ "*.js",
+ "*.ts"
+ ]
+ },
+ "qml": {
+ "directories": [
+ "."
+ ],
+ "files": [
+ ],
+ "filters": [
+ "*.qml"
+ ]
+ },
+ "qmldir": {
+ "directories": [
+ "."
+ ],
+ "files": [
+ ],
+ "filters": [
+ "qmldir"
+ ]
+ }
+ },
+ "fileVersion": 1,
+ "importPaths": [
+ "imports"
+ ],
+ "language": {
+ },
+ "mcuConfig": {
+ },
+ "runConfig": {
+ "fileSelectors": [
+ "WXGA",
+ "darkTheme",
+ "ShowIndicator"
+ ],
+ "mainFile": "fileSelectors.qml"
+ },
+ "shaderTool": {
+ },
+ "versions": {
+ "qt": "5"
+ }
+}
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/MaterialBundle.qmlproject b/tests/unit/unittest/qmlprojectmanager/data/file-filters/MaterialBundle.qmlproject
new file mode 100644
index 00000000000..479c20456be
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/MaterialBundle.qmlproject
@@ -0,0 +1,112 @@
+import QmlProject
+
+Project {
+ mainFile: "content/App.qml"
+ mainUiFile: "Screen01.ui.qml"
+
+
+ /* Include .qml, .js, and image files from current directory and subdirectories */
+ QmlFiles {
+ directory: "content"
+ }
+
+ QmlFiles {
+ directory: "imports"
+ }
+
+ JavaScriptFiles {
+ directory: "content"
+ }
+
+ JavaScriptFiles {
+ directory: "imports"
+ }
+
+ ImageFiles {
+ directory: "content"
+ }
+
+ Files {
+ filter: "*.conf"
+ files: ["qtquickcontrols2.conf"]
+ }
+
+ Files {
+ filter: "qmldir"
+ directory: "."
+ }
+
+ Files {
+ filter: "*.ttf;*.otf"
+ }
+
+ Files {
+ filter: "*.wav;*.mp3"
+ }
+
+ Files {
+ filter: "*.mp4"
+ }
+
+ Files {
+ filter: "*.glsl;*.glslv;*.glslf;*.vsh;*.fsh;*.vert;*.frag"
+ }
+
+ Files {
+ filter: "*.mesh"
+ directory: "asset_imports"
+ }
+
+ Files {
+ filter: "*.mesh"
+ directory: "content"
+ }
+
+ Files {
+ filter: "*.qml"
+ directory: "asset_imports"
+ }
+
+ ImageFiles {
+ directory: "asset_imports"
+ }
+
+ Environment {
+ QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
+ QT_AUTO_SCREEN_SCALE_FACTOR: "1"
+ QT_LOGGING_RULES: "qt.qml.connections=false"
+ QT_ENABLE_HIGHDPI_SCALING: "0"
+ /* Useful for debugging
+ QSG_VISUALIZE=batches
+ QSG_VISUALIZE=clip
+ QSG_VISUALIZE=changes
+ QSG_VISUALIZE=overdraw
+ */
+ }
+
+ qt6Project: true
+
+ /* List of plugin directories passed to QML runtime */
+ importPaths: [ "imports", "asset_imports" ]
+
+ /* Required for deployment */
+ targetDirectory: "/opt/MaterialLibrary"
+
+ qdsVersion: "3.9"
+
+ /* If any modules the project imports require widgets (e.g. QtCharts), widgetApp must be true */
+ widgetApp: true
+
+ /* args: Specifies command line arguments for qsb tool to generate shaders.
+ files: Specifies target files for qsb tool. If path is included, it must be relative to this file.
+ Wildcard '*' can be used in the file name part of the path.
+ e.g. files: [ "content/shaders/*.vert", "*.frag" ] */
+ ShaderTool {
+ args: "-s --glsl \"100 es,120,150\" --hlsl 50 --msl 12"
+ files: [ "content/shaders/*" ]
+ }
+
+ multilanguageSupport: true
+ supportedLanguages: ["en"]
+ primaryLanguage: "en"
+}
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/MaterialBundle.qmlproject.qtds b/tests/unit/unittest/qmlprojectmanager/data/file-filters/MaterialBundle.qmlproject.qtds
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/MaterialBundle.qmlproject.qtds
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/MaterialLibrary.qrc b/tests/unit/unittest/qmlprojectmanager/data/file-filters/MaterialLibrary.qrc
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/MaterialLibrary.qrc
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/CMakeLists.txt b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/CMakeLists.txt
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/CMakeLists.txt
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/CMakeLists.txt b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/CMakeLists.txt
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/CMakeLists.txt
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/AcrylicPaintMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/AcrylicPaintMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/AcrylicPaintMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/AluminiumMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/AluminiumMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/AluminiumMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/AsphaltMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/AsphaltMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/AsphaltMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/BrickMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/BrickMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/BrickMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CMakeLists.txt b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CMakeLists.txt
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CMakeLists.txt
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CarPaintGlitterMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CarPaintGlitterMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CarPaintGlitterMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CarPaintMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CarPaintMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CarPaintMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CarbonFiberMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CarbonFiberMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CarbonFiberMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CeramicMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CeramicMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CeramicMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/ChromeMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/ChromeMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/ChromeMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/ConcreteMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/ConcreteMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/ConcreteMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CopperMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CopperMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/CopperMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/FabricMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/FabricMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/FabricMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/FabricRoughMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/FabricRoughMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/FabricRoughMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/FabricSatinMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/FabricSatinMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/FabricSatinMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/GlassMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/GlassMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/GlassMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/GlassTintedMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/GlassTintedMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/GlassTintedMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/GoldMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/GoldMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/GoldMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/LeatherMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/LeatherMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/LeatherMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/MirrorMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/MirrorMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/MirrorMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PaperMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PaperMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PaperMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PlasticMatteMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PlasticMatteMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PlasticMatteMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PlasticShinyMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PlasticShinyMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PlasticShinyMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PlasticTexturedMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PlasticTexturedMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/PlasticTexturedMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/RubberMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/RubberMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/RubberMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SilverMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SilverMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SilverMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SteelBrushedMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SteelBrushedMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SteelBrushedMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SteelFloorMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SteelFloorMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SteelFloorMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SteelMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SteelMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/SteelMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/StoneMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/StoneMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/StoneMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WaxMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WaxMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WaxMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WoodMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WoodMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WoodMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WoodParquetMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WoodParquetMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WoodParquetMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WoodPlanksMaterial.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WoodPlanksMaterial.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/WoodPlanksMaterial.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/_asset_ref.json b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/_asset_ref.json
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/_asset_ref.json
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/acrylicpaint.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/acrylicpaint.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/acrylicpaint.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/aluminium.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/aluminium.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/aluminium.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/asphalt.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/asphalt.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/asphalt.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/brick.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/brick.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/brick.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/carbonfiber.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/carbonfiber.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/carbonfiber.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/carpaint.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/carpaint.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/carpaint.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/carpaintglitter.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/carpaintglitter.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/carpaintglitter.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/ceramic.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/ceramic.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/ceramic.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/chrome.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/chrome.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/chrome.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/concrete.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/concrete.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/concrete.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/copper.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/copper.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/copper.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/fabric.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/fabric.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/fabric.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/fabricrough.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/fabricrough.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/fabricrough.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/fabricsatin.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/fabricsatin.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/fabricsatin.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/glass.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/glass.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/glass.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/glasstinted.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/glasstinted.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/glasstinted.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/gold.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/gold.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/gold.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/images/material.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/images/material.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/images/material.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/images/material16.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/images/material16.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/images/material16.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/images/[email protected] b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/images/[email protected]
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/images/[email protected]
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/leather.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/leather.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/leather.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/mirror.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/mirror.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/mirror.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/paper.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/paper.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/paper.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/plasticmatte.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/plasticmatte.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/plasticmatte.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/plasticshiny.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/plasticshiny.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/plasticshiny.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/plastictextured.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/plastictextured.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/plastictextured.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/rubber.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/rubber.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/rubber.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/silver.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/silver.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/silver.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/steel.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/steel.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/steel.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/steelbrushed.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/steelbrushed.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/steelbrushed.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/steelfloor.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/steelfloor.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/steelfloor.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/stone.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/stone.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/stone.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/wax.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/wax.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/wax.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/wood.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/wood.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/wood.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/woodparquet.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/woodparquet.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/woodparquet.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/woodplanks.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/woodplanks.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/designer/woodplanks.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_Opacity.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_Opacity.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_Opacity.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_Roughness.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_Roughness.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_Roughness.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_AmbientOcclusion.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_AmbientOcclusion.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_AmbientOcclusion.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_Color.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_Color.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_Color.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_Roughness.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_Roughness.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_Roughness.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Concrete032_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Concrete032_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Concrete032_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Concrete032_2K_Roughness.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Concrete032_2K_Roughness.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Concrete032_2K_Roughness.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/DiamondPlate001_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/DiamondPlate001_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/DiamondPlate001_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/DiamondPlate001_2K_Roughness.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/DiamondPlate001_2K_Roughness.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/DiamondPlate001_2K_Roughness.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric004_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric004_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric004_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_Displacement.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_Displacement.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_Displacement.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_Roughness.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_Roughness.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_Roughness.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_Displacement.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_Displacement.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_Displacement.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_Roughness.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_Roughness.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_Roughness.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/LDR_RGB1_3.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/LDR_RGB1_3.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/LDR_RGB1_3.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_Color.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_Color.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_Color.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_Roughness.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_Roughness.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_Roughness.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal009_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal009_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal009_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal009_2K_Roughness.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal009_2K_Roughness.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal009_2K_Roughness.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal029_2K_Displacement.jpg b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal029_2K_Displacement.jpg
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal029_2K_Displacement.jpg
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal029_2K_Displacement.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal029_2K_Displacement.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Metal029_2K_Displacement.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_AmbientOcclusion.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_AmbientOcclusion.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_AmbientOcclusion.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_Roughness.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_Roughness.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_Roughness.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_AmbientOcclusion.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_AmbientOcclusion.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_AmbientOcclusion.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_Color.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_Color.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_Color.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_Roughness.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_Roughness.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_Roughness.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_Color.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_Color.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_Color.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_Roughness.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_Roughness.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_Roughness.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_Color.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_Color.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_Color.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_Roughness.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_Roughness.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_Roughness.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_AmbientOcclusion.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_AmbientOcclusion.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_AmbientOcclusion.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_Color.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_Color.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_Color.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_NormalGL.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_NormalGL.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_NormalGL.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_Roughness.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_Roughness.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_Roughness.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/blurrynoise.tga b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/blurrynoise.tga
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/blurrynoise.tga
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/noisenormal.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/noisenormal.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/images/noisenormal.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/qmldir b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/qmldir
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/qmldir
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/CMakeLists.txt b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/CMakeLists.txt
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/CMakeLists.txt
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/SSS.frag b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/SSS.frag
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/SSS.frag
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/SSS.vert b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/SSS.vert
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/SSS.vert
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple.frag b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple.frag
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple.frag
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple.vert b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple.vert
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple.vert
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple_nf.frag b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple_nf.frag
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple_nf.frag
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple_nf.vert b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple_nf.vert
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple_nf.vert
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/glass.frag b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/glass.frag
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/glass.frag
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/glass.vert b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/glass.vert
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/glass.vert
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/satin.frag b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/satin.frag
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/satin.frag
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/satin.vert b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/satin.vert
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/asset_imports/ComponentBundles/MaterialBundle/shaders/satin.vert
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/App.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/App.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/App.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/CMakeLists.txt b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/CMakeLists.txt
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/CMakeLists.txt
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/CustomRoundButton.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/CustomRoundButton.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/CustomRoundButton.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/MaterialNames.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/MaterialNames.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/MaterialNames.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/MouseRotator.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/MouseRotator.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/MouseRotator.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/Screen01.ui.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/Screen01.ui.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/Screen01.ui.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/fonts/OpenSans-Bold.ttf b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/fonts/OpenSans-Bold.ttf
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/fonts/OpenSans-Bold.ttf
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/fonts/OpenSans-Regular.ttf b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/fonts/OpenSans-Regular.ttf
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/fonts/OpenSans-Regular.ttf
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/fonts/fonts.txt b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/fonts/fonts.txt
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/fonts/fonts.txt
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/Ground_ShadowMap.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/Ground_ShadowMap.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/Ground_ShadowMap.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/HDR/dark_mode.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/HDR/dark_mode.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/HDR/dark_mode.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/HDR/day_mode.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/HDR/day_mode.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/HDR/day_mode.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/LDR_RGB1_3.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/LDR_RGB1_3.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/LDR_RGB1_3.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/QtLogo_HD.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/QtLogo_HD.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/QtLogo_HD.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/innerMesh.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/innerMesh.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/innerMesh.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/lightToggle.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/lightToggle.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/lightToggle.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/outerMesh.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/outerMesh.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/outerMesh.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/perfhudicon.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/perfhudicon.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/perfhudicon.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/perfhudicon_on.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/perfhudicon_on.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/UI/perfhudicon_on.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/White.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/White.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/White.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/checkmark.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/checkmark.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/checkmark.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/groundAlpha.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/groundAlpha.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/groundAlpha.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/qtlogo.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/qtlogo.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/qtlogo.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/scratchmap.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/scratchmap.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/scratchmap.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/shadow.png b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/shadow.png
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/shadow.png
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_AO.jpg b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_AO.jpg
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_AO.jpg
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_Albedo.jpg b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_Albedo.jpg
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_Albedo.jpg
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_Normal.jpg b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_Normal.jpg
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_Normal.jpg
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_Roughness.jpg b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_Roughness.jpg
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/images/vlkhcah_2K_Roughness.jpg
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/meshes/floor.mesh b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/meshes/floor.mesh
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/meshes/floor.mesh
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/meshes/materialBall.mesh b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/meshes/materialBall.mesh
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/content/meshes/materialBall.mesh
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/filelist.txt b/tests/unit/unittest/qmlprojectmanager/data/file-filters/filelist.txt
new file mode 100644
index 00000000000..81fc1df7fcc
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/filelist.txt
@@ -0,0 +1,126 @@
+asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_AmbientOcclusion.png
+asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_Color.png
+asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_NormalGL.png
+asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_Roughness.png
+asset_imports/ComponentBundles/MaterialBundle/AcrylicPaintMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/GoldMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/shaders/satin.vert
+asset_imports/ComponentBundles/MaterialBundle/CarPaintGlitterMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_NormalGL.png
+asset_imports/ComponentBundles/MaterialBundle/SilverMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/SteelBrushedMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_AmbientOcclusion.png
+content/images/White.png
+asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_NormalGL.png
+asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_Roughness.png
+content/images/UI/perfhudicon_on.png
+asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple.frag
+asset_imports/ComponentBundles/MaterialBundle/images/DiamondPlate001_2K_NormalGL.png
+asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_Color.png
+asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_AmbientOcclusion.png
+content/images/shadow.png
+asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_NormalGL.png
+asset_imports/ComponentBundles/MaterialBundle/AsphaltMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_AmbientOcclusion.png
+content/images/LDR_RGB1_3.png
+imports/MaterialLibrary/EventListSimulator.qml
+asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_Roughness.png
+content/meshes/floor.mesh
+asset_imports/ComponentBundles/MaterialBundle/shaders/satin.frag
+asset_imports/ComponentBundles/MaterialBundle/images/Metal009_2K_Roughness.png
+content/images/UI/innerMesh.png
+content/images/UI/perfhudicon.png
+content/images/qtlogo.png
+content/images/vlkhcah_2K_Normal.jpg
+asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_Roughness.png
+asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_NormalGL.png
+asset_imports/ComponentBundles/MaterialBundle/RubberMaterial.qml
+content/App.qml
+asset_imports/ComponentBundles/MaterialBundle/AluminiumMaterial.qml
+content/images/HDR/dark_mode.png
+asset_imports/ComponentBundles/MaterialBundle/SteelFloorMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_Color.png
+asset_imports/ComponentBundles/MaterialBundle/shaders/SSS.frag
+content/fonts/OpenSans-Regular.ttf
+imports/MaterialLibrary/DirectoryFontLoader.qml
+asset_imports/ComponentBundles/MaterialBundle/LeatherMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/FabricRoughMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/images/LDR_RGB1_3.png
+asset_imports/ComponentBundles/MaterialBundle/PlasticTexturedMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/CopperMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/PlasticShinyMaterial.qml
+content/images/checkmark.png
+asset_imports/ComponentBundles/MaterialBundle/SteelMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_Roughness.png
+asset_imports/ComponentBundles/MaterialBundle/ChromeMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/CarbonFiberMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_Displacement.png
+asset_imports/ComponentBundles/MaterialBundle/images/Metal029_2K_Displacement.jpg
+asset_imports/ComponentBundles/MaterialBundle/FabricSatinMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple.vert
+asset_imports/ComponentBundles/MaterialBundle/designer/images/[email protected]
+asset_imports/ComponentBundles/MaterialBundle/WoodMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/PlasticMatteMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_NormalGL.png
+asset_imports/ComponentBundles/MaterialBundle/images/Concrete032_2K_Roughness.png
+asset_imports/ComponentBundles/MaterialBundle/CarPaintMaterial.qml
+content/images/Ground_ShadowMap.png
+content/MaterialNames.qml
+asset_imports/ComponentBundles/MaterialBundle/shaders/glass.vert
+asset_imports/ComponentBundles/MaterialBundle/images/Rock023_2K_Color.png
+asset_imports/ComponentBundles/MaterialBundle/BrickMaterial.qml
+content/images/UI/lightToggle.png
+asset_imports/ComponentBundles/MaterialBundle/images/Concrete032_2K_NormalGL.png
+content/MouseRotator.qml
+asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_Roughness.png
+asset_imports/ComponentBundles/MaterialBundle/shaders/glass.frag
+asset_imports/ComponentBundles/MaterialBundle/images/Metal029_2K_Displacement.png
+asset_imports/ComponentBundles/MaterialBundle/ConcreteMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/GlassMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/WoodParquetMaterial.qml
+imports/MaterialLibrary/Constants.qml
+content/meshes/materialBall.mesh
+asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple_nf.vert
+asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor044_2K_NormalGL.png
+content/images/vlkhcah_2K_AO.jpg
+asset_imports/ComponentBundles/MaterialBundle/MirrorMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_NormalGL.png
+imports/MaterialLibrary/qmldir
+asset_imports/ComponentBundles/MaterialBundle/images/Leather037_2K_Color.png
+content/Screen01.ui.qml
+asset_imports/ComponentBundles/MaterialBundle/CeramicMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/images/WoodFloor054_2K_Roughness.png
+asset_imports/ComponentBundles/MaterialBundle/images/Fabric004_2K_NormalGL.png
+asset_imports/ComponentBundles/MaterialBundle/images/noisenormal.png
+asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_Opacity.png
+asset_imports/ComponentBundles/MaterialBundle/FabricMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/qmldir
+asset_imports/ComponentBundles/MaterialBundle/PaperMaterial.qml
+content/images/UI/outerMesh.png
+imports/MaterialLibrary/EventListModel.qml
+asset_imports/ComponentBundles/MaterialBundle/images/Bricks026_2K_Color.png
+asset_imports/ComponentBundles/MaterialBundle/WaxMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/shaders/carmat_simple_nf.frag
+content/images/scratchmap.png
+asset_imports/ComponentBundles/MaterialBundle/images/Metal009_2K_NormalGL.png
+content/fonts/OpenSans-Bold.ttf
+asset_imports/ComponentBundles/MaterialBundle/StoneMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/shaders/SSS.vert
+content/images/HDR/day_mode.png
+content/images/QtLogo_HD.png
+content/images/vlkhcah_2K_Albedo.jpg
+asset_imports/ComponentBundles/MaterialBundle/images/Wood048_2K_Roughness.png
+qtquickcontrols2.conf
+asset_imports/ComponentBundles/MaterialBundle/images/Asphalt010_2K_Roughness.png
+asset_imports/ComponentBundles/MaterialBundle/images/Fabric030_2K_Roughness.png
+asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_NormalGL.png
+asset_imports/ComponentBundles/MaterialBundle/images/Fabric031_2K_Displacement.png
+asset_imports/ComponentBundles/MaterialBundle/GlassTintedMaterial.qml
+asset_imports/ComponentBundles/MaterialBundle/designer/images/material.png
+asset_imports/ComponentBundles/MaterialBundle/images/DiamondPlate001_2K_Roughness.png
+asset_imports/ComponentBundles/MaterialBundle/WoodPlanksMaterial.qml
+content/CustomRoundButton.qml
+content/images/groundAlpha.png
+asset_imports/ComponentBundles/MaterialBundle/images/Paint006_2K_NormalGL.png
+content/images/vlkhcah_2K_Roughness.jpg
+asset_imports/ComponentBundles/MaterialBundle/designer/images/material16.png \ No newline at end of file
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/CMakeLists.txt b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/CMakeLists.txt
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/CMakeLists.txt
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/CMakeLists.txt b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/CMakeLists.txt
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/CMakeLists.txt
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/Constants.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/Constants.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/Constants.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/DirectoryFontLoader.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/DirectoryFontLoader.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/DirectoryFontLoader.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/EventListModel.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/EventListModel.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/EventListModel.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/EventListSimulator.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/EventListSimulator.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/EventListSimulator.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/designer/plugin.metainfo b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/designer/plugin.metainfo
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/designer/plugin.metainfo
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/qmldir b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/qmldir
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/imports/MaterialLibrary/qmldir
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/main.qml b/tests/unit/unittest/qmlprojectmanager/data/file-filters/main.qml
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/main.qml
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/qmlcomponents b/tests/unit/unittest/qmlprojectmanager/data/file-filters/qmlcomponents
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/qmlcomponents
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/qmlmodules b/tests/unit/unittest/qmlprojectmanager/data/file-filters/qmlmodules
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/qmlmodules
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/qtquickcontrols2.conf b/tests/unit/unittest/qmlprojectmanager/data/file-filters/qtquickcontrols2.conf
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/qtquickcontrols2.conf
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/share.qrc b/tests/unit/unittest/qmlprojectmanager/data/file-filters/share.qrc
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/share.qrc
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/src/app_environment.h b/tests/unit/unittest/qmlprojectmanager/data/file-filters/src/app_environment.h
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/src/app_environment.h
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/src/import_qml_plugins.h b/tests/unit/unittest/qmlprojectmanager/data/file-filters/src/import_qml_plugins.h
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/src/import_qml_plugins.h
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/src/main.cpp b/tests/unit/unittest/qmlprojectmanager/data/file-filters/src/main.cpp
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/src/main.cpp
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/file-filters/translations.db b/tests/unit/unittest/qmlprojectmanager/data/file-filters/translations.db
new file mode 100644
index 00000000000..8b137891791
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/file-filters/translations.db
@@ -0,0 +1 @@
+
diff --git a/tests/unit/unittest/qmlprojectmanager/data/getter-setter/empty.qmlproject b/tests/unit/unittest/qmlprojectmanager/data/getter-setter/empty.qmlproject
new file mode 100644
index 00000000000..66adaaa7d91
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/getter-setter/empty.qmlproject
@@ -0,0 +1,44 @@
+import QmlProject
+
+Project {
+ mainFile: ""
+ mainUiFile: ""
+
+ qt6Project: false
+ widgetApp: false
+ qtForMCUs: false
+ forceFreeType: false
+
+ importPaths: [ ]
+ targetDirectory: ""
+ fileSelectors: [ ]
+
+ qdsVersion: ""
+ quickVersion: ""
+
+ multilanguageSupport: false
+ supportedLanguages: [ ]
+ primaryLanguage: ""
+
+ QmlFiles {
+ directory: ""
+ }
+
+ JavaScriptFiles {
+ directory: ""
+ }
+
+ ImageFiles {
+ directory: ""
+ }
+
+ Files {
+ filter: "*.testcontent"
+ files: [ ]
+ }
+
+ ShaderTool {
+ args: ""
+ files: [ ]
+ }
+}
diff --git a/tests/unit/unittest/qmlprojectmanager/data/getter-setter/notEmpty.qmlproject b/tests/unit/unittest/qmlprojectmanager/data/getter-setter/notEmpty.qmlproject
new file mode 100644
index 00000000000..ae866ca3974
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/data/getter-setter/notEmpty.qmlproject
@@ -0,0 +1,96 @@
+import QmlProject
+
+Project {
+ mainFile: "content/App.qml"
+ mainUiFile: "Screen01.ui.qml"
+
+ qt6Project: true
+ widgetApp: true
+ qtForMCUs: true
+ forceFreeType: true
+
+ importPaths: [ "imports", "asset_imports" ]
+ targetDirectory: "/opt/targetDirectory"
+ fileSelectors: [ "WXGA", "darkTheme", "ShowIndicator"]
+
+ qdsVersion: "3.9"
+ quickVersion: "6.2"
+
+ multilanguageSupport: true
+ supportedLanguages: ["en" , "fr"]
+ primaryLanguage: "en"
+
+ QmlFiles {
+ directory: "content"
+ }
+
+ QmlFiles {
+ directory: "imports"
+ }
+
+ JavaScriptFiles {
+ directory: "content"
+ }
+
+ JavaScriptFiles {
+ directory: "imports"
+ }
+
+ ImageFiles {
+ directory: "content"
+ }
+
+ Files {
+ filter: "*.conf"
+ files: ["qtquickcontrols2.conf"]
+ }
+
+ Files {
+ filter: "qmldir"
+ directory: "."
+ }
+
+ Files {
+ filter: "*.ttf;*.otf"
+ }
+
+ Files {
+ filter: "*.wav;*.mp3"
+ }
+
+ Files {
+ filter: "*.mp4"
+ }
+
+ Files {
+ filter: "*.glsl;*.glslv;*.glslf;*.vsh;*.fsh;*.vert;*.frag"
+ }
+
+ Files {
+ filter: "*.mesh"
+ directory: "asset_imports"
+ }
+
+ Files {
+ filter: "*.mesh"
+ directory: "content"
+ }
+
+ Files {
+ filter: "*.qml"
+ directory: "asset_imports"
+ }
+
+ ImageFiles {
+ directory: "asset_imports"
+ }
+
+ Environment {
+ QT_QUICK_CONTROLS_CONF: "qtquickcontrols2.conf"
+ }
+
+ ShaderTool {
+ args: "-s --glsl \"100 es,120,150\" --hlsl 50 --msl 12"
+ files: [ "content/shaders/*" ]
+ }
+}
diff --git a/tests/unit/unittest/qmlprojectmanager/projectitem-test.cpp b/tests/unit/unittest/qmlprojectmanager/projectitem-test.cpp
new file mode 100644
index 00000000000..3bf214fd81f
--- /dev/null
+++ b/tests/unit/unittest/qmlprojectmanager/projectitem-test.cpp
@@ -0,0 +1,539 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "googletest.h" // IWYU pragma: keep
+#include "google-using-declarations.h"
+
+#include <qmlprojectmanager/buildsystem/projectitem/qmlprojectitem.h>
+
+#include <utils/algorithm.h>
+namespace {
+
+constexpr QLatin1String localTestDataDir{UNITTEST_DIR "/qmlprojectmanager/data"};
+
+class QmlProjectItem : public testing::Test
+{
+protected:
+ static void SetUpTestSuite()
+ {
+ projectItemEmpty = std::make_unique<const QmlProjectManager::QmlProjectItem>(
+ Utils::FilePath::fromString(localTestDataDir + "/getter-setter/empty.qmlproject"), true);
+
+ projectItemNotEmpty = std::make_unique<const QmlProjectManager::QmlProjectItem>(
+ Utils::FilePath::fromString(localTestDataDir + "/getter-setter/notEmpty.qmlproject"),
+ true);
+
+ projectItemFileFilters = std::make_unique<const QmlProjectManager::QmlProjectItem>(
+ Utils::FilePath::fromString(localTestDataDir + "/file-filters/MaterialBundle.qmlproject"),
+ true);
+ }
+
+ static void TearDownTestSuite()
+ {
+ projectItemEmpty.reset();
+ projectItemNotEmpty.reset();
+ projectItemFileFilters.reset();
+ }
+
+protected:
+ static inline std::unique_ptr<const QmlProjectManager::QmlProjectItem> projectItemEmpty;
+ static inline std::unique_ptr<const QmlProjectManager::QmlProjectItem> projectItemNotEmpty;
+ std::unique_ptr<QmlProjectManager::QmlProjectItem>
+ projectItemSetters = std::make_unique<QmlProjectManager::QmlProjectItem>(
+ Utils::FilePath::fromString(localTestDataDir + "/getter-setter/empty.qmlproject"), true);
+ static inline std::unique_ptr<const QmlProjectManager::QmlProjectItem> projectItemFileFilters;
+};
+
+auto createAbsoluteFilePaths(const QStringList &fileList)
+{
+ return Utils::transform(fileList, [](const QString &fileName) {
+ return Utils::FilePath::fromString(localTestDataDir + "/file-filters").pathAppended(fileName);
+ });
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyMainFileProject)
+{
+ auto mainFile = projectItemNotEmpty->mainFile();
+
+ ASSERT_THAT(mainFile, Eq("content/App.qml"));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyMainUIFileProject)
+{
+ auto mainUiFile = projectItemNotEmpty->mainUiFile();
+
+ ASSERT_THAT(mainUiFile, Eq("Screen01.ui.qml"));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyMcuProject)
+{
+ auto isMcuProject = projectItemNotEmpty->isQt4McuProject();
+
+ ASSERT_TRUE(isMcuProject);
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyQtVersion)
+{
+ auto qtVersion = projectItemNotEmpty->versionQt();
+
+ ASSERT_THAT(qtVersion, Eq("6"));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyQtQuickVersion)
+{
+ auto qtQuickVersion = projectItemNotEmpty->versionQtQuick();
+
+ ASSERT_THAT(qtQuickVersion, Eq("6.2"));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyDesignStudioVersion)
+{
+ auto designStudioVersion = projectItemNotEmpty->versionDesignStudio();
+
+ ASSERT_THAT(designStudioVersion, Eq("3.9"));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptySourceDirectory)
+{
+ auto sourceDirectory = projectItemNotEmpty->sourceDirectory().path();
+
+ auto expectedSourceDir = localTestDataDir + "/getter-setter";
+
+ ASSERT_THAT(sourceDirectory, Eq(expectedSourceDir));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyTarGetNotEmptyDirectory)
+{
+ auto targetDirectory = projectItemNotEmpty->targetDirectory();
+
+ ASSERT_THAT(targetDirectory, Eq("/opt/targetDirectory"));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyImportPaths)
+{
+ auto importPaths = projectItemNotEmpty->importPaths();
+
+ ASSERT_THAT(importPaths, UnorderedElementsAre("imports", "asset_imports"));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyFileSelectors)
+{
+ auto fileSelectors = projectItemNotEmpty->fileSelectors();
+
+ ASSERT_THAT(fileSelectors, UnorderedElementsAre("WXGA", "darkTheme", "ShowIndicator"));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyMultiLanguageSupport)
+{
+ auto multilanguageSupport = projectItemNotEmpty->multilanguageSupport();
+
+ ASSERT_TRUE(multilanguageSupport);
+}
+
+TEST_F(QmlProjectItem, GetNotEmptySupportedLanguages)
+{
+ auto supportedLanguages = projectItemNotEmpty->supportedLanguages();
+
+ ASSERT_THAT(supportedLanguages, UnorderedElementsAre("en", "fr"));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyPrimaryLanguage)
+{
+ auto primaryLanguage = projectItemNotEmpty->primaryLanguage();
+ ;
+
+ ASSERT_THAT(primaryLanguage, Eq("en"));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyWidgetApp)
+{
+ auto widgetApp = projectItemNotEmpty->widgetApp();
+
+ ASSERT_TRUE(widgetApp);
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyFileList)
+{
+ QStringList fileList;
+ for (const auto &file : projectItemNotEmpty->files()) {
+ fileList.append(file.path());
+ }
+
+ auto expectedFileList = localTestDataDir + "/getter-setter/qtquickcontrols2.conf";
+
+ ASSERT_THAT(fileList, UnorderedElementsAre(expectedFileList));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyShaderToolArgs)
+{
+ auto shaderToolArgs = projectItemNotEmpty->shaderToolArgs();
+
+ ASSERT_THAT(shaderToolArgs,
+ UnorderedElementsAre("-s", "--glsl", "\"100 es,120,150\"", "--hlsl", "50", "--msl", "12"));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyShaderToolFiles)
+{
+ auto shaderToolFiles = projectItemNotEmpty->shaderToolFiles();
+
+ ASSERT_THAT(shaderToolFiles, UnorderedElementsAre("content/shaders/*"));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyEnvironment)
+{
+ auto env = projectItemNotEmpty->environment();
+
+ ASSERT_THAT(env,
+ UnorderedElementsAre(
+ Utils::EnvironmentItem("QT_QUICK_CONTROLS_CONF", "qtquickcontrols2.conf")));
+}
+
+TEST_F(QmlProjectItem, GetNotEmptyForceFreeType)
+{
+ auto forceFreeType = projectItemNotEmpty->forceFreeType();
+
+ ASSERT_TRUE(forceFreeType);
+}
+
+TEST_F(QmlProjectItem, GetEmptyMainFileProject)
+{
+ auto mainFile = projectItemEmpty->mainFile();
+
+ ASSERT_THAT(mainFile, IsEmpty());
+}
+
+TEST_F(QmlProjectItem, GetEmptyMainUIFileProject)
+{
+ auto mainUiFile = projectItemEmpty->mainUiFile();
+
+ ASSERT_THAT(mainUiFile, IsEmpty());
+}
+
+TEST_F(QmlProjectItem, GetEmptyMcuProject)
+{
+ auto isMcuProject = projectItemEmpty->isQt4McuProject();
+
+ ASSERT_FALSE(isMcuProject);
+}
+
+TEST_F(QmlProjectItem, GetEmptyQtVersion)
+{
+ auto qtVersion = projectItemEmpty->versionQt();
+
+ // default Qt Version is "5" for Design Studio projects
+ ASSERT_THAT(qtVersion, Eq("5"));
+}
+
+TEST_F(QmlProjectItem, GetEmptyQtQuickVersion)
+{
+ auto qtQuickVersion = projectItemEmpty->versionQtQuick();
+
+ ASSERT_THAT(projectItemEmpty->versionQtQuick(), IsEmpty());
+}
+
+TEST_F(QmlProjectItem, GetEmptyDesignStudioVersion)
+{
+ auto designStudioVersion = projectItemEmpty->versionDesignStudio();
+
+ ASSERT_THAT(projectItemEmpty->versionDesignStudio(), IsEmpty());
+}
+
+TEST_F(QmlProjectItem, GetEmptySourceDirectory)
+{
+ auto sourceDirectory = projectItemEmpty->sourceDirectory().path();
+
+ auto expectedSourceDir = localTestDataDir + "/getter-setter";
+
+ // default source directory is the project directory
+ ASSERT_THAT(sourceDirectory, Eq(expectedSourceDir));
+}
+
+TEST_F(QmlProjectItem, GetEmptyTarGetEmptyDirectory)
+{
+ auto targetDirectory = projectItemEmpty->targetDirectory();
+
+ ASSERT_THAT(targetDirectory, IsEmpty());
+}
+
+TEST_F(QmlProjectItem, GetEmptyImportPaths)
+{
+ auto importPaths = projectItemEmpty->importPaths();
+
+ ASSERT_THAT(importPaths, IsEmpty());
+}
+
+TEST_F(QmlProjectItem, GetEmptyFileSelectors)
+{
+ auto fileSelectors = projectItemEmpty->fileSelectors();
+
+ ASSERT_THAT(fileSelectors, IsEmpty());
+}
+
+TEST_F(QmlProjectItem, GetEmptyMultiLanguageSupport)
+{
+ auto multilanguageSupport = projectItemEmpty->multilanguageSupport();
+
+ ASSERT_FALSE(multilanguageSupport);
+}
+
+TEST_F(QmlProjectItem, GetEmptySupportedLanguages)
+{
+ auto supportedLanguages = projectItemEmpty->supportedLanguages();
+
+ ASSERT_THAT(supportedLanguages, IsEmpty());
+}
+
+TEST_F(QmlProjectItem, GetEmptyPrimaryLanguage)
+{
+ auto primaryLanguage = projectItemEmpty->primaryLanguage();
+
+ ASSERT_THAT(primaryLanguage, IsEmpty());
+}
+
+TEST_F(QmlProjectItem, GetEmptyWidgetApp)
+{
+ auto widgetApp = projectItemEmpty->widgetApp();
+
+ ASSERT_FALSE(widgetApp);
+}
+
+TEST_F(QmlProjectItem, GetEmptyFileList)
+{
+ auto fileList = projectItemEmpty->files();
+
+ ASSERT_THAT(fileList, IsEmpty());
+}
+
+TEST_F(QmlProjectItem, GetEmptyShaderToolArgs)
+{
+ auto shaderToolArgs = projectItemEmpty->shaderToolArgs();
+
+ ASSERT_THAT(shaderToolArgs, IsEmpty());
+}
+
+TEST_F(QmlProjectItem, GetEmptyShaderToolFiles)
+{
+ auto shaderToolFiles = projectItemEmpty->shaderToolFiles();
+
+ ASSERT_THAT(shaderToolFiles, IsEmpty());
+}
+
+TEST_F(QmlProjectItem, GetEmptyEnvironment)
+{
+ auto env = projectItemEmpty->environment();
+
+ ASSERT_THAT(env, IsEmpty());
+}
+
+TEST_F(QmlProjectItem, GetEmptyForceFreeType)
+{
+ auto forceFreeType = projectItemEmpty->forceFreeType();
+
+ ASSERT_FALSE(forceFreeType);
+}
+
+TEST_F(QmlProjectItem, SetMainFileProject)
+{
+ projectItemSetters->setMainFile("testing");
+
+ auto mainFile = projectItemSetters->mainFile();
+
+ ASSERT_THAT(mainFile, Eq("testing"));
+}
+
+TEST_F(QmlProjectItem, SetMainUIFileProject)
+{
+ projectItemSetters->setMainUiFile("testing");
+
+ auto mainUiFile = projectItemSetters->mainUiFile();
+
+ ASSERT_THAT(mainUiFile, Eq("testing"));
+}
+
+TEST_F(QmlProjectItem, SetImportPaths)
+{
+ projectItemSetters->setImportPaths({"testing"});
+
+ auto importPaths = projectItemSetters->importPaths();
+
+ ASSERT_THAT(importPaths, UnorderedElementsAre("testing"));
+}
+
+TEST_F(QmlProjectItem, AddImportPaths)
+{
+ projectItemSetters->setImportPaths({});
+ projectItemSetters->addImportPath("testing");
+
+ auto importPaths = projectItemSetters->importPaths();
+
+ ASSERT_THAT(importPaths, UnorderedElementsAre("testing"));
+}
+
+TEST_F(QmlProjectItem, SetFileSelectors)
+{
+ projectItemSetters->setFileSelectors({"testing"});
+
+ auto fileSelectors = projectItemSetters->fileSelectors();
+
+ ASSERT_THAT(fileSelectors, UnorderedElementsAre("testing"));
+}
+
+TEST_F(QmlProjectItem, AddFileSelectors)
+{
+ projectItemSetters->setFileSelectors({});
+ projectItemSetters->addFileSelector("testing");
+
+ auto fileSelectors = projectItemSetters->fileSelectors();
+
+ ASSERT_THAT(fileSelectors, UnorderedElementsAre("testing"));
+}
+
+TEST_F(QmlProjectItem, SetMultiLanguageSupport)
+{
+ projectItemSetters->setMultilanguageSupport(true);
+
+ auto multilanguageSupport = projectItemSetters->multilanguageSupport();
+
+ ASSERT_TRUE(multilanguageSupport);
+}
+
+TEST_F(QmlProjectItem, SetSupportedLanguages)
+{
+ projectItemSetters->setSupportedLanguages({"testing"});
+
+ auto supportedLanguages = projectItemSetters->supportedLanguages();
+
+ ASSERT_THAT(supportedLanguages, UnorderedElementsAre("testing"));
+}
+
+TEST_F(QmlProjectItem, AddSupportedLanguages)
+{
+ projectItemSetters->setSupportedLanguages({});
+ projectItemSetters->addSupportedLanguage("testing");
+
+ auto supportedLanguages = projectItemSetters->supportedLanguages();
+
+ ASSERT_THAT(supportedLanguages, UnorderedElementsAre("testing"));
+}
+
+TEST_F(QmlProjectItem, SetPrimaryLanguage)
+{
+ projectItemSetters->setPrimaryLanguage("testing");
+
+ auto primaryLanguage = projectItemSetters->primaryLanguage();
+ ;
+
+ ASSERT_THAT(primaryLanguage, Eq("testing"));
+}
+
+TEST_F(QmlProjectItem, SetWidgetApp)
+{
+ projectItemSetters->setWidgetApp(true);
+
+ auto widgetApp = projectItemSetters->widgetApp();
+
+ ASSERT_TRUE(widgetApp);
+}
+
+TEST_F(QmlProjectItem, SetShaderToolArgs)
+{
+ projectItemSetters->setShaderToolArgs({"testing"});
+
+ auto shaderToolArgs = projectItemSetters->shaderToolArgs();
+
+ ASSERT_THAT(shaderToolArgs, UnorderedElementsAre("testing"));
+}
+
+TEST_F(QmlProjectItem, AddShaderToolArgs)
+{
+ projectItemSetters->setShaderToolArgs({});
+ projectItemSetters->addShaderToolArg("testing");
+
+ auto shaderToolArgs = projectItemSetters->shaderToolArgs();
+
+ ASSERT_THAT(shaderToolArgs, UnorderedElementsAre("testing"));
+}
+
+TEST_F(QmlProjectItem, SetShaderToolFiles)
+{
+ projectItemSetters->setShaderToolFiles({"testing"});
+
+ auto shaderToolFiles = projectItemSetters->shaderToolFiles();
+
+ ASSERT_THAT(shaderToolFiles, UnorderedElementsAre("testing"));
+}
+
+TEST_F(QmlProjectItem, AddShaderToolFiles)
+{
+ projectItemSetters->setShaderToolFiles({});
+ projectItemSetters->addShaderToolFile("testing");
+
+ auto shaderToolFiles = projectItemSetters->shaderToolFiles();
+
+ ASSERT_THAT(shaderToolFiles, UnorderedElementsAre("testing"));
+}
+
+TEST_F(QmlProjectItem, AddEnvironment)
+{
+ projectItemSetters->addToEnviroment("testing", "testing");
+ auto envs = projectItemSetters->environment();
+
+ Utils::EnvironmentItems expectedEnvs;
+ expectedEnvs.push_back({"testing", "testing"});
+
+ ASSERT_EQ(envs, expectedEnvs);
+}
+
+TEST_F(QmlProjectItem, SetForceFreeTypeTrue)
+{
+ projectItemSetters->setForceFreeType(true);
+
+ ASSERT_EQ(projectItemSetters->forceFreeType(), true);
+}
+
+TEST_F(QmlProjectItem, SetForceFreeTypeFalse)
+{
+ projectItemSetters->setForceFreeType(false);
+
+ ASSERT_EQ(projectItemSetters->forceFreeType(), false);
+}
+
+TEST_F(QmlProjectItem, SetQtVersion)
+{
+ projectItemSetters->setVersionQt("6");
+
+ ASSERT_EQ(projectItemSetters->versionQt().toStdString(), "6");
+}
+
+TEST_F(QmlProjectItem, SetQtQuickVersion)
+{
+ projectItemSetters->setVersionQtQuick("6");
+
+ ASSERT_EQ(projectItemSetters->versionQtQuick(), "6");
+}
+
+TEST_F(QmlProjectItem, SetDesignStudioVersion)
+{
+ projectItemSetters->setVersionDesignStudio("6");
+
+ ASSERT_EQ(projectItemSetters->versionDesignStudio(), "6");
+}
+
+// TODO: We should move this one into the integration tests
+TEST_F(QmlProjectItem, TestFileFilters)
+{
+ // GIVEN
+ auto fileListPath = Utils::FilePath::fromString(localTestDataDir + "/file-filters/filelist.txt");
+ QStringList fileNameList = QString::fromUtf8(fileListPath.fileContents().value())
+ .replace("\r\n", "\n")
+ .split("\n");
+ auto expectedAbsoluteFilePaths = createAbsoluteFilePaths(fileNameList);
+
+ // WHEN
+ auto filePaths = projectItemFileFilters->files();
+
+ // THEN
+ ASSERT_THAT(filePaths, UnorderedElementsAreArray(expectedAbsoluteFilePaths));
+}
+
+} // namespace
diff --git a/tests/unit/unittest/qmltypesparser-test.cpp b/tests/unit/unittest/qmltypesparser-test.cpp
index 405eec57df6..3fbbaa6b8cc 100644
--- a/tests/unit/unittest/qmltypesparser-test.cpp
+++ b/tests/unit/unittest/qmltypesparser-test.cpp
@@ -149,7 +149,7 @@ protected:
QmlDesigner::ProjectStorage<Sqlite::Database> storage{database, database.isInitialized()};
QmlDesigner::SourcePathCache<QmlDesigner::ProjectStorage<Sqlite::Database>> sourcePathCache{
storage};
- QmlDesigner::QmlTypesParser parser{sourcePathCache, storage};
+ QmlDesigner::QmlTypesParser parser{storage};
Storage::Imports imports;
Storage::Types types;
SourceId qmltypesFileSourceId{sourcePathCache.sourceId("path/to/types.qmltypes")};
@@ -171,14 +171,22 @@ TEST_F(QmlTypesParser, Imports)
parser.parse(source, imports, types, projectData);
- ASSERT_THAT(
- imports,
- UnorderedElementsAre(
- IsImport(storage.moduleId("QML-cppnative"), Storage::Version{}, qmltypesFileSourceId),
- IsImport(storage.moduleId("QtQml-cppnative"), Storage::Version{}, qmltypesFileSourceId),
- IsImport(storage.moduleId("QtQuick-cppnative"), Storage::Version{}, qmltypesFileSourceId),
- IsImport(storage.moduleId("QtQuick.Window-cppnative"), Storage::Version{}, qmltypesFileSourceId),
- IsImport(storage.moduleId("QtFoo-cppnative"), Storage::Version{}, qmltypesFileSourceId)));
+ ASSERT_THAT(imports,
+ UnorderedElementsAre(IsImport(storage.moduleId("QML-cppnative"),
+ QmlDesigner::Storage::Version{},
+ qmltypesFileSourceId),
+ IsImport(storage.moduleId("QtQml-cppnative"),
+ QmlDesigner::Storage::Version{},
+ qmltypesFileSourceId),
+ IsImport(storage.moduleId("QtQuick-cppnative"),
+ QmlDesigner::Storage::Version{},
+ qmltypesFileSourceId),
+ IsImport(storage.moduleId("QtQuick.Window-cppnative"),
+ QmlDesigner::Storage::Version{},
+ qmltypesFileSourceId),
+ IsImport(storage.moduleId("QtFoo-cppnative"),
+ QmlDesigner::Storage::Version{},
+ qmltypesFileSourceId)));
}
TEST_F(QmlTypesParser, Types)
@@ -261,13 +269,14 @@ TEST_F(QmlTypesParser, ExportedTypes)
parser.parse(source, imports, types, projectData);
- ASSERT_THAT(types,
- ElementsAre(
- Field(&Storage::Type::exportedTypes,
- UnorderedElementsAre(
- IsExportedType(qmlModuleId, "QtObject", Storage::Version{1, 0}),
- IsExportedType(qtQmlModuleId, "QtObject", Storage::Version{2, 1}),
- IsExportedType(qtQmlNativeModuleId, "QObject", Storage::Version{})))));
+ ASSERT_THAT(
+ types,
+ ElementsAre(Field(
+ &Storage::Type::exportedTypes,
+ UnorderedElementsAre(
+ IsExportedType(qmlModuleId, "QtObject", QmlDesigner::Storage::Version{1, 0}),
+ IsExportedType(qtQmlModuleId, "QtObject", QmlDesigner::Storage::Version{2, 1}),
+ IsExportedType(qtQmlNativeModuleId, "QObject", QmlDesigner::Storage::Version{})))));
}
TEST_F(QmlTypesParser, Properties)
@@ -567,30 +576,28 @@ TEST_F(QmlTypesParser, EnumerationIsExportedAsType)
parser.parse(source, imports, types, projectData);
- ASSERT_THAT(types,
- UnorderedElementsAre(
- AllOf(IsType("QObject::NamedColorSpace",
- Storage::ImportedType{},
- Storage::ImportedType{},
- QmlDesigner::Storage::TypeTraits::Value
- | QmlDesigner::Storage::TypeTraits::IsEnum,
- qmltypesFileSourceId),
- Field(&Storage::Type::exportedTypes,
- UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
- "QObject::NamedColorSpace",
- Storage::Version{})))),
- AllOf(IsType("QObject::VerticalLayoutDirection",
- Storage::ImportedType{},
- Storage::ImportedType{},
- QmlDesigner::Storage::TypeTraits::Value
- | QmlDesigner::Storage::TypeTraits::IsEnum,
- qmltypesFileSourceId),
- Field(&Storage::Type::exportedTypes,
- UnorderedElementsAre(
- IsExportedType(qtQmlNativeModuleId,
- "QObject::VerticalLayoutDirection",
- Storage::Version{})))),
- _));
+ ASSERT_THAT(
+ types,
+ UnorderedElementsAre(
+ AllOf(IsType("QObject::NamedColorSpace",
+ Storage::ImportedType{},
+ Storage::ImportedType{},
+ QmlDesigner::Storage::TypeTraits::Value | QmlDesigner::Storage::TypeTraits::IsEnum,
+ qmltypesFileSourceId),
+ Field(&Storage::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
+ "QObject::NamedColorSpace",
+ QmlDesigner::Storage::Version{})))),
+ AllOf(IsType("QObject::VerticalLayoutDirection",
+ Storage::ImportedType{},
+ Storage::ImportedType{},
+ QmlDesigner::Storage::TypeTraits::Value | QmlDesigner::Storage::TypeTraits::IsEnum,
+ qmltypesFileSourceId),
+ Field(&Storage::Type::exportedTypes,
+ UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
+ "QObject::VerticalLayoutDirection",
+ QmlDesigner::Storage::Version{})))),
+ _));
}
TEST_F(QmlTypesParser, EnumerationIsExportedAsTypeWithAlias)
@@ -624,10 +631,10 @@ TEST_F(QmlTypesParser, EnumerationIsExportedAsTypeWithAlias)
Field(&Storage::Type::exportedTypes,
UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
"QObject::NamedColorSpace",
- Storage::Version{}),
+ QmlDesigner::Storage::Version{}),
IsExportedType(qtQmlNativeModuleId,
"QObject::NamedColorSpaces",
- Storage::Version{})))),
+ QmlDesigner::Storage::Version{})))),
_));
}
@@ -671,10 +678,10 @@ TEST_F(QmlTypesParser, EnumerationIsExportedAsTypeWithAliasToo)
Field(&Storage::Type::exportedTypes,
UnorderedElementsAre(IsExportedType(qtQmlNativeModuleId,
"QObject::NamedColorSpace",
- Storage::Version{}),
+ QmlDesigner::Storage::Version{}),
IsExportedType(qtQmlNativeModuleId,
"QObject::NamedColorSpaces",
- Storage::Version{})))),
+ QmlDesigner::Storage::Version{})))),
_));
}
diff --git a/tests/unit/unittest/smallstring-test.cpp b/tests/unit/unittest/smallstring-test.cpp
index d8321ec98f4..a77e0bdc2d4 100644
--- a/tests/unit/unittest/smallstring-test.cpp
+++ b/tests/unit/unittest/smallstring-test.cpp
@@ -9,8 +9,6 @@
#include <utils/smallstringio.h>
#include <utils/smallstringvector.h>
-using namespace ::testing;
-
using Utils::PathString;
using Utils::SmallString;
using Utils::SmallStringLiteral;
@@ -125,7 +123,7 @@ TEST(SmallString, MaximumShortSmallString)
{
SmallString maximumShortText("very very very very short text", 30);
- ASSERT_THAT(maximumShortText.constData(), StrEq("very very very very short text"));
+ ASSERT_THAT(maximumShortText, StrEq("very very very very short text"));
}
TEST(SmallString, LongConstExpressionSmallStringIsReference)
@@ -221,21 +219,21 @@ TEST(SmallString, SmallStringLiteralShortSmallStringDataAccess)
{
SmallStringLiteral literalText("very very very very very very very very very very very long string");
- ASSERT_THAT(literalText.data(), StrEq("very very very very very very very very very very very long string"));
+ ASSERT_THAT(literalText, StrEq("very very very very very very very very very very very long string"));
}
TEST(SmallString, SmallStringLiteralLongSmallStringDataAccess)
{
SmallStringLiteral literalText("short string");
- ASSERT_THAT(literalText.data(), StrEq("short string"));
+ ASSERT_THAT(literalText, StrEq("short string"));
}
TEST(SmallString, ReferenceDataAccess)
{
SmallString literalText("short string");
- ASSERT_THAT(literalText.constData(), StrEq("short string"));
+ ASSERT_THAT(literalText, StrEq("short string"));
}
TEST(SmallString, ShortDataAccess)
@@ -243,7 +241,7 @@ TEST(SmallString, ShortDataAccess)
const char *shortCString = "short string";
auto shortText = SmallString::fromUtf8(shortCString);
- ASSERT_THAT(shortText.constData(), StrEq("short string"));
+ ASSERT_THAT(shortText, StrEq("short string"));
}
TEST(SmallString, LongDataAccess)
@@ -251,7 +249,7 @@ TEST(SmallString, LongDataAccess)
const char *longCString = "very very very very very very very very very very very long string";
auto longText = SmallString::fromUtf8(longCString);
- ASSERT_THAT(longText.constData(), StrEq(longCString));
+ ASSERT_THAT(longText, StrEq(longCString));
}
TEST(SmallString, LongSmallStringHasShortSmallStringSizeZero)
@@ -964,8 +962,8 @@ TEST(SmallString, EqualCStringArrayOperator)
TEST(SmallString, EqualCStringPointerOperator)
{
- ASSERT_TRUE(SmallString("text") == SmallString("text").data());
- ASSERT_FALSE(SmallString("text") == SmallString("text2").data());
+ ASSERT_TRUE(SmallString("text") == std::string("text").data());
+ ASSERT_FALSE(SmallString("text") == std::string("text2").data());
}
TEST(SmallString, EqualSmallStringViewOperator)
@@ -994,8 +992,8 @@ TEST(SmallString, UnequalCStringArrayOperator)
TEST(SmallString, UnequalCStringPointerOperator)
{
- ASSERT_FALSE(SmallString("text") != SmallString("text").data());
- ASSERT_TRUE(SmallString("text") != SmallString("text2").data());
+ ASSERT_FALSE(SmallString("text") != std::string("text").data());
+ ASSERT_TRUE(SmallString("text") != std::string("text2").data());
}
TEST(SmallString, UnequalSmallStringViewArrayOperator)
@@ -1535,10 +1533,9 @@ TEST(SmallString, LongPathStringMoveConstuctor)
"text"));
}
-#if __clang__
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wself-move"
-#endif
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_GCC("-Wself-move")
+QT_WARNING_DISABLE_CLANG("-Wself-move")
TEST(SmallString, ShortSmallStringMoveConstuctorToSelf)
{
@@ -1585,9 +1582,7 @@ TEST(SmallString, LongPathStringMoveConstuctorToSelf)
"text"));
}
-#if __clang__
-#pragma clang diagnostic pop
-#endif
+QT_WARNING_POP
TEST(SmallString, ShortSmallStringCopyAssignment)
{
diff --git a/tests/unit/unittest/sqlitereadstatementmock.cpp b/tests/unit/unittest/sqlitereadstatementmock.cpp
index b90053e9f13..cad99a8bcff 100644
--- a/tests/unit/unittest/sqlitereadstatementmock.cpp
+++ b/tests/unit/unittest/sqlitereadstatementmock.cpp
@@ -8,6 +8,7 @@
SqliteReadStatementMockBase::SqliteReadStatementMockBase(Utils::SmallStringView sqlStatement,
SqliteDatabaseMock &databaseMock)
: sqlStatement(sqlStatement)
+ , databaseMock(databaseMock)
{
databaseMock.prepare(sqlStatement);
}
diff --git a/tests/unit/unittest/sqlitereadstatementmock.h b/tests/unit/unittest/sqlitereadstatementmock.h
index 9ab3b451220..38d7e41ecfb 100644
--- a/tests/unit/unittest/sqlitereadstatementmock.h
+++ b/tests/unit/unittest/sqlitereadstatementmock.h
@@ -11,6 +11,7 @@
#include <projectstorageids.h>
#include <sqliteblob.h>
#include <sqlitetimestamp.h>
+#include <sqlitetransaction.h>
#include <utils/smallstring.h>
#include <QImage>
@@ -198,7 +199,9 @@ public:
template<typename ResultType, typename... QueryTypes>
auto optionalValueWithTransaction(const QueryTypes &...queryValues)
{
- return optionalValue<ResultType>(queryValues...);
+ return Sqlite::withDeferredTransaction(databaseMock, [&] {
+ return optionalValue<ResultType>(queryValues...);
+ });
}
template<typename ResultType, typename... QueryType>
@@ -261,6 +264,7 @@ public:
public:
Utils::SmallString sqlStatement;
+ SqliteDatabaseMock &databaseMock;
};
template<int ResultCount, int BindParameterCount = 0>
diff --git a/tests/unit/unittest/sqlitetransaction-test.cpp b/tests/unit/unittest/sqlitetransaction-test.cpp
index fa502218c77..ca52dd0ae11 100644
--- a/tests/unit/unittest/sqlitetransaction-test.cpp
+++ b/tests/unit/unittest/sqlitetransaction-test.cpp
@@ -22,7 +22,12 @@ using Sqlite::ImmediateTransaction;
class SqliteTransaction : public testing::Test
{
protected:
+ SqliteTransaction() { ON_CALL(callableWithReturnMock, Call()).WillByDefault(Return(212)); }
+
+protected:
NiceMock<MockSqliteTransactionBackend> mockTransactionBackend;
+ NiceMock<MockFunction<void()>> callableMock;
+ NiceMock<MockFunction<int()>> callableWithReturnMock;
};
TEST_F(SqliteTransaction, DeferredTransactionCommit)
@@ -38,19 +43,6 @@ TEST_F(SqliteTransaction, DeferredTransactionCommit)
transaction.commit();
}
-TEST_F(SqliteTransaction, DeferredTransactionCommitCallsInterface)
-{
- InSequence s;
-
- EXPECT_CALL(mockTransactionBackend, lock());
- EXPECT_CALL(mockTransactionBackend, deferredBegin());
- EXPECT_CALL(mockTransactionBackend, commit());
- EXPECT_CALL(mockTransactionBackend, unlock());
-
- DeferredTransaction transaction{mockTransactionBackend};
- transaction.commit();
-}
-
TEST_F(SqliteTransaction, DeferredTransactionRollBack)
{
InSequence s;
@@ -337,4 +329,110 @@ TEST_F(SqliteTransaction, ImmediateSessionTransactionBeginThrowsAndNotRollback)
ASSERT_ANY_THROW(ImmediateSessionTransaction{mockTransactionBackend});
}
+TEST_F(SqliteTransaction, WithDeferredTransactionNoReturnCommit)
+{
+ InSequence s;
+
+ EXPECT_CALL(mockTransactionBackend, lock());
+ EXPECT_CALL(mockTransactionBackend, deferredBegin());
+ EXPECT_CALL(callableMock, Call());
+ EXPECT_CALL(mockTransactionBackend, commit());
+ EXPECT_CALL(mockTransactionBackend, unlock());
+
+ Sqlite::withDeferredTransaction(mockTransactionBackend, callableMock.AsStdFunction());
+}
+
+TEST_F(SqliteTransaction, WithDeferredTransactionWithReturnCommit)
+{
+ InSequence s;
+
+ EXPECT_CALL(mockTransactionBackend, lock());
+ EXPECT_CALL(mockTransactionBackend, deferredBegin());
+ EXPECT_CALL(callableWithReturnMock, Call());
+ EXPECT_CALL(mockTransactionBackend, commit());
+ EXPECT_CALL(mockTransactionBackend, unlock());
+
+ Sqlite::withDeferredTransaction(mockTransactionBackend, callableWithReturnMock.AsStdFunction());
+}
+
+TEST_F(SqliteTransaction, WithDeferredTransactionReturnsValue)
+{
+ auto callable = callableWithReturnMock.AsStdFunction();
+
+ auto value = Sqlite::withDeferredTransaction(mockTransactionBackend,
+ callableWithReturnMock.AsStdFunction());
+
+ ASSERT_THAT(value, Eq(212));
+}
+
+TEST_F(SqliteTransaction, WithDeferredTransactionRollsbackForException)
+{
+ InSequence s;
+ ON_CALL(callableMock, Call()).WillByDefault(Throw(std::exception{}));
+
+ EXPECT_CALL(mockTransactionBackend, lock());
+ EXPECT_CALL(mockTransactionBackend, deferredBegin());
+ EXPECT_CALL(callableMock, Call());
+ EXPECT_CALL(mockTransactionBackend, rollback());
+ EXPECT_CALL(mockTransactionBackend, unlock());
+
+ try {
+ Sqlite::withDeferredTransaction(mockTransactionBackend, callableMock.AsStdFunction());
+ } catch (...) {
+ }
+}
+
+TEST_F(SqliteTransaction, WithImmediateTransactionNoReturnCommit)
+{
+ InSequence s;
+
+ EXPECT_CALL(mockTransactionBackend, lock());
+ EXPECT_CALL(mockTransactionBackend, immediateBegin());
+ EXPECT_CALL(callableMock, Call());
+ EXPECT_CALL(mockTransactionBackend, commit());
+ EXPECT_CALL(mockTransactionBackend, unlock());
+
+ Sqlite::withImmediateTransaction(mockTransactionBackend, callableMock.AsStdFunction());
+}
+
+TEST_F(SqliteTransaction, WithImmediateTransactionWithReturnCommit)
+{
+ InSequence s;
+
+ EXPECT_CALL(mockTransactionBackend, lock());
+ EXPECT_CALL(mockTransactionBackend, immediateBegin());
+ EXPECT_CALL(callableWithReturnMock, Call());
+ EXPECT_CALL(mockTransactionBackend, commit());
+ EXPECT_CALL(mockTransactionBackend, unlock());
+
+ Sqlite::withImmediateTransaction(mockTransactionBackend, callableWithReturnMock.AsStdFunction());
+}
+
+TEST_F(SqliteTransaction, WithImmediateTransactionReturnsValue)
+{
+ auto callable = callableWithReturnMock.AsStdFunction();
+
+ auto value = Sqlite::withImmediateTransaction(mockTransactionBackend,
+ callableWithReturnMock.AsStdFunction());
+
+ ASSERT_THAT(value, Eq(212));
+}
+
+TEST_F(SqliteTransaction, WithImmediateTransactionRollsbackForException)
+{
+ InSequence s;
+ ON_CALL(callableMock, Call()).WillByDefault(Throw(std::exception{}));
+
+ EXPECT_CALL(mockTransactionBackend, lock());
+ EXPECT_CALL(mockTransactionBackend, immediateBegin());
+ EXPECT_CALL(callableMock, Call());
+ EXPECT_CALL(mockTransactionBackend, rollback());
+ EXPECT_CALL(mockTransactionBackend, unlock());
+
+ try {
+ Sqlite::withImmediateTransaction(mockTransactionBackend, callableMock.AsStdFunction());
+ } catch (...) {
+ }
+}
+
} // namespace
diff --git a/tests/unit/unittest/storagecache-test.cpp b/tests/unit/unittest/storagecache-test.cpp
index 3e3763dae4b..543b4dc5787 100644
--- a/tests/unit/unittest/storagecache-test.cpp
+++ b/tests/unit/unittest/storagecache-test.cpp
@@ -90,11 +90,11 @@ protected:
Utils::PathString filePath5{"/file/pathFife"};
Utils::PathStringVector filePaths{filePath1, filePath2, filePath3, filePath4, filePath5};
Utils::PathStringVector reverseFilePaths{filePath1, filePath2, filePath3, filePath4, filePath5};
- SourceContextId id1{SourceContextId::create(0)};
- SourceContextId id2{SourceContextId::create(1)};
- SourceContextId id3{SourceContextId::create(2)};
- SourceContextId id4{SourceContextId::create(3)};
- SourceContextId id5{SourceContextId::create(4)};
+ SourceContextId id1{SourceContextId::create(1)};
+ SourceContextId id2{SourceContextId::create(2)};
+ SourceContextId id3{SourceContextId::create(3)};
+ SourceContextId id4{SourceContextId::create(4)};
+ SourceContextId id5{SourceContextId::create(5)};
SourceContextId id41{SourceContextId::create(41)};
SourceContextId id42{SourceContextId::create(42)};
SourceContextId id43{SourceContextId::create(43)};
diff --git a/tests/unit/unittest/unittest-matchers.h b/tests/unit/unittest/unittest-matchers.h
index 12f47074835..0f59a5e79a8 100644
--- a/tests/unit/unittest/unittest-matchers.h
+++ b/tests/unit/unittest/unittest-matchers.h
@@ -7,7 +7,7 @@
#include <utils/smallstringio.h>
-namespace UnitTests {
+namespace Internal {
template <typename StringType>
class EndsWithMatcher
@@ -46,10 +46,68 @@ private:
const StringType m_suffix;
};
-inline
-testing::PolymorphicMatcher<EndsWithMatcher<Utils::SmallString> >
-EndsWith(const Utils::SmallString &suffix)
+class QStringEndsWithMatcher
{
- return testing::MakePolymorphicMatcher(EndsWithMatcher<Utils::SmallString>(suffix));
+public:
+ explicit QStringEndsWithMatcher(const QString &suffix)
+ : m_suffix(suffix)
+ {}
+
+ template<typename MatcheeStringType>
+ bool MatchAndExplain(const MatcheeStringType &s, testing::MatchResultListener * /* listener */) const
+ {
+ return s.endsWith(m_suffix);
+ }
+
+ void DescribeTo(::std::ostream *os) const
+ {
+ *os << "ends with " << testing::PrintToString(m_suffix);
+ }
+
+ void DescribeNegationTo(::std::ostream *os) const
+ {
+ *os << "doesn't end with " << testing::PrintToString(m_suffix);
+ }
+
+private:
+ const QString m_suffix;
+};
+
+class IsEmptyMatcher : public testing::internal::IsEmptyMatcher
+{
+public:
+ using Base = testing::internal::IsEmptyMatcher;
+
+ using Base::MatchAndExplain;
+
+ bool MatchAndExplain(const QString &s, testing::MatchResultListener *listener) const
+ {
+ if (s.isEmpty()) {
+ return true;
+ }
+
+ *listener << "whose size is " << s.size();
+ return false;
+ }
+
+ void DescribeTo(std::ostream *os) const { *os << "is empty"; }
+
+ void DescribeNegationTo(std::ostream *os) const { *os << "isn't empty"; }
+};
+
+} // namespace Internal
+
+inline auto EndsWith(const Utils::SmallString &suffix)
+{
+ return Internal::EndsWithMatcher(suffix);
}
+
+inline auto EndsWith(const QStringView &suffix)
+{
+ return ::testing::PolymorphicMatcher(Internal::QStringEndsWithMatcher(suffix.toString()));
+}
+
+inline auto IsEmpty()
+{
+ return ::testing::PolymorphicMatcher(Internal::IsEmptyMatcher());
}
diff --git a/tests/unit/unittest/unittest-utility-functions.h b/tests/unit/unittest/unittest-utility-functions.h
index a4866cfa889..090360e8a70 100644
--- a/tests/unit/unittest/unittest-utility-functions.h
+++ b/tests/unit/unittest/unittest-utility-functions.h
@@ -15,10 +15,9 @@ bool operator==(const QString &first, const char *second)
namespace UnitTest {
-inline
-Utils::PathString temporaryDirPath()
+inline ::Utils::PathString temporaryDirPath()
{
- return Utils::PathString::fromQString(Utils::TemporaryDirectory::masterDirectoryPath());
+ return ::Utils::PathString::fromQString(Utils::TemporaryDirectory::masterDirectoryPath());
}
} // namespace UnitTest